Skip to content
Merged
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
78 changes: 58 additions & 20 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,23 +33,26 @@ discovery document with full JSON Schema input declarations for every tool.
https://thhanke.github.io/ontosphere/.well-known/mcp.json
```

**Key tools** (30+ total — see manifest for full schemas):
**Key tools** (31 total — see manifest for full schemas):

| Tool | Purpose |
|------|---------|
| `loadOntology` | Load TBox (schema/classes) — no canvas nodes |
| `loadRdf` | Load ABox (individuals) — subjects appear as canvas nodes |
| `loadOntology` | Load TBox (schema/classes) — no canvas nodes. Also search/list registered ontologies |
| `suggestOntologiesForTask` | Suggest ontology packs for a task description |
| `loadRdf` | Load ABox (individuals) or inline Turtle — subjects appear as canvas nodes |
| `addNode` / `removeNode` | Add/remove individual canvas nodes |
| `addLink` / `removeLink` | Add/remove object-property triples |
| `queryGraph` | SPARQL SELECT / CONSTRUCT against the RDF store |
| `queryGraph` | SPARQL SELECT / CONSTRUCT / UPDATE against the RDF store |
| `runReasoning` | OWL-RL inference — inferred triples in `urn:vg:inferred` |
| `runLayout` | Layout: `dagre-lr`, `dagre-tb`, `elk-layered`, `elk-force`, … |
| `focusNode` / `fitCanvas` | Pan/zoom viewport |
| `exportImage` | Export full canvas as SVG or PNG |
| `exportImage` | Export canvas as SVG or PNG (focused or full) |
| `exportGraph` | Export RDF store as Turtle / JSON-LD / RDF-XML |
| `getNodes` / `getLinks` | Inspect current canvas state |
| `getNeighbors` / `findPath` | Graph traversal queries |
| `loadShacl` / `validateGraph` | SHACL constraint validation |
| `setNamespace` / `listNamespaces` | Register/list IRI prefixes (upsert) |
| `expandNode` | Expand one node or all nodes (omit iri) to show properties |
| `getCapabilities` / `help` | Discover tools at runtime |

## How to call tools
Expand Down Expand Up @@ -85,10 +88,25 @@ Full setup: [docs/relay-bridge.md](docs/relay-bridge.md)
**Relay starter prompt:**

```
You are connected to Ontosphere via a relay. A script in this tab intercepts
your JSON-RPC 2.0 tool calls (wrapped in backtick fences), runs them in
Ontosphere, and injects results back as a user message. All computation runs
client-side. Full tool list: https://thhanke.github.io/ontosphere/.well-known/mcp.json
You control Ontosphere (browser-based RDF knowledge graph editor) via this relay.

CALL FORMAT — single backtick per JSON-RPC object, up to 5 per message:
`{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"TOOLNAME","arguments":ARGS}}`

Example — layout + fit + export in one message:
`{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"runLayout","arguments":{"algorithm":"dagre-lr"}}}`
`{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"fitCanvas","arguments":{}}}`
`{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"exportImage","arguments":{"format":"svg"}}}`

RULES:
1. Single ` NOT triple ```. Increment id per call.
2. Batch up to 5 non-dependent calls. Discovery calls (getNodes, queryGraph) send alone, wait for result.
3. addLink: both nodes must exist first.
4. 5+ individuals: loadRdf(turtle=...) not N×addNode.
5. Tool failed? Call help({tool:"toolname"}) for the exact schema.

Full docs: call help({}).
Full tool list: https://thhanke.github.io/ontosphere/.well-known/mcp.json
```

## Graph architecture (read before building)
Expand All @@ -107,31 +125,51 @@ amber dashed edges. Clear them with `clearInferred`.
## Recommended workflow

```
loadOntology(url) # TBox — classes/properties searchable, no canvas nodes
suggestOntologiesForTask({ task: '…' }) # discover which ontology packs to use
getNodes({ labelContains: '' }) # IRI lookup from TBox
loadOntology({ url: '<prefix>' }) × N # TBox — classes/properties, no canvas nodes
addNode × N (typeIri from lookup) # ABox individuals on canvas
setNamespace({ prefix: '…', namespace: '…' }) × N # register short IRIs (upsert)
addLink × N # subjectIri / predicateIri / objectIri
setViewMode({ mode: 'abox' })
loadRdf({ turtle: '…' }) # preferred for 5+ individuals (one round-trip)
OR
addNode × N → addLink × N # for small numbers of nodes
runLayout({ algorithm: 'dagre-lr' })
runReasoning({}) # OWL-RL → urn:vg:inferred
runReasoning({}) # OWL-RL → urn:vg:inferred
focusNode({ iri }) → browser_take_screenshot # show the user
fitCanvas() + exportImage({ format: 'svg' }) [safe to batch with runLayout]
exportGraph({ format: 'turtle' }) # persist
exportGraph({ format: 'turtle' }) # persist
```

**Never call `expandAll` after loading a large ontology** — it floods the
canvas with thousands of TBox nodes.
**Batching guidance:**
- Safe to batch: `loadOntology` × N, `addNode` + `addLink` pairs, `runLayout` + `fitCanvas` + `exportImage`
- Send alone: `getNodes`, `queryGraph`, `getNodeDetails` — you need the result before deciding what to call next

## Anti-patterns — never do these

| Wrong | Right | Why |
|-------|-------|-----|
| `addLink({s, p, o})` | `addLink({subjectIri, predicateIri, objectIri})` | Wrong param names |
| `addNode({iri, type})` | `addNode({iri, typeIri})` | `type` is not the canonical name (though accepted as alias) |
| `loadOntology({url:"calendar"})` to search | `loadOntology({query:"calendar"})` | `url` loads by prefix; `query` searches |
| `expandNode` in a loop over every IRI | `expandNode({})` (no iri) | Expands all in one call |
| SPARQL without PREFIX | Add `PREFIX owl: <…>` etc. | No implicit prefixes |
| `addLink` before `addNode` for both endpoints | `addNode` both endpoints first | Canvas links only connect existing nodes |
| N×`addNode` for 5+ individuals | `loadRdf({turtle:"…"})` | One round-trip is far faster |

## Common parameter mistakes

| Tool | Wrong | Right |
|------|-------|-------|
| `addLink` | `{ s, p, o }` | `{ subjectIri, predicateIri, objectIri }` |
| `loadOntology` (search) | `{ url: "calendar" }` | `{ query: "calendar" }` |
| `expandNode` (expand all) | loop over each IRI | call with no `iri`: `expandNode({})` |
| `expandNode` (collapse all) | loop with `expand:false` | `expandNode({expand:false})` — compact canvas before export |
| SPARQL | bare `owl:Class` | declare `PREFIX owl: <…>` in every query |

## Example sessions (rendered demos)
Expand Down Expand Up @@ -180,7 +218,7 @@ SELECT DISTINCT ?prop ?label WHERE {

## SPARQL caveats

- Every query needs explicit `PREFIX` declarations — there are no implicit prefixes.
- All prefixes in your namespace registry (from `loadOntology` or `setNamespace`) are **auto-injected** into every SPARQL query — you do not need to declare them. Only declare prefixes that are not registered.
- `FILTER(STRSTARTS(STR(?s), '...'))` in SELECT/CONSTRUCT does **not** reliably filter triples (N3.js limitation) — returns full store. Use named graphs or check `urn:vg:inferred` instead.
- Inferred triples are stored in the `urn:vg:inferred` named graph.

Expand Down Expand Up @@ -208,7 +246,7 @@ Key IRIs for modeling material compositions with PMDCO v3:
| iron atom | `http://purl.obolibrary.org/obo/CHEBI_18248` |
| carbon atom | `http://purl.obolibrary.org/obo/CHEBI_27594` |

After `loadOntology`, `pmd:` registers as `https://w3id.org/pmd/co/`. Check with `listNamespaces({})`. All SPARQL queries still need full `PREFIX` declarations.
After `loadOntology`, `pmd:` registers as `https://w3id.org/pmd/co/`. Check with `listNamespaces({})`. The `pmd:` prefix is then auto-injected into all SPARQL queries — no explicit PREFIX declaration needed.

## More reading

Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Key capabilities
- **Namespace management**: edit namespace URIs directly in the legend panel (rename propagates across all stored triples). Colour-coded namespace badges on nodes and edges.
- Export the current graph as Turtle, RDF/XML, or JSON-LD.
- **Workflow catalog**: drag reusable workflow template cards from the sidebar onto the canvas to instantiate connected subgraphs.
- **MCP support**: exposes a Model Context Protocol server (via the browser's `navigator.modelContext` API) for AI-agent integration. Tools: `loadRdf`, `loadOntology`, `suggestOntologiesForTask`, `queryGraph`, `exportGraph`, `exportImage`, `addNode`, `removeNode`, `expandNode`, `expandAll`, `getNodes`, `addLink`, `removeLink`, `getLinks`, `runLayout`, `clusterNodes`, `layoutNodes`, `focusNode`, `fitCanvas`, `runReasoning`, `clearInferred`, `getNeighbors`, `findPath`, `getNodeDetails`, `updateNode`, `getGraphState`, `addNamespace`, `updateNamespace`, `removeNamespace`, `listNamespaces`, `loadShacl`, `validateGraph`, `getCapabilities`, `help`. MCP manifest at `/.well-known/mcp.json`.
- **MCP support**: exposes a Model Context Protocol server (via the browser's `navigator.modelContext` API) for AI-agent integration. Tools: `loadRdf`, `loadOntology`, `suggestOntologiesForTask`, `queryGraph`, `exportGraph`, `exportImage`, `addNode`, `removeNode`, `expandNode`, `getNodes`, `addLink`, `removeLink`, `getLinks`, `runLayout`, `clusterNodes`, `layoutNodes`, `focusNode`, `fitCanvas`, `runReasoning`, `clearInferred`, `getNeighbors`, `findPath`, `getNodeDetails`, `updateNode`, `getGraphState`, `setNamespace`, `removeNamespace`, `listNamespaces`, `loadShacl`, `validateGraph`, `getCapabilities`, `help`. MCP manifest at `/.well-known/mcp.json`.

Quick start (development)
-------------------------
Expand Down Expand Up @@ -367,7 +367,7 @@ Ontosphere exposes a full [Model Context Protocol](https://modelcontextprotocol.
The app has two coupled layers:

- **N3 RDF store** — source of truth. `addNode` / `addLink` write triples here.
- **Reactodia canvas** — visual mirror. Nodes are *not* created automatically from triples; you must call `addNode` to place a subject on canvas. After adding triples, canvas links refresh automatically. Nodes start collapsed — call `expandNode` or `expandAll` to reveal annotation property cards.
- **Reactodia canvas** — visual mirror. Nodes are *not* created automatically from triples; you must call `addNode` to place a subject on canvas. After adding triples, canvas links refresh automatically. Nodes start collapsed — call `expandNode` (with an IRI to expand one node, or no args to expand all) to reveal annotation property cards.

OWL-RL reasoning writes inferred triples back to the store and refreshes the canvas.

Expand Down Expand Up @@ -411,7 +411,7 @@ loadOntology (TBox)
→ addNode ×N (ABox individuals, rdf:type set)
→ addLink ×N (object-property triples, edges appear on canvas)
→ runLayout (dagre-lr recommended)
expandAll (reveal annotation property cards)
expandNode (reveal annotation property cards — omit iri to expand all)
→ runReasoning (infer subClass / domain / range entailments)
→ fitCanvas + exportImage (SVG snapshot, token-efficient)
→ exportGraph(turtle) (final deliverable)
Expand Down
12 changes: 6 additions & 6 deletions docs/mcp-demo/foaf-social-network.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ Canvas: 5 nodes, 6 links
`{"jsonrpc":"2.0","id":19,"method":"tools/call","params":{"name":"addLink","arguments":{"subjectIri":"http://example.org/ex#collaboratesWith","predicateIri":"http://www.w3.org/2000/01/rdf-schema#domain","objectIri":"http://example.org/ex#Employee"}}}`
`{"jsonrpc":"2.0","id":20,"method":"tools/call","params":{"name":"addLink","arguments":{"subjectIri":"http://example.org/ex#collaboratesWith","predicateIri":"http://www.w3.org/2000/01/rdf-schema#range","objectIri":"http://example.org/ex#Employee"}}}`
`{"jsonrpc":"2.0","id":21,"method":"tools/call","params":{"name":"runLayout","arguments":{"algorithm":"elk-layered","spacing":200}}}`
`{"jsonrpc":"2.0","id":22,"method":"tools/call","params":{"name":"expandAll","arguments":{}}}`
`{"jsonrpc":"2.0","id":22,"method":"tools/call","params":{"name":"expandNode","arguments":{}}}`
`{"jsonrpc":"2.0","id":23,"method":"tools/call","params":{"name":"runLayout","arguments":{"algorithm":"elk-layered","spacing":200}}}`

```tool-result
Expand All @@ -105,7 +105,7 @@ Canvas: 5 nodes, 6 links
✓ addLink: s=collaboratesWith p=domain o=Employee
✓ addLink: s=collaboratesWith p=range o=Employee
✓ runLayout: elk-layered
expandAll
expandNode
✓ runLayout: elk-layered

Canvas: 12 nodes, 16 links
Expand Down Expand Up @@ -182,7 +182,7 @@ Canvas: 8 nodes, 0 links
`{"jsonrpc":"2.0","id":47,"method":"tools/call","params":{"name":"addLink","arguments":{"subjectIri":"http://example.org/eve","predicateIri":"http://xmlns.com/foaf/0.1/member","objectIri":"http://example.org/research"}}}`
`{"jsonrpc":"2.0","id":48,"method":"tools/call","params":{"name":"addLink","arguments":{"subjectIri":"http://example.org/frank","predicateIri":"http://xmlns.com/foaf/0.1/member","objectIri":"http://example.org/research"}}}`
`{"jsonrpc":"2.0","id":49,"method":"tools/call","params":{"name":"runLayout","arguments":{"algorithm":"dagre-lr","spacing":200}}}`
`{"jsonrpc":"2.0","id":50,"method":"tools/call","params":{"name":"expandAll","arguments":{}}}`
`{"jsonrpc":"2.0","id":50,"method":"tools/call","params":{"name":"expandNode","arguments":{}}}`
`{"jsonrpc":"2.0","id":51,"method":"tools/call","params":{"name":"runLayout","arguments":{"algorithm":"dagre-lr","spacing":200}}}`

```tool-result
Expand All @@ -204,7 +204,7 @@ Canvas: 8 nodes, 0 links
✓ addLink: s=eve p=member o=research
✓ addLink: s=frank p=member o=research
✓ runLayout: dagre-lr
expandAll
expandNode
✓ runLayout: dagre-lr

Canvas: 8 nodes, 16 links
Expand All @@ -229,13 +229,13 @@ Canvas: 8 nodes, 16 links
<summary>3 tool calls ✓</summary>

`{"jsonrpc":"2.0","id":52,"method":"tools/call","params":{"name":"runReasoning","arguments":{}}}`
`{"jsonrpc":"2.0","id":53,"method":"tools/call","params":{"name":"expandAll","arguments":{}}}`
`{"jsonrpc":"2.0","id":53,"method":"tools/call","params":{"name":"expandNode","arguments":{}}}`
`{"jsonrpc":"2.0","id":54,"method":"tools/call","params":{"name":"runLayout","arguments":{"algorithm":"dagre-lr","spacing":200}}}`

```tool-result
[Ontosphere — 3 tools ✓]
✓ runReasoning: 10720 triples inferred
expandAll
expandNode
✓ runLayout: dagre-lr

Canvas: 8 nodes, 17 links
Expand Down
28 changes: 14 additions & 14 deletions docs/mcp-demo/foaf-social-network/01-tbox.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 14 additions & 14 deletions docs/mcp-demo/foaf-social-network/02-before-reasoning.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 14 additions & 14 deletions docs/mcp-demo/foaf-social-network/03-after-reasoning.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 14 additions & 14 deletions docs/mcp-demo/foaf-social-network/04-frank-focus.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading