Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
"dapp",
"ad4m-hooks/react",
"ad4m-hooks/vue",
"ad4m-hooks/helpers"
"ad4m-hooks/helpers",
"soa",
"soa/language"
],
"private": true,
"scripts": {
Expand Down
136 changes: 136 additions & 0 deletions soa/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
# State of Affairs (SoA) — AD4M Ontology

A universal ontology for representing knowledge, beliefs, intentions, and plans as structured trees within AD4M perspectives.

## Overview

A **State of Affairs** (SoA) is a proposition about how things are, could be, or should be. It is the fundamental unit of knowledge representation in this ontology.

Every node in a SoA tree is a `StateOfAffair` with a **modality** that describes its epistemic status:

| Modality | Meaning | Example |
|---|---|---|
| `belief` | Something we hold as true | "Holochain handles P2P sync" |
| `observation` | Something directly verified | "CI is green on commit abc123" |
| `intention` | Something we want to make true | "AD4M has MCP support" |
| `vision` | A high-level desired future | "Distributed collective intelligence" |
| `plan` | Steps to reach an intended SoA | "Merge branches → release → prototype" |
| `skill` | A capability an agent has | "Can query perspectives via MCP" |

## Relationships

Relationships between SoA nodes are expressed as **standard AD4M links** using the `soa` language for predicates. No separate model needed — link expressions natively carry author and timestamp.

| Predicate | Meaning |
|---|---|
| `soa://rel_supports` | Evidence or argument for |
| `soa://rel_contradicts` | Evidence or argument against |
| `soa://rel_similar` | Related but not identical |
| `soa://rel_same` | Equivalent propositions |
| `soa://rel_requires` | Dependency (target requires source) |
| `soa://rel_enables` | Capability (source enables target) |
| `soa://rel_parent` | Tree structure (source is parent of target) |
| `soa://rel_refines` | More specific version of |
| `soa://rel_blocks` | Prevents or blocks |

The `soa` language is a static language — these expressions resolve to documentation describing the relationship semantics.

## Authorship & Provenance

SoA nodes do **not** store author or timestamp fields. Every link that constitutes a SoA shape is an AD4M `LinkExpression` which natively includes:
- `author` — the DID of the agent who created the link
- `timestamp` — when the link was created

A single SoA can have multiple authors — when different agents independently create the same state of affairs, the link graph naturally represents this.

## Structure

```text
soa/
├── README.md # This file
├── src/ # TypeScript model classes
│ ├── index.ts # Exports + relationship predicate constants
│ └── StateOfAffair.ts
├── language/ # Static SoA language (ReadOnlyLanguage)
│ └── src/
│ ├── index.ts # Language entry point
│ ├── adapter.ts # ExpressionAdapter — resolves soa:// to docs
│ └── expressions.ts # Registry of all soa:// expressions + docs
└── package.json
```

SHACL shapes are auto-generated from the `Ad4mModel` decorators — no separate schema files needed. The TypeScript classes ARE the source of truth.

## Usage

### TypeScript (UI / Flux)
```typescript
import { StateOfAffair, SoA } from '@coasys/soa';

// Create a belief
const belief = new StateOfAffair();
belief.title = "SHACL is the source of truth for subject classes";
belief.modality = "belief";
belief.confidence = 0.95;

// Create an intention
const goal = new StateOfAffair();
goal.title = "Migrate Data's memory to AD4M perspectives";
goal.modality = "intention";

// Link them with a relationship (just an AD4M link!)
perspective.addLink({
source: belief.baseExpression,
predicate: SoA.REL_SUPPORTS,
target: goal.baseExpression,
});

// Tree structure
perspective.addLink({
source: parentSoA.baseExpression,
predicate: SoA.REL_PARENT,
target: childSoA.baseExpression,
});
```

### MCP / Programmatic Access
SoA instances can be created via MCP tools using the auto-generated SHACL shape. Relationships are just `add_link` calls with `soa://rel_*` predicates.

## Design Principles

1. **No flags** — the graph shape + `soa://` namespace is sufficient for type identification
2. **No separate relationship model** — relationships are native AD4M links with typed predicates
3. **No author/timestamp fields** — link expressions handle provenance natively
4. **Works for humans AND agents** — same schema for personal memory, shared task boards, Eve's worldview
5. **Trees AND graphs** — `rel_parent` gives hierarchy; other predicates give cross-links
6. **Fractal** — same pattern at individual, group, and network levels
7. **Evolvable** — new modalities and relationship predicates can be added without breaking existing trees

## The `soa` Language

The `soa` language is a **static ReadOnlyLanguage** — it defines fixed expressions that resolve to structured documentation. When any agent (human or AI) resolves a `soa://` URL, they get back a rich object explaining what it means and how to use it:

```typescript
// Resolving soa://rel_supports returns:
{
"@type": "SoADocumentation",
"address": "soa://rel_supports",
"name": "Supports",
"kind": "relationship",
"description": "Source provides evidence, argument, or backing for target...",
"example": "link(evidence_soa, \"soa://rel_supports\", claim_soa)",
"agentNotes": "Directional: A supports B means A is evidence FOR B..."
}
```

This makes the ontology **self-documenting and discoverable**. AI agents encountering `soa://` predicates for the first time can resolve them to understand the ontology without external documentation.

### Pattern for other languages

The soa language serves as a template for how AD4M languages can act as **self-documenting semantic vocabularies**. Any domain can create a similar static language to define its own predicates — just map addresses to documentation objects.

Implementation: `soa/language/src/`

## Connection to Eve

In the Eve vision, every agent (human or AI) builds their own SoA tree — their worldview. Shared neighbourhoods allow SoA subtrees to be synchronized, enabling distributed consensus through Eve-to-Eve communication. The same ontology powers personal memory, collaborative task tracking, and collective intelligence.
18 changes: 18 additions & 0 deletions soa/language/esbuild.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import * as esbuild from "esbuild";
import { fileURLToPath } from "url";
import { dirname, join } from "path";

const __dirname = dirname(fileURLToPath(import.meta.url));

const result = await esbuild.build({
entryPoints: [join(__dirname, "src", "index.ts")],
bundle: true,
outfile: join(__dirname, "dist", "index.js"),
format: "esm",
platform: "node",
target: "es2020",
sourcemap: true,
external: ["@perspect3vism/ad4m"],
});

console.log("Build completed:", result);
23 changes: 23 additions & 0 deletions soa/language/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "@coasys/soa-language",
"version": "0.1.0",
"description": "Static self-documenting vocabulary for State of Affairs ontology",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
},
"scripts": {
"build": "node esbuild.ts"
},
"dependencies": {
"@perspect3vism/ad4m": "^0.5.0"
},
"devDependencies": {
"esbuild": "^0.19.0"
}
}
65 changes: 65 additions & 0 deletions soa/language/src/adapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import type {
Address,
Expression,
ExpressionAdapter,
ReadOnlyLanguage,
LanguageContext,
AgentService,
} from "https://esm.sh/v135/@perspect3vism/ad4m@0.5.0";
import { SOA_EXPRESSIONS } from "./expressions.ts";

/**
* SoA Expression Adapter
*
* Resolves soa:// addresses to structured documentation.
* This is a ReadOnlyLanguage — expressions are predefined,
* not created by users.
*
* When an AI agent or application resolves "soa://rel_supports",
* they get back a rich documentation object explaining what
* "supports" means, how to use it, and example link triples.
*/
export default class SoAExpressionAdapter implements ExpressionAdapter {
#agent: AgentService;
putAdapter: ReadOnlyLanguage;

constructor(context: LanguageContext) {
this.#agent = context.agent;
this.putAdapter = new SoAReadOnly();
}

async get(address: Address): Promise<Expression | null> {
// Strip the soa:// prefix if present
const key = address.replace(/^soa:\/\//, '');

const doc = SOA_EXPRESSIONS[key];
if (!doc) {
// Return null for unknown addresses per ExpressionAdapter contract
return null;
}

// Return the documentation as a signed expression
const expression = await this.#agent.createSignedExpression({
'@type': 'SoADocumentation',
address: `soa://${key}`,
...doc,
});
return expression;
}
}

class SoAReadOnly implements ReadOnlyLanguage {
async addressOf(content: object): Promise<Address> {
// For a read-only language, the address is the key itself
const c = content as { key?: string; address?: string };
const addr = c.key ?? c.address;
if (!addr) {
throw new Error('SoA content must have a "key" or "address" property');
}
// Canonicalize to soa:// form
if (addr.startsWith('soa://')) {
return addr;
}
return `soa://${addr}`;
}
}
Loading