open-standards/jouleclaw/jouleclaw-rs/crates/jouleclaw-hydra/conformance/graph-mcp-api.jsonld
Transaction Science 50b234f2d7 jouleclaw-hydra: Hydra ApiDocumentation emitter (wave-22 #2)
The structural fix for the generation-2 "72% of context window on
tool schemas" pathology Michael Kerduchi flagged. A JouleClaw tool
surface (MCP server, the out-of-process policy daemon, an HTTP
endpoint) now emits a Hydra Core Vocabulary
hydra:ApiDocumentation document a generic third-generation agent
client reads ONCE — and is then free to call every operation
without ever loading a tool-by-tool schema into its context window.

Composes directly on wave-22 #1: every operation's input / output
class IRI references the JouleClaw vocabulary at /vocab/v1#, so
the Hydra doc and the receipt stream share one term space. A
client that knows our vocabulary AND Hydra Core Vocabulary needs
zero JouleClaw-specific code beyond standard W3C semantics.

Surface:

  - Hydra type vocabulary: ApiDocumentation, Class, Operation,
    Status, SupportedProperty.
  - ToolDescription — neutral input type any tool source can
    populate (MCP, policy IPC, HTTP services).
  - ApiDocumentationBuilder — fluent, deterministic emitter.
  - to_pretty() helper for the JSON-LD wire form.
  - mcp-adapter feature: From<&McpToolSchema> for ToolDescription
    so an existing jouleclaw-graph-mcp server emits a Hydra doc
    in one chained call.

Defaults a Hydra client expects:

  - method = GET for read-only operations (mutating: false)
  - method = POST for mutating operations (mutating: true)
  - expects = owl:Nothing for parameterless operations
  - returns = jc:ToolResponse from the JouleClaw vocabulary
  - statusCodes = 200, 400, 500
  - jc_tool_id and jc_mutating extension fields cross-link the
    operation back to the receipt-stream vocabulary

Constraints upheld:

  - #![forbid(unsafe_code)], no FFI, no model invocation.
  - Deterministic: identical input → identical JSON-LD output.
  - Picojoule cost.

17 tests + a worked example (gen_graph_mcp_api_doc) that emits
conformance/graph-mcp-api.jsonld from the live jouleclaw-graph-mcp
tool set. The committed sample doc lets a third party verify the
emitter byte-equal against the canonical output without running
Cargo.

SPEC.md §14 documents the contract a conforming JouleClaw tool
surface meets; prior §§14-16 (Does-not-say / Adjacent /
References) renumber to §§15-17.

Workspace: 105 crates (+1), 2,591 lib tests (+17), 0 failures.

Next wave-22 steps remain: #3 SHACL shapes for actions + tool
inputs (local validation, no model-side guessing), and #4 the
generic Rust + WASM Hydra client crate (agent-side counterpart;
demoable on /playground).
2026-06-02 11:17:22 -04:00

295 lines
8.4 KiB
Text

{
"@context": {
"ApiDocumentation": "hydra:ApiDocumentation",
"Class": "hydra:Class",
"Operation": "hydra:Operation",
"Status": "hydra:Status",
"SupportedProperty": "hydra:SupportedProperty",
"code": "hydra:code",
"description": "hydra:description",
"entrypoint": {
"@id": "hydra:entrypoint",
"@type": "@id"
},
"expects": {
"@id": "hydra:expects",
"@type": "@id"
},
"hydra": "http://www.w3.org/ns/hydra/core#",
"jc": "https://jouleclaw.transaction.science/vocab/v1#",
"jc_mutating": {
"@id": "jc:mutating",
"@type": "xsd:boolean"
},
"jc_tool_id": {
"@id": "jc:toolId",
"@type": "xsd:string"
},
"method": "hydra:method",
"property": {
"@id": "hydra:property",
"@type": "@id"
},
"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
"readable": "hydra:readable",
"required": "hydra:required",
"returns": {
"@id": "hydra:returns",
"@type": "@id"
},
"statusCodes": {
"@id": "hydra:statusCodes"
},
"supportedClass": {
"@id": "hydra:supportedClass",
"@type": "@id"
},
"supportedOperation": {
"@id": "hydra:supportedOperation",
"@type": "@id"
},
"supportedProperty": {
"@id": "hydra:supportedProperty",
"@type": "@id"
},
"title": "hydra:title",
"writable": "hydra:writable",
"xsd": "http://www.w3.org/2001/XMLSchema#"
},
"@id": "https://jouleclaw.transaction.science/examples/graph-mcp",
"@type": [
"ApiDocumentation"
],
"title": "JouleClaw graph-MCP surface",
"description": "Reference MCP server exposing the JouleClaw run-graph verbs. Conforms to Hydra Core Vocabulary; field IRIs reference the JouleClaw vocabulary v1.",
"entrypoint": "https://jouleclaw.transaction.science/examples/graph-mcp/",
"supportedClass": [
{
"@id": "https://jouleclaw.transaction.science/examples/graph-mcp#Server",
"@type": [
"Class"
],
"title": "Graph-MCP server",
"description": "Holds the run graph + journal; surfaces six verbs (read-only + mutating + verification).",
"supportedOperation": [
{
"@id": "_:op_jouleclaw_list_nodes",
"@type": [
"Operation"
],
"title": "jouleclaw:list_nodes",
"description": "List nodes in the run graph; optional filter by completion.",
"method": "GET",
"expects": "http://www.w3.org/2002/07/owl#Nothing",
"returns": "https://jouleclaw.transaction.science/vocab/v1#ToolResponse",
"statusCodes": [
{
"@type": [
"Status"
],
"code": 200,
"description": "OK"
},
{
"@type": [
"Status"
],
"code": 400,
"description": "Bad Request"
},
{
"@type": [
"Status"
],
"code": 500,
"description": "Internal Server Error"
}
],
"jc_tool_id": "jouleclaw:list_nodes",
"jc_mutating": false
},
{
"@id": "_:op_jouleclaw_get_node",
"@type": [
"Operation"
],
"title": "jouleclaw:get_node",
"description": "Fetch one node's kind + completion status by id.",
"method": "GET",
"expects": "http://www.w3.org/2002/07/owl#Nothing",
"returns": "https://jouleclaw.transaction.science/vocab/v1#ToolResponse",
"statusCodes": [
{
"@type": [
"Status"
],
"code": 200,
"description": "OK"
},
{
"@type": [
"Status"
],
"code": 400,
"description": "Bad Request"
},
{
"@type": [
"Status"
],
"code": 500,
"description": "Internal Server Error"
}
],
"jc_tool_id": "jouleclaw:get_node",
"jc_mutating": false
},
{
"@id": "_:op_jouleclaw_get_journal",
"@type": [
"Operation"
],
"title": "jouleclaw:get_journal",
"description": "Fetch the run journal — entry count + last hash.",
"method": "GET",
"expects": "http://www.w3.org/2002/07/owl#Nothing",
"returns": "https://jouleclaw.transaction.science/vocab/v1#ToolResponse",
"statusCodes": [
{
"@type": [
"Status"
],
"code": 200,
"description": "OK"
},
{
"@type": [
"Status"
],
"code": 400,
"description": "Bad Request"
},
{
"@type": [
"Status"
],
"code": 500,
"description": "Internal Server Error"
}
],
"jc_tool_id": "jouleclaw:get_journal",
"jc_mutating": false
},
{
"@id": "_:op_jouleclaw_append_child",
"@type": [
"Operation"
],
"title": "jouleclaw:append_child",
"description": "Record a checkpoint for a successor node; appends a NodeRecorded event.",
"method": "POST",
"expects": "http://www.w3.org/2002/07/owl#Nothing",
"returns": "https://jouleclaw.transaction.science/vocab/v1#ToolResponse",
"statusCodes": [
{
"@type": [
"Status"
],
"code": 200,
"description": "OK"
},
{
"@type": [
"Status"
],
"code": 400,
"description": "Bad Request"
},
{
"@type": [
"Status"
],
"code": 500,
"description": "Internal Server Error"
}
],
"jc_tool_id": "jouleclaw:append_child",
"jc_mutating": true
},
{
"@id": "_:op_jouleclaw_mark_replicated",
"@type": [
"Operation"
],
"title": "jouleclaw:mark_replicated",
"description": "Record that a node was reproduced by a separate run; appends a journal event.",
"method": "POST",
"expects": "http://www.w3.org/2002/07/owl#Nothing",
"returns": "https://jouleclaw.transaction.science/vocab/v1#ToolResponse",
"statusCodes": [
{
"@type": [
"Status"
],
"code": 200,
"description": "OK"
},
{
"@type": [
"Status"
],
"code": 400,
"description": "Bad Request"
},
{
"@type": [
"Status"
],
"code": 500,
"description": "Internal Server Error"
}
],
"jc_tool_id": "jouleclaw:mark_replicated",
"jc_mutating": true
},
{
"@id": "_:op_jouleclaw_verify_artifact",
"@type": [
"Operation"
],
"title": "jouleclaw:verify_artifact",
"description": "Dispatch a node's verification artifact; returns its content-address.",
"method": "GET",
"expects": "http://www.w3.org/2002/07/owl#Nothing",
"returns": "https://jouleclaw.transaction.science/vocab/v1#ToolResponse",
"statusCodes": [
{
"@type": [
"Status"
],
"code": 200,
"description": "OK"
},
{
"@type": [
"Status"
],
"code": 400,
"description": "Bad Request"
},
{
"@type": [
"Status"
],
"code": 500,
"description": "Internal Server Error"
}
],
"jc_tool_id": "jouleclaw:verify_artifact",
"jc_mutating": false
}
]
}
]
}