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).
295 lines
8.4 KiB
Text
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
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|