{
  "name": "purple8-hyper-graph",
  "version": "0.72.0",
  "tool_count": 176,
  "namespace_count": 19,
  "profiles": [
    {
      "id": "starter",
      "name": "Starter (Core 28)",
      "description": "Focused 28-tool starter belt for Claude Desktop, Cursor, Copilot, and rapid app building: Schema modeling, Unified LPG + RDF graph CRUD/queries, hybrid search, structured table & Markdown commit, and Journey workflows + HITL.",
      "tool_count": 28
    },
    {
      "id": "builder",
      "name": "App Builder (117 tools)",
      "description": "Full application-building toolbelt for Cursor, Claude Code, and Copilot: all Starter tools plus schema modeling, structured tables, memory, model routing, webhooks, scheduled triggers, feedback loops, and tool federation.",
      "tool_count": 117
    },
    {
      "id": "ops",
      "name": "Operations & Governance (37 tools)",
      "description": "Operational monitoring, SLA alerts, HITL approvals, Sentinel findings, guardrails, and audit/retention compliance.",
      "tool_count": 37
    },
    {
      "id": "full",
      "name": "Full Platform (All 176 tools)",
      "description": "Complete 176-tool manifest across all 19 namespaces, including AEC/BIM engineering, SOC, SuperGraph, quantum optimization, evolutionary search, Sentinel, and system administration.",
      "tool_count": 176
    }
  ],
  "tools": [
    {
      "name": "rag.query",
      "namespace": "rag",
      "description": "Flat Vector RAG \u2014 retrieves the most relevant graph nodes by pure vector similarity (HNSW + RRF fusion + keyword fallback), then calls the configured LLM to generate a grounded answer.  Fastest of the three RAG modes (p50 ~45 ms, MRR 0.64); best for single-hop factual questions.  Use rag.graph_query or rag.hybrid_query for multi-hop or relationship-heavy questions.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "question"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "question": {
            "type": "string",
            "description": "The question to answer."
          }
        },
        "required": [
          "question"
        ]
      }
    },
    {
      "name": "rag.graph_query",
      "namespace": "rag",
      "description": "Graph-native RAG \u2014 seeds the search with vector-nearest nodes, then expands a multi-hop BFS subgraph and builds a relationship-rich context before LLM generation.  MRR 0.76, multi-hop accuracy 0.79.  ~4x slower than flat RAG (p50 ~180 ms).  Use rag.hybrid_query for best accuracy.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "question"
      ],
      "optional_params": [
        "max_hops",
        "seed_k",
        "max_nodes",
        "write_inferred",
        "label_filter",
        "max_tokens",
        "temperature"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "question": {
            "type": "string",
            "description": "The question to answer."
          },
          "max_hops": {
            "type": "integer",
            "description": "BFS expansion depth (1-5).  Default 2.",
            "default": 2
          },
          "seed_k": {
            "type": "integer",
            "description": "Number of vector-nearest seed nodes (1-20).  Default 5.",
            "default": 5
          },
          "max_nodes": {
            "type": "integer",
            "description": "Maximum subgraph nodes in context (5-200).  Default 50.",
            "default": 50
          },
          "write_inferred": {
            "type": "boolean",
            "description": "Persist LLM-inferred edges back to the graph.  Default false.",
            "default": false
          },
          "label_filter": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Restrict retrieval to nodes with these labels."
          },
          "max_tokens": {
            "type": "integer",
            "description": "LLM output token budget.  Default 1024.",
            "default": 1024
          },
          "temperature": {
            "type": "number",
            "description": "LLM sampling temperature.  Default 0.0.",
            "default": 0.0
          }
        },
        "required": [
          "question"
        ]
      }
    },
    {
      "name": "rag.hybrid_query",
      "namespace": "rag",
      "description": "Hybrid Graph-Vector RAG \u2014 fuses vector similarity AND graph structural signals at every stage: dual-seed fusion (Weighted RRF over vector rank + degree centrality), vector-guided BFS, and semantic path scoring.  Highest accuracy: MRR 0.85, multi-hop 0.91.  ~5x slower (p50 ~240 ms).  Recommended as the default RAG tool for agents that need high quality.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "question"
      ],
      "optional_params": [
        "mode",
        "fusion_alpha",
        "max_hops",
        "seed_k",
        "max_nodes",
        "write_inferred",
        "vector_expansion",
        "semantic_path_scoring",
        "label_filter",
        "max_tokens",
        "temperature",
        "collection_profile"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "question": {
            "type": "string",
            "description": "The question to answer."
          },
          "mode": {
            "type": "string",
            "enum": [
              "balanced",
              "graph_first",
              "vector_first"
            ],
            "description": "Fusion mode.  'balanced' for most questions; 'graph_first' for dense-relationship queries; 'vector_first' for semantic similarity.",
            "default": "balanced"
          },
          "fusion_alpha": {
            "type": "number",
            "description": "Explicit graph weight (0.0=pure vector, 1.0=pure graph).  Overrides mode."
          },
          "max_hops": {
            "type": "integer",
            "description": "BFS expansion depth (1-5).  Default 2.",
            "default": 2
          },
          "seed_k": {
            "type": "integer",
            "description": "Seed nodes per signal (1-20).  Default 5.",
            "default": 5
          },
          "max_nodes": {
            "type": "integer",
            "description": "Maximum subgraph nodes in context (5-200).  Default 50.",
            "default": 50
          },
          "write_inferred": {
            "type": "boolean",
            "description": "Persist LLM-inferred edges back to the graph.  Default false.",
            "default": false
          },
          "vector_expansion": {
            "type": "boolean",
            "description": "Filter BFS neighbours by cosine similarity.  Default true.",
            "default": true
          },
          "semantic_path_scoring": {
            "type": "boolean",
            "description": "Rank paths by keyword overlap + edge-type bonuses.  Default true.",
            "default": true
          },
          "label_filter": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Restrict retrieval to nodes with these labels."
          },
          "max_tokens": {
            "type": "integer",
            "description": "LLM output token budget.  Default 1024.",
            "default": 1024
          },
          "temperature": {
            "type": "number",
            "description": "LLM sampling temperature.  Default 0.0.",
            "default": 0.0
          },
          "collection_profile": {
            "type": "string",
            "description": "Name of a saved CollectionProfile (from rag.tune_collection save_as).  Fills in mode/fusion_alpha/max_hops/seed_k as defaults \u2014 explicit params always win."
          }
        },
        "required": [
          "question"
        ]
      }
    },
    {
      "name": "rag.profile_collection",
      "namespace": "rag",
      "description": "Analyse the graph topology and return recommended RAG retrieval settings.  Profiles node count, edge density, degree distribution, edge-type distribution, and embedding coverage, then derives concrete values for fusion_alpha, max_hops, seed_k, vector_weight, k, and mode.  Call this before tuning rag.hybrid_query on a new corpus or collection.  Returns topology_class (sparse/moderate/dense), a 'recommended' param block ready to pass to rag.hybrid_query, and a 'rationale' explaining each choice.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [
        "label_filter"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "label_filter": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Restrict analysis to nodes with these labels.  Omit for whole graph."
          }
        },
        "required": []
      }
    },
    {
      "name": "rag.tune_collection",
      "namespace": "rag",
      "description": "Grid-search hybrid RAG retrieval parameters against a small eval set and return the best-performing configuration.  Runs profile_collection() to derive a topology-aware baseline, then evaluates combinations of fusion_alpha / expand_hops / seed_k using token-F1 between retrieved context and expected answers (retrieval-only mode \u2014 no LLM generation).  Returns best_params, best_score, baseline_score, improvement_pct, and full grid_results.  Requires an LLM provider configured (embedding step only).  Call after rag.profile_collection when you want autonomous param optimisation or when retrieval quality has degraded due to corpus drift.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "eval_set"
      ],
      "optional_params": [
        "label_filter",
        "max_iterations",
        "save_as"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "eval_set": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "question": {
                  "type": "string"
                },
                "expected_answer": {
                  "type": "string"
                }
              },
              "required": [
                "question",
                "expected_answer"
              ]
            },
            "description": "5\u201320 question/expected_answer pairs to evaluate retrieval quality.",
            "minItems": 1,
            "maxItems": 50
          },
          "label_filter": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Restrict tuning to nodes with these labels.  Omit for whole graph."
          },
          "max_iterations": {
            "type": "integer",
            "description": "Maximum number of param combinations to evaluate.  Default 12.",
            "default": 12
          },
          "save_as": {
            "type": "string",
            "description": "If provided, persist best_params as a named CollectionProfile after tuning.  Pass this name to rag.hybrid_query collection_profile to auto-apply the optimal params on every subsequent query \u2014 zero manual config required."
          }
        },
        "required": [
          "eval_set"
        ]
      }
    },
    {
      "name": "graph.query",
      "namespace": "graph",
      "description": "Execute a Cypher query against the Purple8 knowledge graph and return matching records.  Use for nodes, edges, paths, or aggregated data.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "cypher"
      ],
      "optional_params": [
        "parameters"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "cypher": {
            "type": "string",
            "description": "The Cypher query to execute."
          },
          "parameters": {
            "type": "object",
            "description": "Optional named parameters.",
            "default": {}
          }
        },
        "required": [
          "cypher"
        ]
      }
    },
    {
      "name": "graph.vector_search",
      "namespace": "graph",
      "description": "Find the k nearest nodes to a natural-language query using the HNSW vector index.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "query_text"
      ],
      "optional_params": [
        "label",
        "k"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "query_text": {
            "type": "string",
            "description": "The search query in natural language."
          },
          "label": {
            "type": "string",
            "description": "Restrict search to nodes with this label."
          },
          "k": {
            "type": "integer",
            "description": "Number of results to return.  Default 5.",
            "default": 5
          }
        },
        "required": [
          "query_text"
        ]
      }
    },
    {
      "name": "graph.hybrid_search",
      "namespace": "graph",
      "description": "Combine vector similarity with graph traversal for highest-recall retrieval.  Best when graph structure matters.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "query_text"
      ],
      "optional_params": [
        "label",
        "k"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "query_text": {
            "type": "string",
            "description": "The search query in natural language."
          },
          "label": {
            "type": "string",
            "description": "Restrict search to nodes with this label."
          },
          "k": {
            "type": "integer",
            "description": "Number of results to return.  Default 10.",
            "default": 10
          }
        },
        "required": [
          "query_text"
        ]
      }
    },
    {
      "name": "graph.traverse",
      "namespace": "graph",
      "description": "Walk the graph from a starting node following edges up to a given depth.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "node_id"
      ],
      "optional_params": [
        "depth",
        "edge_type",
        "direction"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "node_id": {
            "type": "string",
            "description": "ID of the starting node."
          },
          "depth": {
            "type": "integer",
            "description": "Maximum traversal depth.  Default 2.",
            "default": 2
          },
          "edge_type": {
            "type": "string",
            "description": "Restrict to edges of this type.  Omit for all types."
          },
          "direction": {
            "type": "string",
            "enum": [
              "outgoing",
              "incoming",
              "both"
            ],
            "description": "Edge direction.  Default 'both'.",
            "default": "both"
          }
        },
        "required": [
          "node_id"
        ]
      }
    },
    {
      "name": "graph.add_node",
      "namespace": "graph",
      "description": "Insert a new node into the graph (accepts `type`, `label`, or `node_type`).  Requires editor role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "node_id"
      ],
      "optional_params": [
        "type",
        "label",
        "node_type",
        "labels",
        "properties"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "node_id": {
            "type": "string",
            "description": "Unique identifier for the node."
          },
          "type": {
            "type": "string",
            "description": "Node label / type (e.g. 'Person', 'Company')."
          },
          "label": {
            "type": "string",
            "description": "Alias for `type` (e.g. 'Document', 'Borrower')."
          },
          "node_type": {
            "type": "string",
            "description": "Alias for `type`."
          },
          "labels": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Optional additional labels."
          },
          "properties": {
            "type": "object",
            "description": "Key-value properties.",
            "default": {}
          }
        },
        "required": [
          "node_id"
        ]
      }
    },
    {
      "name": "graph.add_edge",
      "namespace": "graph",
      "description": "Create a directed edge (relationship) between two existing nodes.  This is the primary agentic handoff mechanism \u2014 agents write their output as edges (e.g. DERIVED_FROM, RISK_ASSESSMENT, EXTRACTED_FROM) so downstream agents can discover work by querying graph state rather than passing messages.  edge_id is auto-generated (UUID4) when omitted.  Requires editor role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "source_id",
        "target_id",
        "edge_type"
      ],
      "optional_params": [
        "edge_id",
        "properties",
        "weight"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "source_id": {
            "type": "string",
            "description": "ID of the source (tail) node."
          },
          "target_id": {
            "type": "string",
            "description": "ID of the target (head) node."
          },
          "edge_type": {
            "type": "string",
            "description": "Relationship type label (e.g. 'DERIVED_FROM', 'RISK_ASSESSMENT', 'EXTRACTED_FROM')."
          },
          "edge_id": {
            "type": "string",
            "description": "Unique identifier for the edge.  Auto-generated UUID4 when omitted."
          },
          "properties": {
            "type": "object",
            "description": "Key-value edge properties (e.g. {\"confidence\": 0.9, \"assessor\": \"legal\"}).",
            "default": {}
          },
          "weight": {
            "type": "number",
            "description": "Edge weight for traversal algorithms.  Default 1.0.",
            "default": 1.0
          }
        },
        "required": [
          "source_id",
          "target_id",
          "edge_type"
        ]
      }
    },
    {
      "name": "graph.update_node",
      "namespace": "graph",
      "description": "Update properties or labels on an existing node.  Properties are merged with existing values (patch semantics \u2014 only the keys you supply are changed).  Labels replace the full label set when provided.  Use this to advance agent relay state, e.g. setting {\"status\": \"enriched\", \"handoff_to\": null} to hand off work to the next agent in a relay pipeline.  Requires editor role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "node_id"
      ],
      "optional_params": [
        "properties",
        "labels"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "node_id": {
            "type": "string",
            "description": "ID of the node to update."
          },
          "properties": {
            "type": "object",
            "description": "Properties to merge into the node (patch semantics)."
          },
          "labels": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Replacement label set (replaces all existing labels when provided)."
          }
        },
        "required": [
          "node_id"
        ]
      }
    },
    {
      "name": "graph.get_node",
      "namespace": "graph",
      "description": "Retrieve a node and all its stored properties by ID.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "node_id"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "node_id": {
            "type": "string",
            "description": "ID of the node to retrieve."
          }
        },
        "required": [
          "node_id"
        ]
      }
    },
    {
      "name": "graph.pagerank",
      "namespace": "graph",
      "description": "Run PageRank on the graph and return the top-ranked (most influential) nodes.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [
        "label",
        "top_k"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "label": {
            "type": "string",
            "description": "Restrict PageRank to nodes with this label."
          },
          "top_k": {
            "type": "integer",
            "description": "Number of top nodes to return.  Default 20.",
            "default": 20
          }
        },
        "required": []
      }
    },
    {
      "name": "graph.communities",
      "namespace": "graph",
      "description": "Detect communities (Louvain) in the graph.  Useful for discovering entity clusters.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [
        "label"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "label": {
            "type": "string",
            "description": "Restrict community detection to nodes with this label."
          }
        },
        "required": []
      }
    },
    {
      "name": "data.ingest_text",
      "namespace": "data",
      "description": "Extract entities and relationships from raw text and write them into the graph. Calls preview first, then commits the complete extraction on success. auto_commit=false returns a review-only preview. Pending jobs return job_id for resumption. Original bytes are not stored automatically; supply file_ref or use data.commit with file_bytes_b64 if needed. After an interrupted write, ask the user to confirm a retry; use data.commit with the retained reviewed payload instead of re-extracting. Requires editor role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "text",
        "source_name"
      ],
      "optional_params": [
        "profile_hint",
        "auto_commit",
        "job_id",
        "wait_seconds",
        "file_ref"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string",
            "description": "The raw text to extract knowledge from."
          },
          "source_name": {
            "type": "string",
            "description": "Label for the source document (provenance)."
          },
          "profile_hint": {
            "type": "string",
            "enum": [
              "",
              "aec",
              "contract",
              "financial",
              "scientific",
              "general"
            ],
            "description": "Extraction profile; omit for auto-detection."
          },
          "auto_commit": {
            "type": "boolean",
            "default": true,
            "description": "false returns the complete preview without graph writes. Review then use data.commit."
          },
          "job_id": {
            "type": "string",
            "description": "Resume an earlier extraction instead of submitting again; repeat the original input arguments."
          },
          "wait_seconds": {
            "type": "integer",
            "minimum": 0,
            "maximum": 600,
            "default": 30,
            "description": "Maximum wait for an admitted extraction. Pending jobs are NOT committed; resume with job_id."
          },
          "file_ref": {
            "type": "string",
            "description": "Optional existing Graph file_id in this tenant, used as the original/document anchor at commit."
          }
        },
        "required": [
          "text",
          "source_name"
        ]
      }
    },
    {
      "name": "data.commit",
      "namespace": "data",
      "description": "Commit a reviewed extraction or your own extractor's output without invoking DocIntel. Uses the complete POST /ingest/commit contract: entities, relationships, Markdown, spans, tables/pages, context, file_ref or inline file_bytes_b64 and ingestion options. Existing entities are linked, not edited, unless update_entities=true. For extractor-generated IDs use identity_policy='review_conflicts': name matches alone are not identity proof. On entity_identity_conflict nothing was written; correct/exclude the incoming entity and update relationship endpoints, or explicitly confirm identity_resolution='link_existing', then retry. link_existing never edits existing facts. After interruption or a lost response, ask the user to confirm retrying the retained reviewed payload. Reuse entity IDs, assertion keys and file_ref; do not automatically re-extract. Retain metadata.sha256 (original bytes) and optional metadata.file_version. On source_version_conflict nothing was written: obtain and review current-source extraction and ask for confirmation, rather than replaying or relabeling the old review. SIMILAR_TO edges (enabled by default) are similarity, not factual assertions. Inspect embedding, document_chunks, structured_content and original_file outcomes; a successful write alone does not guarantee retrieval readiness. Requires editor role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "entities",
        "relationships"
      ],
      "optional_params": [
        "identity_policy",
        "source_name",
        "metadata",
        "doc_type",
        "chunking_hint",
        "section_boundaries",
        "suggested_embedding_model",
        "markdown",
        "markdown_sections",
        "tables",
        "pages",
        "links",
        "file_ref",
        "file_bytes_b64",
        "context",
        "session_id",
        "build_similarity_edges",
        "similarity_threshold",
        "similarity_k",
        "file_id",
        "raw_text",
        "upsert",
        "update_entities"
      ],
      "inputSchema": {
        "$defs": {
          "CommitPage": {
            "description": "A page/slide/sheet as a ``[char_start, char_end)`` range of ``markdown``.",
            "properties": {
              "page_number": {
                "title": "Page Number",
                "type": "integer"
              },
              "char_start": {
                "minimum": 0,
                "title": "Char Start",
                "type": "integer"
              },
              "char_end": {
                "minimum": 0,
                "title": "Char End",
                "type": "integer"
              }
            },
            "required": [
              "page_number",
              "char_start",
              "char_end"
            ],
            "title": "CommitPage",
            "type": "object"
          },
          "CommitTable": {
            "description": "A document table as rows (``[row][col]`` strings, header rows first).",
            "properties": {
              "page_number": {
                "anyOf": [
                  {
                    "type": "integer"
                  },
                  {
                    "type": "null"
                  }
                ],
                "default": null,
                "title": "Page Number"
              },
              "table_index": {
                "default": 0,
                "minimum": 0,
                "title": "Table Index",
                "type": "integer"
              },
              "caption": {
                "anyOf": [
                  {
                    "maxLength": 2000,
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "default": null,
                "title": "Caption"
              },
              "header_rows": {
                "default": 1,
                "maximum": 10,
                "minimum": 0,
                "title": "Header Rows",
                "type": "integer"
              },
              "rows": {
                "items": {
                  "items": {
                    "type": "string"
                  },
                  "type": "array"
                },
                "maxItems": 200000,
                "title": "Rows",
                "type": "array"
              },
              "indexed_columns": {
                "additionalProperties": {
                  "enum": [
                    "profile",
                    "agent",
                    "user"
                  ],
                  "type": "string"
                },
                "maxProperties": 64,
                "title": "Indexed Columns",
                "type": "object"
              }
            },
            "title": "CommitTable",
            "type": "object"
          },
          "DocumentContextClaims": {
            "description": "Content-derived 4D context-signal fields \u2014 the *claim* half of the barcode.\n\nThese are extracted from the document by Purple8-DocIntel and are, by nature,\n*claims* (the document asserting facts about itself), as opposed to the\nengine-stamped high-trust fields (``_ctx.ingested_at`` / ``_ctx.tenant`` /\n``_ctx.ingest_actor``) which the graph engine writes itself.\n\nEvery field is **optional** \u2014 the barcode degrades gracefully when a signal is\nabsent (missing \u2192 neutral at scoring time, never a penalty).  The ingest\nrouter translates these to reserved ``_ctx.*`` node properties and runs\n:func:`~purple8_graph.core.context_signal.validate_context_types` before\nwriting, so a malformed claim is rejected at the boundary rather than silently\ncorrupting the retrieval scorer downstream.  See ``purple8-company: ip/trade-secrets/context-signal-4d.md``.",
            "properties": {
              "content_time": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "default": null,
                "description": "Primary date the content is ABOUT (ISO-8601), e.g. '2025-09-30'.",
                "title": "Content Time"
              },
              "content_time_span": {
                "anyOf": [
                  {
                    "items": {
                      "type": "string"
                    },
                    "type": "array"
                  },
                  {
                    "type": "null"
                  }
                ],
                "default": null,
                "description": "Optional [start, end] ISO-8601 range the content covers.",
                "title": "Content Time Span"
              },
              "geo": {
                "anyOf": [
                  {
                    "items": {
                      "type": "string"
                    },
                    "type": "array"
                  },
                  {
                    "type": "null"
                  }
                ],
                "default": null,
                "description": "Locations mentioned in the content, e.g. ['London, UK'].",
                "title": "Geo"
              },
              "author": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "default": null,
                "description": "Authoring entity named in the content, e.g. 'entity:JPMorgan'.",
                "title": "Author"
              },
              "doc_type_confidence": {
                "anyOf": [
                  {
                    "type": "number"
                  },
                  {
                    "type": "null"
                  }
                ],
                "default": null,
                "description": "Confidence in the doc_type classification, in [0.0, 1.0].",
                "title": "Doc Type Confidence"
              }
            },
            "title": "DocumentContextClaims",
            "type": "object"
          },
          "ExtractedEntityPayload": {
            "properties": {
              "id": {
                "title": "Id",
                "type": "string"
              },
              "type": {
                "title": "Type",
                "type": "string"
              },
              "name": {
                "title": "Name",
                "type": "string"
              },
              "properties": {
                "type": "object",
                "additionalProperties": true,
                "title": "Properties"
              },
              "include": {
                "default": true,
                "title": "Include",
                "type": "boolean"
              },
              "identity": {
                "additionalProperties": {
                  "type": "string"
                },
                "description": "Explicit stable identifiers, keyed by namespace (for example company_registration). Not inferred from arbitrary properties.",
                "title": "Identity",
                "type": "object"
              },
              "identity_resolution": {
                "default": "check",
                "description": "link_existing explicitly confirms this ID is the intended existing entity despite conflicting identity evidence; it does not request an edit.",
                "enum": [
                  "check",
                  "link_existing"
                ],
                "title": "Identity Resolution",
                "type": "string"
              },
              "spans": {
                "items": {
                  "maxItems": 2,
                  "minItems": 2,
                  "prefixItems": [
                    {
                      "type": "integer"
                    },
                    {
                      "type": "integer"
                    }
                  ],
                  "type": "array"
                },
                "maxItems": 200,
                "title": "Spans",
                "type": "array"
              },
              "relation_keys": {
                "description": "Shared semantic keys that trigger CO_RELEVANT edges across batches. Any two nodes with the same key will be connected automatically.",
                "items": {
                  "type": "string"
                },
                "title": "Relation Keys",
                "type": "array"
              }
            },
            "required": [
              "id",
              "type",
              "name"
            ],
            "title": "ExtractedEntityPayload",
            "type": "object"
          },
          "ExtractedRelationshipPayload": {
            "properties": {
              "source": {
                "title": "Source",
                "type": "string"
              },
              "target": {
                "title": "Target",
                "type": "string"
              },
              "type": {
                "title": "Type",
                "type": "string"
              },
              "properties": {
                "type": "object",
                "additionalProperties": true,
                "title": "Properties"
              },
              "include": {
                "default": true,
                "title": "Include",
                "type": "boolean"
              },
              "edge_dedup_key": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "default": null,
                "title": "Edge Dedup Key"
              }
            },
            "required": [
              "source",
              "target",
              "type"
            ],
            "title": "ExtractedRelationshipPayload",
            "type": "object"
          },
          "LinkRule": {
            "description": "One declared Row \u2192 entity link (spec \u00a76).",
            "properties": {
              "column": {
                "maxLength": 256,
                "minLength": 1,
                "title": "Column",
                "type": "string"
              },
              "target_label": {
                "title": "Target Label",
                "type": "string"
              },
              "match": {
                "default": "name_normalised",
                "enum": [
                  "exact_id",
                  "name_exact",
                  "name_normalised"
                ],
                "title": "Match",
                "type": "string"
              },
              "edge": {
                "default": "REFERS_TO",
                "title": "Edge",
                "type": "string"
              },
              "on_missing": {
                "default": "skip",
                "enum": [
                  "skip",
                  "create"
                ],
                "title": "On Missing",
                "type": "string"
              },
              "columns_include": {
                "items": {
                  "type": "string"
                },
                "maxItems": 32,
                "title": "Columns Include",
                "type": "array"
              }
            },
            "required": [
              "column",
              "target_label"
            ],
            "title": "LinkRule",
            "type": "object"
          }
        },
        "properties": {
          "entities": {
            "items": {
              "$ref": "#/$defs/ExtractedEntityPayload"
            },
            "title": "Entities",
            "type": "array"
          },
          "relationships": {
            "items": {
              "$ref": "#/$defs/ExtractedRelationshipPayload"
            },
            "title": "Relationships",
            "type": "array"
          },
          "identity_policy": {
            "default": "trust_ids",
            "description": "review_conflicts rejects conflicting names/types/identifiers and cross-document name-only matches before writes. Supply matching stable identifiers, same-source provenance, or explicit link_existing confirmation. trust_ids preserves caller-managed ID semantics. Explicit identifier evidence is checked in either mode.",
            "enum": [
              "trust_ids",
              "review_conflicts"
            ],
            "title": "Identity Policy",
            "type": "string"
          },
          "source_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": "unknown",
            "title": "Source Name"
          },
          "metadata": {
            "additionalProperties": true,
            "description": "Preserve extraction metadata. For a stored File, sha256 binds the review to original bytes (not Markdown); optional file_version pins its positive integer version. A changed/missing bound source returns source_version_conflict (409) before writes. Unpinned legacy payloads cannot prove that their review matches the current source.",
            "title": "Metadata",
            "type": "object"
          },
          "doc_type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": "",
            "title": "Doc Type"
          },
          "chunking_hint": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": "",
            "title": "Chunking Hint"
          },
          "section_boundaries": {
            "items": {
              "type": "integer"
            },
            "title": "Section Boundaries",
            "type": "array"
          },
          "suggested_embedding_model": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": "",
            "title": "Suggested Embedding Model"
          },
          "markdown": {
            "default": "",
            "maxLength": 20000000,
            "title": "Markdown",
            "type": "string"
          },
          "markdown_sections": {
            "items": {
              "type": "integer"
            },
            "title": "Markdown Sections",
            "type": "array"
          },
          "tables": {
            "items": {
              "$ref": "#/$defs/CommitTable"
            },
            "maxItems": 2000,
            "title": "Tables",
            "type": "array"
          },
          "pages": {
            "items": {
              "$ref": "#/$defs/CommitPage"
            },
            "maxItems": 20000,
            "title": "Pages",
            "type": "array"
          },
          "links": {
            "items": {
              "$ref": "#/$defs/LinkRule"
            },
            "maxItems": 64,
            "title": "Links",
            "type": "array"
          },
          "file_ref": {
            "anyOf": [
              {
                "maxLength": 128,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "title": "File Ref"
          },
          "file_bytes_b64": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "title": "File Bytes B64"
          },
          "context": {
            "anyOf": [
              {
                "$ref": "#/$defs/DocumentContextClaims"
              },
              {
                "type": "null"
              }
            ],
            "default": null
          },
          "session_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "title": "Session Id"
          },
          "build_similarity_edges": {
            "default": true,
            "description": "Build SIMILAR_TO edges to cross-batch neighbours via vector search. On by default \u2014 turns every commit into a native hybrid ingest.",
            "title": "Build Similarity Edges",
            "type": "boolean"
          },
          "similarity_threshold": {
            "default": 0.7,
            "description": "Minimum cosine similarity for SIMILAR_TO edge creation.",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "Similarity Threshold",
            "type": "number"
          },
          "similarity_k": {
            "default": 5,
            "description": "Number of nearest neighbours to consider per node.",
            "maximum": 20,
            "minimum": 1,
            "title": "Similarity K",
            "type": "integer"
          },
          "file_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Content-hash / File node ID for a file-backed commit. When provided, the orchestrator creates File \u2192 HAS_CHUNK \u2192 Chunk edges.",
            "title": "File Id"
          },
          "raw_text": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": "",
            "description": "Full document text used to extract per-chunk text from section_boundaries. Pass the complete text for accurate MENTIONED_IN linkage.",
            "title": "Raw Text"
          },
          "upsert": {
            "default": true,
            "description": "Idempotent re-projection mode (default on): never create __vN twins, and derive deterministic edge ids so re-commits converge instead of duplicating.",
            "title": "Upsert",
            "type": "boolean"
          },
          "update_entities": {
            "default": false,
            "description": "Merge this document's values into entities that already exist. Off by default: existing entities are linked, not modified. Requires edit access to every existing entity (403 otherwise; nothing is written).",
            "title": "Update Entities",
            "type": "boolean"
          }
        },
        "required": [
          "entities",
          "relationships"
        ],
        "title": "CommitRequest",
        "type": "object"
      }
    },
    {
      "name": "data.replace_file",
      "namespace": "data",
      "description": "Upload a new version of an existing file blob. The current blob is automatically archived as v1 (idempotent). The new bytes become v{N+1}. The File node is updated (version, content_hash, blob_ref, size_bytes, updated_at). Immutable FileVersion records distinguish the previous version from the exact base. Set base_version to revise from an older version without losing intervening history. Set intent=linked_file and base_version to create an independent linked File instead. Superseded source versions and extraction records remain available as archived history. DocIntel processing is queued by default. Set re_extract=false for reviewed/custom ingestion. Use data.list_file_versions to inspect the version history afterwards. Requires editor role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "file_id",
        "url"
      ],
      "optional_params": [
        "re_extract",
        "intent",
        "base_version"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "file_id": {
            "type": "string",
            "description": "ID of the File node to replace (the content hash from the original upload)."
          },
          "url": {
            "type": "string",
            "description": "Publicly accessible URL of the new file to fetch and store as the replacement."
          },
          "re_extract": {
            "type": "boolean",
            "description": "Process automatically; false defers to reviewed/custom ingestion.",
            "default": true
          },
          "intent": {
            "type": "string",
            "enum": [
              "new_version",
              "linked_file"
            ],
            "default": "new_version"
          },
          "base_version": {
            "type": "integer",
            "minimum": 1,
            "description": "Exact source version; required for linked_file, otherwise defaults to current."
          }
        },
        "required": [
          "file_id",
          "url"
        ],
        "allOf": [
          {
            "if": {
              "properties": {
                "intent": {
                  "const": "linked_file"
                }
              },
              "required": [
                "intent"
              ]
            },
            "then": {
              "required": [
                "base_version"
              ]
            }
          }
        ]
      }
    },
    {
      "name": "data.patch_file_properties",
      "namespace": "data",
      "description": "Update mutable metadata on a File node without touching the stored blob or bumping the version number. Fields: filename, description, tags (list of strings), classification. Only the supplied fields are updated; omitted fields are left unchanged. Requires editor role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "file_id"
      ],
      "optional_params": [
        "filename",
        "description",
        "tags",
        "classification"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "file_id": {
            "type": "string",
            "description": "ID of the File node to update."
          },
          "filename": {
            "type": "string",
            "description": "New display filename."
          },
          "description": {
            "type": "string",
            "description": "Human-readable description of the file's content or purpose."
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Replacement tag list."
          },
          "classification": {
            "type": "string",
            "description": "Sensitivity classification, e.g. 'confidential', 'internal', 'public'."
          }
        },
        "required": [
          "file_id"
        ]
      }
    },
    {
      "name": "data.list_file_versions",
      "namespace": "data",
      "description": "Return the full version history of a stored file, oldest to newest. Each entry contains: version (int), filename, size_bytes, content_hash, file_ref, modified_at. If no version history exists yet (file pre-dates versioning), a synthesised v1 record is returned from the current node properties. Use GET /files/{id}/versions/{ver} to download a specific version. Requires viewer role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "file_id"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "file_id": {
            "type": "string",
            "description": "ID of the File node to inspect."
          }
        },
        "required": [
          "file_id"
        ]
      }
    },
    {
      "name": "data.get_table",
      "namespace": "data",
      "description": "Summary of a stored document table (from a commit with tables): columns, inferred column_types, indexed_columns (with which layer set them), typed_status / typed_skipped, and link_rules. Table ids appear in the commit response and on Table nodes. Requires viewer role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "table_id"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "table_id": {
            "type": "string"
          }
        },
        "required": [
          "table_id"
        ]
      }
    },
    {
      "name": "data.link_table_rows",
      "namespace": "data",
      "description": "Declare rule-based links from a table's rows to entities and apply them. Each rule: column (header name), target_label (e.g. Organization), match (exact_id | name_exact | name_normalised, default name_normalised), edge (UPPER_SNAKE, default REFERS_TO), on_missing (skip | create, default skip), columns_include (optional header columns the table must have). Rules are stored on the table and re-applied on re-extraction. Re-running is idempotent; edges that no longer match are removed. replace=true drops rules not listed (and their edges). All-or-nothing. Requires editor role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "table_id",
        "rules"
      ],
      "optional_params": [
        "replace"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "table_id": {
            "type": "string"
          },
          "rules": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "column": {
                  "type": "string"
                },
                "target_label": {
                  "type": "string"
                },
                "match": {
                  "type": "string",
                  "enum": [
                    "exact_id",
                    "name_exact",
                    "name_normalised"
                  ]
                },
                "edge": {
                  "type": "string"
                },
                "on_missing": {
                  "type": "string",
                  "enum": [
                    "skip",
                    "create"
                  ]
                },
                "columns_include": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              },
              "required": [
                "column",
                "target_label"
              ]
            }
          },
          "replace": {
            "type": "boolean",
            "default": false
          }
        },
        "required": [
          "table_id",
          "rules"
        ]
      }
    },
    {
      "name": "data.index_table_columns",
      "namespace": "data",
      "description": "Mark table columns as indexed: each row gets a typed copy (<col>__n number, __d ISO date, __b bool) next to the original string, and a property index is built scoped to that table. Set at the 'agent' layer: a column a user already set is not overridden. Cells that do not parse keep only their string and are counted in typed_skipped. Requires editor role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "table_id",
        "columns"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "table_id": {
            "type": "string"
          },
          "columns": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "table_id",
          "columns"
        ]
      }
    },
    {
      "name": "data.query_table_rows",
      "namespace": "data",
      "description": "Filter one table's rows. 'where' maps a column to a value (equality) or to operators {$eq,$ne,$lt,$lte,$gt,$gte,$in,$nin,$exists}. Indexed typed columns compare as numbers / ISO dates / bools and operands are parsed like cells (\"\u00a31,200\", \"3 March 2025\"); other columns compare strings. Call data.index_table_columns first to range-filter a numeric or date column. Returns rows ordered by row_index, each with its cells.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "table_id"
      ],
      "optional_params": [
        "where",
        "limit"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "table_id": {
            "type": "string"
          },
          "where": {
            "type": "object"
          },
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 1000,
            "default": 100
          }
        },
        "required": [
          "table_id"
        ]
      }
    },
    {
      "name": "journey.start",
      "namespace": "journey",
      "description": "Create a new Journey Engine instance for an entity and move it to the first stage.  All transitions are recorded as immutable graph edges.  Requires editor role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "journey_type",
        "entity_id"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "journey_type": {
            "type": "string",
            "description": "Journey type to instantiate (e.g. 'sales-cycle')."
          },
          "entity_id": {
            "type": "string",
            "description": "ID of the entity node the journey is for."
          }
        },
        "required": [
          "journey_type",
          "entity_id"
        ]
      }
    },
    {
      "name": "journey.advance",
      "namespace": "journey",
      "description": "Advance a journey instance to the next stage.  Actor and notes are written to the audit trail as an ADVANCED_TO edge.  Requires editor role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "instance_id",
        "to_stage"
      ],
      "optional_params": [
        "notes"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "instance_id": {
            "type": "string",
            "description": "ID of the journey instance."
          },
          "to_stage": {
            "type": "string",
            "description": "Stage name to advance to."
          },
          "notes": {
            "type": "string",
            "description": "Optional notes for the audit trail."
          }
        },
        "required": [
          "instance_id",
          "to_stage"
        ]
      }
    },
    {
      "name": "journey.status",
      "namespace": "journey",
      "description": "Return the full state and audit trail for a journey instance \u2014 every stage transition, AI recommendation, and HITL decision.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "instance_id"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "instance_id": {
            "type": "string",
            "description": "ID of the journey instance."
          }
        },
        "required": [
          "instance_id"
        ]
      }
    },
    {
      "name": "journey.define",
      "namespace": "journey",
      "description": "Define a new journey type (workflow template) with ordered stages, owner systems, and per-stage SLA policies.  Once defined, instances can be started with journey.start.  Call this first when building any new workflow \u2014 the agent can define the entire process in one call.  Use overwrite=true to update an existing definition. Requires journey:admin permission (admin or super_admin by default). Use operation=configure_ai with ai_enabled to persistently enable/disable this tenant's advisor. Generation uses tenant LLM settings; delivery is currently best-effort.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [
        "operation",
        "ai_enabled",
        "journey_type",
        "description",
        "stages",
        "overwrite"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "operation": {
            "type": "string",
            "enum": [
              "define",
              "configure_ai"
            ],
            "default": "define"
          },
          "ai_enabled": {
            "type": "boolean",
            "description": "Required for configure_ai. Explicit opt-in to automatic LLM calls for this tenant."
          },
          "journey_type": {
            "type": "string",
            "description": "Unique snake_case name for this workflow (e.g. 'loan_application', 'supplier_approval')."
          },
          "description": {
            "type": "string",
            "description": "Human-readable description of what this journey tracks.",
            "default": ""
          },
          "stages": {
            "type": "array",
            "description": "Ordered list of stages.  First stage is the initial state.",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "description": "Stage identifier (e.g. 'kyc_verified')."
                },
                "owner_system": {
                  "type": "string",
                  "description": "System responsible for this stage.",
                  "default": "unassigned"
                },
                "description": {
                  "type": "string",
                  "description": "What happens at this stage.",
                  "default": ""
                },
                "sla_warn_seconds": {
                  "type": "integer",
                  "description": "Emit SLA warning after N seconds in this stage.  0 = no warning.",
                  "default": 0
                },
                "sla_breach_seconds": {
                  "type": "integer",
                  "description": "Mark instance STALLED after N seconds in this stage.  0 = no enforcement.",
                  "default": 0
                },
                "terminal": {
                  "type": "boolean",
                  "description": "If true, reaching this stage marks the instance as completed.  Use for branching exits (e.g. 'approved' / 'rejected').",
                  "default": false
                },
                "hitl": {
                  "type": "object",
                  "description": "Human-In-The-Loop approval gate.  When set, advancing into this stage automatically creates a pending HITL task that must be resolved before the instance can continue.",
                  "properties": {
                    "required": {
                      "type": "boolean",
                      "description": "Whether the approval task must be resolved before advancing.",
                      "default": true
                    },
                    "assigned_role": {
                      "type": "string",
                      "description": "Role that can action this task (e.g. 'compliance_officer')."
                    },
                    "title": {
                      "type": "string",
                      "description": "Task title shown to the reviewer.",
                      "default": ""
                    },
                    "description": {
                      "type": "string",
                      "description": "Task description / instructions for the reviewer.",
                      "default": ""
                    },
                    "advance_to_stage": {
                      "type": "string",
                      "description": "Stage to advance to on approval.  Defaults to next stage.",
                      "default": ""
                    },
                    "expires_in_seconds": {
                      "type": "integer",
                      "description": "Optional deadline for the HITL task (seconds).  Null = no deadline."
                    }
                  },
                  "required": [
                    "assigned_role"
                  ]
                },
                "ai_step": {
                  "type": "object",
                  "description": "Native stage advisory configuration. Uses tenant LLM settings after configure_ai opt-in; auto_execute=false suggests only and HITL gates remain enforced.",
                  "properties": {
                    "trigger": {
                      "type": "string",
                      "enum": [
                        "manual",
                        "on_enter",
                        "on_sla_warn",
                        "on_sla_breach"
                      ],
                      "default": "manual"
                    },
                    "auto_execute": {
                      "type": "boolean",
                      "default": false
                    },
                    "allowed_actions": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "enum": [
                          "suggest_advance",
                          "force_advance",
                          "cancel",
                          "flag",
                          "hold",
                          "annotate",
                          "no_action"
                        ]
                      }
                    },
                    "system_prompt": {
                      "type": "string"
                    },
                    "extra_context": {
                      "type": "object"
                    }
                  },
                  "additionalProperties": false
                }
              },
              "required": [
                "name"
              ]
            }
          },
          "overwrite": {
            "type": "boolean",
            "description": "Replace an existing definition with the same journey_type.  Default false.",
            "default": false
          }
        },
        "required": [],
        "anyOf": [
          {
            "properties": {
              "operation": {
                "const": "define"
              }
            },
            "required": [
              "journey_type",
              "stages"
            ]
          },
          {
            "properties": {
              "operation": {
                "const": "configure_ai"
              }
            },
            "required": [
              "operation",
              "ai_enabled"
            ]
          }
        ]
      }
    },
    {
      "name": "journey.list",
      "namespace": "journey",
      "description": "List journey instances with optional filters.  Use this to discover what is in flight, find instances for a specific entity, or check all instances of a given type.  Also returns all defined journey types when called with no arguments.  Essential for any agent monitoring or orchestrating workflows. Set runtime_status=true to inspect this tenant's advisor enablement, provider readiness and delivery guarantees.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [
        "journey_type",
        "entity_id",
        "status",
        "list_types",
        "runtime_status"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "journey_type": {
            "type": "string",
            "description": "Filter by journey type (e.g. 'loan_application')."
          },
          "entity_id": {
            "type": "string",
            "description": "Filter by the entity the journey is tracking."
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "completed",
              "cancelled",
              "stalled"
            ],
            "description": "Filter by instance status."
          },
          "list_types": {
            "type": "boolean",
            "description": "Return defined journey type names instead of instances.  Default false.",
            "default": false
          },
          "runtime_status": {
            "type": "boolean",
            "description": "Return tenant Journey AI configuration/readiness instead of instances.",
            "default": false
          }
        },
        "required": []
      }
    },
    {
      "name": "journey.sla_alerts",
      "namespace": "journey",
      "description": "Inspect and operate tenant SLA monitoring. operation=breached (default) returns active journey instances that have breached their SLA. health reports local monitor state, not scheduler/provider health. history returns a bounded event page for instance_id in event-type/native-adjacency order, not time order. acknowledge appends an immutable acknowledgement (journey:write); reset resumes only a stalled occurrence and resets its clock (journey:admin), requiring reason and expected_stage_entered_at from journey.status. Acknowledgement does not resolve a breach or change the clock. Legacy breach results contain active instances past their breach deadline. Use history for recorded warning/breach events. Use this for proactive monitoring: an agent can poll this tool on a schedule and take remediation actions (escalate, reassign, cancel) without waiting for a human to notice.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [
        "journey_type",
        "operation",
        "instance_id",
        "event_id",
        "notes",
        "reason",
        "expected_stage_entered_at",
        "limit",
        "offset"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "journey_type": {
            "type": "string",
            "description": "Restrict to a specific journey type.  Omit for all types."
          },
          "operation": {
            "type": "string",
            "enum": [
              "breached",
              "health",
              "history",
              "acknowledge",
              "reset"
            ],
            "default": "breached"
          },
          "instance_id": {
            "type": "string",
            "minLength": 1
          },
          "event_id": {
            "type": "string",
            "minLength": 1
          },
          "notes": {
            "type": "string",
            "maxLength": 4096
          },
          "reason": {
            "type": "string",
            "minLength": 1,
            "maxLength": 4096
          },
          "expected_stage_entered_at": {
            "type": "string",
            "minLength": 1
          },
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 200,
            "default": 50
          },
          "offset": {
            "type": "integer",
            "minimum": 0,
            "default": 0
          }
        },
        "required": [],
        "allOf": [
          {
            "if": {
              "properties": {
                "operation": {
                  "enum": [
                    "history",
                    "acknowledge",
                    "reset"
                  ]
                }
              },
              "required": [
                "operation"
              ]
            },
            "then": {
              "required": [
                "instance_id"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "operation": {
                  "const": "acknowledge"
                }
              },
              "required": [
                "operation"
              ]
            },
            "then": {
              "required": [
                "event_id"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "operation": {
                  "const": "reset"
                }
              },
              "required": [
                "operation"
              ]
            },
            "then": {
              "required": [
                "reason",
                "expected_stage_entered_at"
              ]
            }
          }
        ]
      }
    },
    {
      "name": "journey.list_hitl",
      "namespace": "journey",
      "description": "List pending Human-In-The-Loop (HITL) tasks \u2014 decisions that require a human (or agent acting as human proxy) to approve, reject, or escalate before the journey can continue.  Returns task ID, title, assigned role, description, and the stage the journey is waiting on.  An agent can use this to surface pending decisions to the user or take autonomous action if authorised.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [
        "instance_id",
        "assigned_role",
        "status"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "instance_id": {
            "type": "string",
            "description": "Restrict to HITL tasks for a specific journey instance."
          },
          "assigned_role": {
            "type": "string",
            "description": "Filter by role (e.g. 'compliance_officer')."
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "claimed",
              "completed",
              "rejected",
              "expired"
            ],
            "description": "Filter by task status.  Default: pending."
          }
        },
        "required": []
      }
    },
    {
      "name": "journey.resolve_hitl",
      "namespace": "journey",
      "description": "Resolve a Human-In-The-Loop (HITL) task \u2014 approve, reject, or escalate it.  On approval the journey automatically advances to the next stage if advance_to_stage is set.  The decision is written to the immutable graph audit trail with the actor and timestamp.  An AI agent acting as a human proxy must set actor to the user or role it is acting on behalf of.  Requires editor role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "task_id",
        "action",
        "actor"
      ],
      "optional_params": [
        "decision",
        "advance_to_stage",
        "notes",
        "new_assigned_role"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "task_id": {
            "type": "string",
            "description": "ID of the HITL task to resolve."
          },
          "action": {
            "type": "string",
            "enum": [
              "complete",
              "reject",
              "escalate"
            ],
            "description": "Resolution action."
          },
          "actor": {
            "type": "string",
            "description": "User or system making the decision (written to audit trail)."
          },
          "decision": {
            "type": "string",
            "description": "Decision label for complete actions (e.g. 'approved', 'denied').  Default 'approved'.",
            "default": "approved"
          },
          "advance_to_stage": {
            "type": "string",
            "description": "Stage to advance the journey to on completion.  Omit to leave stage unchanged."
          },
          "notes": {
            "type": "string",
            "description": "Notes written to the audit trail.",
            "default": ""
          },
          "new_assigned_role": {
            "type": "string",
            "description": "New role to escalate to (required when action=escalate)."
          }
        },
        "required": [
          "task_id",
          "action",
          "actor"
        ]
      }
    },
    {
      "name": "journey.audit",
      "namespace": "journey",
      "description": "Retrieve the immutable audit trail for a journey instance.  Returns every stage transition, HITL decision, SLA event, and AI-step note recorded against the instance, in chronological order.  The audit trail is append-only \u2014 nothing can be deleted or mutated.  Use this to review what happened, why an instance stalled, or what an AI agent decided at each step.  Requires viewer role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "instance_id"
      ],
      "optional_params": [
        "limit"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "instance_id": {
            "type": "string",
            "description": "Journey instance ID to retrieve the audit trail for."
          },
          "limit": {
            "type": "integer",
            "description": "Maximum number of events to return (most recent first).  0 = all.",
            "default": 0
          }
        },
        "required": [
          "instance_id"
        ]
      }
    },
    {
      "name": "data.ingest_file",
      "namespace": "data",
      "description": "Send a document file (PDF, DOCX, PPTX, XLSX, HTML, IFC, CSV, \u2026) to Purple8 DocIntel for parsing, entity extraction, and graph ingestion.  The document is fetched by DocIntel from a public URL, not a local path. The complete extraction is committed only when finished successfully. auto_commit=false returns a review-only preview; pending jobs return job_id for resumption. URL extraction does not retain original bytes in Graph; supply file_ref or commit an original separately. Use this when the knowledge source is a document rather than raw text.  Requires editor role and DocIntel to be running. After an interrupted write, ask the user to confirm a retry; use data.commit with the retained reviewed payload instead of re-extracting.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "url",
        "source_name"
      ],
      "optional_params": [
        "profile_hint",
        "auto_commit",
        "job_id",
        "wait_seconds",
        "file_ref"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "description": "Publicly accessible URL of the document to fetch and process."
          },
          "source_name": {
            "type": "string",
            "description": "Label for provenance tracking (e.g. 'loan_policy_v3.pdf')."
          },
          "profile_hint": {
            "type": "string",
            "enum": [
              "",
              "aec",
              "contract",
              "financial",
              "scientific",
              "general"
            ],
            "description": "Extraction profile; omit for auto-detection."
          },
          "auto_commit": {
            "type": "boolean",
            "default": true,
            "description": "false returns the complete preview without graph writes. Review then use data.commit."
          },
          "job_id": {
            "type": "string",
            "description": "Resume an earlier extraction instead of submitting again; repeat the original input arguments."
          },
          "wait_seconds": {
            "type": "integer",
            "minimum": 0,
            "maximum": 600,
            "default": 30,
            "description": "Maximum wait for an admitted extraction. Pending jobs are NOT committed; resume with job_id."
          },
          "file_ref": {
            "type": "string",
            "description": "Optional existing Graph file_id in this tenant, used as the original/document anchor at commit."
          }
        },
        "required": [
          "url",
          "source_name"
        ]
      }
    },
    {
      "name": "graph.poll_changes",
      "namespace": "graph",
      "description": "Poll the CDC (Change Data Capture) event stream for recent graph mutations. Returns up to *limit* events that occurred after *since_sequence* (exclusive). Use this to detect new nodes, edges, or journey transitions without a persistent connection \u2014 ideal for agents that need to react to graph changes.  Store the highest *sequence* from the response and pass it as *since_sequence* on the next poll to advance the cursor.  Start with since_sequence=0 to read from the beginning.  Filter by event_type (node_added, edge_added, node_updated, edge_updated, node_deleted, edge_deleted) to reduce noise.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [
        "since_sequence",
        "limit",
        "event_type"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "since_sequence": {
            "type": "integer",
            "description": "Return only events with sequence > this value.  Pass 0 to start from the beginning.",
            "default": 0
          },
          "limit": {
            "type": "integer",
            "description": "Maximum number of events to return.  Default 50, max 500.",
            "default": 50
          },
          "event_type": {
            "type": "string",
            "description": "Filter to a specific event type: node_added, edge_added, node_updated, edge_updated, node_deleted, edge_deleted.  Omit for all types."
          }
        },
        "required": []
      }
    },
    {
      "name": "graph.wait_for_changes",
      "namespace": "graph",
      "description": "Block until the next graph mutation after *since_sequence*, or until *timeout* seconds elapse \u2014 a push-latency alternative to graph.poll_changes.  Where poll_changes returns immediately (an instant snapshot), wait_for_changes holds the connection open and returns the moment a matching event occurs, so reacting agents see changes with near-zero latency and without burning CPU in a tight polling loop.  Ideal for multi-agent coordination: one agent writes to the graph, another is woken instantly to react.  Cursor semantics are identical to poll_changes \u2014 store the response *next_since_sequence* and pass it back on the next call.  The response includes a *waited* flag: false = events were already available (catch-up), true = the call blocked (and may return an empty list on timeout, which is normal \u2014 just call again to keep waiting).  Filter by event_type to be woken only by node_added, edge_added, node_updated, edge_updated, node_deleted, or edge_deleted.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [
        "since_sequence",
        "timeout",
        "limit",
        "event_type"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "since_sequence": {
            "type": "integer",
            "description": "Return only events with sequence > this value.  Pass 0 to start from the beginning.",
            "default": 0
          },
          "timeout": {
            "type": "number",
            "description": "Maximum seconds to block waiting for the first event (0\u201360).  0 = non-blocking catch-up only.  Default 25.",
            "default": 25
          },
          "limit": {
            "type": "integer",
            "description": "Maximum number of events to return.  Default 50, max 500.",
            "default": 50
          },
          "event_type": {
            "type": "string",
            "description": "Filter to a specific event type: node_added, edge_added, node_updated, edge_updated, node_deleted, edge_deleted.  Omit for all types."
          }
        },
        "required": []
      }
    },
    {
      "name": "graph.auto_config",
      "namespace": "graph",
      "description": "Inspect the hardware-derived QCDR configuration recommendation for this Purple8 engine, and optionally simulate the impact of parameter overrides before committing.  Called with no arguments: returns the current proposal \u2014 hardware detected, quality tier chosen, QCDR assessment per dimension (Quality/Cost/Speed/Risk), and the five tuning levers available.  Called with one or more override parameters: runs what_if() and returns a structured diff showing exactly which QCDR dimensions improve, degrade, or stay unchanged \u2014 so you can tune with confidence before locking down.  All parameters are optional.  Example: {\"M\": 8} shows the QCDR impact of lowering graph connectivity.  Example: {\"alpha\": 0.9} shows the impact of using 90% of available RAM.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [
        "M",
        "ef_construction",
        "segment_size",
        "batch_size",
        "max_hot_segments",
        "alpha"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "M": {
            "type": "integer",
            "description": "HNSW graph connectivity per node (4\u201332).  Higher = better recall, more RAM per segment.",
            "minimum": 4,
            "maximum": 32
          },
          "ef_construction": {
            "type": "integer",
            "description": "ef during HNSW build (8\u20131024).  Higher = better recall, slower ingest.",
            "minimum": 8,
            "maximum": 1024
          },
          "segment_size": {
            "type": "integer",
            "description": "Nodes per sealed segment.  Larger = fewer segments, more RAM per seal cycle.",
            "minimum": 100
          },
          "batch_size": {
            "type": "integer",
            "description": "Write-buffer batch size.  Larger = higher throughput, more peak RAM.",
            "minimum": 10
          },
          "max_hot_segments": {
            "type": "integer",
            "description": "Sealed segments pinned in RAM.  Higher = lower cold-I/O risk.",
            "minimum": 1
          },
          "alpha": {
            "type": "number",
            "description": "Target RAM fraction (0.1\u20131.0).  Higher = more budget, higher peak RSS risk.",
            "minimum": 0.1,
            "maximum": 1.0
          }
        },
        "required": []
      }
    },
    {
      "name": "graph.delete_node",
      "namespace": "graph",
      "description": "Delete a node and all its incident edges from the graph.  Returns ``{\"deleted\": true}`` when the node existed and was removed, or ``{\"deleted\": false}`` when no node with that ID was found.  Requires editor role.  For source Files set file=true to use the lineage-safe file lifecycle. Set erase=true with a documented reason for explicit erasure (super_admin only); surviving derivatives are reported for review, not silently erased. \u26a0 human_only \u2014 agents are blocked; a human operator must perform this action directly.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": true,
      "required_params": [
        "node_id"
      ],
      "optional_params": [
        "file",
        "erase",
        "reason"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "node_id": {
            "type": "string",
            "description": "ID of the node to delete."
          },
          "file": {
            "type": "boolean",
            "default": false,
            "description": "Use the source File lifecycle, not generic node deletion."
          },
          "erase": {
            "type": "boolean",
            "default": false,
            "description": "Explicit irreversible erasure; requires super_admin."
          },
          "reason": {
            "type": "string",
            "minLength": 10,
            "description": "Required documented reason when erase=true."
          }
        },
        "required": [
          "node_id"
        ]
      }
    },
    {
      "name": "rag.rerank",
      "namespace": "rag",
      "description": "Graph-signal reranking of vector / hybrid search candidates.  Takes a list of ``{node_id, score, ...}`` candidates (as returned by graph.vector_search or rag.hybrid_query), blends their base cosine score with a graph-neighbourhood density signal, and returns them sorted by the combined final score.  alpha=1.0 = pure base score (no-op rerank).  alpha=0.0 = pure graph signal.  Default alpha=0.7 \u2014 strongly favours base score while rewarding hubs.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "candidates"
      ],
      "optional_params": [
        "top_k",
        "alpha"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "candidates": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "List of candidate objects, each with ``node_id`` (str) and ``score`` (float) fields.  Additional fields are passed through."
          },
          "top_k": {
            "type": "integer",
            "description": "Return at most this many results.  Omit to return all.",
            "minimum": 1
          },
          "alpha": {
            "type": "number",
            "description": "Blend weight (0.0=graph, 1.0=base score).  Default 0.7.",
            "default": 0.7,
            "minimum": 0.0,
            "maximum": 1.0
          }
        },
        "required": [
          "candidates"
        ]
      }
    },
    {
      "name": "quantum.anneal",
      "namespace": "quantum",
      "description": "Run Simulated Annealing (optionally with greedy refinement) on a QUBO problem and return the best binary solution found.  Suitable for combinatorial optimisation problems including VRP, scheduling, and binary portfolio selection.  hybrid=true (default) runs a greedy descent pass after SA which typically reduces residual energy by 2\u201315 %.  Requires editor role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "n",
        "Q"
      ],
      "optional_params": [
        "problem_id",
        "n_steps",
        "t_start",
        "t_end",
        "schedule",
        "seed",
        "hybrid",
        "warm_start"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "n": {
            "type": "integer",
            "description": "Number of binary variables.",
            "minimum": 2
          },
          "Q": {
            "type": "array",
            "items": {
              "type": "array",
              "items": {
                "type": "number"
              }
            },
            "description": "n\u00d7n QUBO coupling matrix (row-major list of lists)."
          },
          "problem_id": {
            "type": "string",
            "description": "Optional problem identifier."
          },
          "n_steps": {
            "type": "integer",
            "description": "Annealing steps.  Default 2000.",
            "default": 2000
          },
          "t_start": {
            "type": "number",
            "description": "Initial temperature.  Default 10.0.",
            "default": 10.0
          },
          "t_end": {
            "type": "number",
            "description": "Final temperature.  Default 0.01.",
            "default": 0.01
          },
          "schedule": {
            "type": "string",
            "enum": [
              "exponential",
              "linear",
              "logarithmic",
              "adaptive"
            ],
            "description": "Cooling schedule.  Default exponential.",
            "default": "exponential"
          },
          "seed": {
            "type": "integer",
            "description": "RNG seed for reproducibility."
          },
          "hybrid": {
            "type": "boolean",
            "description": "Run greedy refinement after SA.  Default true.",
            "default": true
          },
          "warm_start": {
            "type": "array",
            "items": {
              "type": "integer"
            },
            "description": "Binary warm-start vector, length n."
          }
        },
        "required": [
          "n",
          "Q"
        ]
      }
    },
    {
      "name": "quantum.optimize",
      "namespace": "quantum",
      "description": "Topology-aware QUBO solver dispatch \u2014 automatically selects between greedy descent, simulated annealing, tabu search, and hybrid SA+greedy based on problem size and density.  Prefer this over quantum.anneal when you don't need explicit solver control.  Returns the solution, energy, and the solver profile that was used.  Requires editor role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "n",
        "Q"
      ],
      "optional_params": [
        "problem_id",
        "domain",
        "force_method"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "n": {
            "type": "integer",
            "description": "Number of binary variables.",
            "minimum": 2
          },
          "Q": {
            "type": "array",
            "items": {
              "type": "array",
              "items": {
                "type": "number"
              }
            },
            "description": "n\u00d7n QUBO coupling matrix."
          },
          "problem_id": {
            "type": "string",
            "description": "Optional identifier."
          },
          "domain": {
            "type": "string",
            "enum": [
              "vrp",
              "portfolio",
              "scheduling",
              "general"
            ],
            "description": "Domain hint for profile selection."
          },
          "force_method": {
            "type": "string",
            "enum": [
              "greedy",
              "simulated_annealing",
              "tabu",
              "hybrid"
            ],
            "description": "Override the auto-selected solver."
          }
        },
        "required": [
          "n",
          "Q"
        ]
      }
    },
    {
      "name": "quantum.simulate",
      "namespace": "quantum",
      "description": "Construct a random Matrix Product State (MPS) tensor network and optionally compute the expectation value \u27e8\u03c8|O|\u03c8\u27e9 for a given MPO operator.  Useful for validating tensor network calculations without a quantum hardware backend.  operator='identity' verifies norm preservation; operator='transverse_ising' computes the Ising Hamiltonian expectation.  Requires editor role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "n_sites"
      ],
      "optional_params": [
        "bond_dim",
        "phys_dim",
        "seed",
        "operator",
        "ising_h"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "n_sites": {
            "type": "integer",
            "description": "Number of tensor sites.",
            "minimum": 2,
            "maximum": 50
          },
          "bond_dim": {
            "type": "integer",
            "description": "Bond dimension D.  Default 4.",
            "default": 4
          },
          "phys_dim": {
            "type": "integer",
            "description": "Physical dimension d (2 for qubits).  Default 2.",
            "default": 2
          },
          "seed": {
            "type": "integer",
            "description": "RNG seed."
          },
          "operator": {
            "type": "string",
            "enum": [
              "identity",
              "transverse_ising"
            ],
            "description": "MPO to apply.  Omit to return norm only."
          },
          "ising_h": {
            "type": "number",
            "description": "Transverse field strength (transverse_ising only).  Default 1.0.",
            "default": 1.0
          }
        },
        "required": [
          "n_sites"
        ]
      }
    },
    {
      "name": "quantum.encode_state",
      "namespace": "quantum",
      "description": "Encode a quantum state vector and store it as a Purple8 graph node.  The state is HNSW-indexed via an interleaved real/imag embedding so it can be retrieved by fidelity similarity or compared pair-wise via quantum.compare.  Accepts a complex amplitude vector split into real and imaginary lists.  The state is automatically normalised.  Returns the HilbertStateRecord with the assigned state_id and node_id.  Requires editor role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "amplitudes_real"
      ],
      "optional_params": [
        "amplitudes_imag",
        "state_id",
        "domain",
        "metadata"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "amplitudes_real": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "description": "Real parts of state-vector amplitudes."
          },
          "amplitudes_imag": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "description": "Imaginary parts.  Zeros if omitted."
          },
          "state_id": {
            "type": "string",
            "description": "Human-readable identifier.  Auto-generated if empty."
          },
          "domain": {
            "type": "string",
            "description": "Domain tag for filtering (e.g. 'chemistry', 'logistics').  Default 'default'.",
            "default": "default"
          },
          "metadata": {
            "type": "object",
            "description": "Arbitrary key-value metadata stored on the graph node."
          }
        },
        "required": [
          "amplitudes_real"
        ]
      }
    },
    {
      "name": "quantum.measure",
      "namespace": "quantum",
      "description": "Simulate projective measurement of a stored quantum state.  Loads the state vector from the graph store and samples n_shots computational-basis outcomes according to the Born-rule probability distribution.  Returns counts per bitstring and the dominant (most-probable) outcome.  Requires viewer role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "state_id"
      ],
      "optional_params": [
        "n_shots",
        "seed"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "state_id": {
            "type": "string",
            "description": "ID of a previously encoded state (from quantum.encode_state)."
          },
          "n_shots": {
            "type": "integer",
            "description": "Number of measurement shots.  Default 1024.",
            "default": 1024,
            "minimum": 1,
            "maximum": 100000
          },
          "seed": {
            "type": "integer",
            "description": "RNG seed for reproducibility."
          }
        },
        "required": [
          "state_id"
        ]
      }
    },
    {
      "name": "quantum.vqe_step",
      "namespace": "quantum",
      "description": "Execute one Variational Quantum Eigensolver step using a pure-numpy RBM (Restricted Boltzmann Machine) variational ansatz.  Pass the weights from the previous step to continue training; omit them to start from a random initialisation.  Returns updated weights and the estimated ground-state energy.  Loop this tool to converge toward the variational ground state.  Supports transverse_ising and heisenberg Hamiltonians.  Requires editor role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "n_visible",
        "n_hidden"
      ],
      "optional_params": [
        "hamiltonian",
        "J",
        "h",
        "n_samples",
        "learning_rate",
        "use_sr",
        "seed",
        "weights_a",
        "weights_b",
        "weights_W_flat"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "n_visible": {
            "type": "integer",
            "description": "Number of visible units (system size).",
            "minimum": 2
          },
          "n_hidden": {
            "type": "integer",
            "description": "Number of hidden units.",
            "minimum": 1
          },
          "hamiltonian": {
            "type": "string",
            "enum": [
              "transverse_ising",
              "heisenberg"
            ],
            "description": "Hamiltonian to optimise.  Default transverse_ising.",
            "default": "transverse_ising"
          },
          "J": {
            "type": "number",
            "description": "Coupling constant.  Default 1.0.",
            "default": 1.0
          },
          "h": {
            "type": "number",
            "description": "Transverse field (transverse_ising only).  Default 0.5.",
            "default": 0.5
          },
          "n_samples": {
            "type": "integer",
            "description": "Metropolis samples per step.  Default 200.",
            "default": 200
          },
          "learning_rate": {
            "type": "number",
            "description": "SGD/SR learning rate.  Default 0.01.",
            "default": 0.01
          },
          "use_sr": {
            "type": "boolean",
            "description": "Use Stochastic Reconfiguration (natural gradient).  Default false.",
            "default": false
          },
          "seed": {
            "type": "integer",
            "description": "RNG seed."
          },
          "weights_a": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "description": "Visible bias weights from prior step."
          },
          "weights_b": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "description": "Hidden bias weights from prior step."
          },
          "weights_W_flat": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "description": "Flattened (n_visible\u00d7n_hidden) weight matrix from prior step."
          }
        },
        "required": [
          "n_visible",
          "n_hidden"
        ]
      }
    },
    {
      "name": "quantum.compare",
      "namespace": "quantum",
      "description": "Compute the quantum fidelity F = |\u27e8\u03c8_A|\u03c8_B\u27e9|\u00b2 between two stored quantum states.  Both states must have been previously encoded via quantum.encode_state.  Returns fidelity in [0, 1]: 1.0 = identical states, 0.0 = orthogonal.  Useful for checking whether two optimisation solutions correspond to the same quantum state, or for nearest-state retrieval workflows.  Requires viewer role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "state_id_a",
        "state_id_b"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "state_id_a": {
            "type": "string",
            "description": "ID of the first state."
          },
          "state_id_b": {
            "type": "string",
            "description": "ID of the second state."
          }
        },
        "required": [
          "state_id_a",
          "state_id_b"
        ]
      }
    },
    {
      "name": "quantum.profile",
      "namespace": "quantum",
      "description": "Recommend the optimal QUBO solver for a given problem size and density.  No computation is performed \u2014 this is a pure advisory call.  Returns the recommended solver method, an anneal config dict ready to pass to quantum.anneal, and a rationale.  Call this before quantum.optimize when you need explicit time/quality trade-off control.  Requires viewer role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "n"
      ],
      "optional_params": [
        "density",
        "domain"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "n": {
            "type": "integer",
            "description": "Problem size (number of binary variables).",
            "minimum": 2
          },
          "density": {
            "type": "number",
            "description": "Fraction of non-zero off-diagonal entries (0.0\u20131.0).  Default 0.5.",
            "default": 0.5,
            "minimum": 0.0,
            "maximum": 1.0
          },
          "domain": {
            "type": "string",
            "enum": [
              "vrp",
              "portfolio",
              "scheduling",
              "general"
            ],
            "description": "Domain hint."
          }
        },
        "required": [
          "n"
        ]
      }
    },
    {
      "name": "graph.import_nquads",
      "namespace": "graph",
      "description": "Import bounded RDF 1.1 N-Quads with an explicit stable blank_node_scope. Full parse and authorization preflight precede writes. Quads commit individually, not atomically; interruption reports acknowledged progress. Retry the entire input with the same scope. Requires data:import and node/edge read/create permissions. Preserves lexical literals; no URL fetching or inference.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "nquads",
        "blank_node_scope"
      ],
      "optional_params": [
        "max_input_bytes",
        "max_statements"
      ],
      "inputSchema": {
        "additionalProperties": false,
        "properties": {
          "nquads": {
            "maxLength": 8388608,
            "title": "Nquads",
            "type": "string"
          },
          "blank_node_scope": {
            "title": "Blank Node Scope",
            "type": "string"
          },
          "max_input_bytes": {
            "default": 8388608,
            "maximum": 8388608,
            "minimum": 1,
            "title": "Max Input Bytes",
            "type": "integer"
          },
          "max_statements": {
            "default": 1000,
            "maximum": 1000,
            "minimum": 1,
            "title": "Max Statements",
            "type": "integer"
          }
        },
        "required": [
          "nquads",
          "blank_node_scope"
        ],
        "title": "SemanticImportRequest",
        "type": "object"
      }
    },
    {
      "name": "graph.assert_statement",
      "namespace": "graph",
      "description": "Idempotently assert one native RDF quad with exact lexical terms, explicit blank-node scope and optional graph name. Uses existing node/edge create and read permissions, record policies and API-key label restrictions. No bulk import or caller-supplied metadata.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "statement"
      ],
      "optional_params": [],
      "inputSchema": {
        "$defs": {
          "RDFStatement": {
            "additionalProperties": false,
            "description": "One asserted quad. None identifies the default graph, not every graph.",
            "properties": {
              "subject": {
                "$ref": "#/$defs/RDFTerm"
              },
              "predicate": {
                "$ref": "#/$defs/RDFTerm"
              },
              "object": {
                "$ref": "#/$defs/RDFTerm"
              },
              "graph": {
                "anyOf": [
                  {
                    "$ref": "#/$defs/RDFTerm"
                  },
                  {
                    "type": "null"
                  }
                ],
                "default": null
              }
            },
            "required": [
              "subject",
              "predicate",
              "object"
            ],
            "title": "RDFStatement",
            "type": "object"
          },
          "RDFTerm": {
            "additionalProperties": false,
            "description": "An immutable RDF term; blank-node scope is explicit, never global.",
            "properties": {
              "kind": {
                "enum": [
                  "iri",
                  "blank",
                  "literal"
                ],
                "title": "Kind",
                "type": "string"
              },
              "value": {
                "title": "Value",
                "type": "string"
              },
              "datatype": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "default": null,
                "title": "Datatype"
              },
              "language": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "default": null,
                "title": "Language"
              },
              "scope": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "default": null,
                "title": "Scope"
              }
            },
            "required": [
              "kind",
              "value"
            ],
            "title": "RDFTerm",
            "type": "object"
          }
        },
        "additionalProperties": false,
        "properties": {
          "statement": {
            "$ref": "#/$defs/RDFStatement"
          }
        },
        "required": [
          "statement"
        ],
        "title": "SemanticStatementRequest",
        "type": "object"
      }
    },
    {
      "name": "graph.retract_statement",
      "namespace": "graph",
      "description": "Physically remove exactly one native RDF quad, preserving other graph memberships. Admin-only; existing node/edge delete and read permissions, visibility policies and legal holds apply. human_only: AI agent callers are blocked.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "statement"
      ],
      "optional_params": [],
      "inputSchema": {
        "$defs": {
          "RDFStatement": {
            "additionalProperties": false,
            "description": "One asserted quad. None identifies the default graph, not every graph.",
            "properties": {
              "subject": {
                "$ref": "#/$defs/RDFTerm"
              },
              "predicate": {
                "$ref": "#/$defs/RDFTerm"
              },
              "object": {
                "$ref": "#/$defs/RDFTerm"
              },
              "graph": {
                "anyOf": [
                  {
                    "$ref": "#/$defs/RDFTerm"
                  },
                  {
                    "type": "null"
                  }
                ],
                "default": null
              }
            },
            "required": [
              "subject",
              "predicate",
              "object"
            ],
            "title": "RDFStatement",
            "type": "object"
          },
          "RDFTerm": {
            "additionalProperties": false,
            "description": "An immutable RDF term; blank-node scope is explicit, never global.",
            "properties": {
              "kind": {
                "enum": [
                  "iri",
                  "blank",
                  "literal"
                ],
                "title": "Kind",
                "type": "string"
              },
              "value": {
                "title": "Value",
                "type": "string"
              },
              "datatype": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "default": null,
                "title": "Datatype"
              },
              "language": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "default": null,
                "title": "Language"
              },
              "scope": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "default": null,
                "title": "Scope"
              }
            },
            "required": [
              "kind",
              "value"
            ],
            "title": "RDFTerm",
            "type": "object"
          }
        },
        "additionalProperties": false,
        "properties": {
          "statement": {
            "$ref": "#/$defs/RDFStatement"
          }
        },
        "required": [
          "statement"
        ],
        "title": "SemanticStatementRequest",
        "type": "object"
      }
    },
    {
      "name": "graph.semantic_query",
      "namespace": "graph",
      "description": "Read-only indexed RDF/LPG pattern query with policy-filtered evidence. Use tagged rdf, lpg and lpg_edge patterns. Returns unified bindings and evidence or, with output_format=nquads, a JSON envelope containing selected asserted N-Quads and selection metadata. Raw work stats are withheld (stats=null). No inferred RDF, writes, import, or whole-corpus export. Existing read permissions apply; N-Quads additionally requires data:export.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "patterns"
      ],
      "optional_params": [
        "bindings",
        "node_bindings",
        "limit",
        "limits",
        "max_output_bytes",
        "output_format"
      ],
      "inputSchema": {
        "$defs": {
          "GraphSelection": {
            "enum": [
              "any"
            ],
            "title": "GraphSelection",
            "type": "string"
          },
          "LPGEdgeReadPattern": {
            "additionalProperties": false,
            "properties": {
              "equals": {
                "additionalProperties": {
                  "anyOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "integer"
                    },
                    {
                      "type": "boolean"
                    },
                    {
                      "type": "number"
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "title": "Equals",
                "type": "object"
              },
              "iri_properties": {
                "additionalProperties": {
                  "anyOf": [
                    {
                      "$ref": "#/$defs/RDFTerm"
                    },
                    {
                      "$ref": "#/$defs/RDFVariable"
                    }
                  ]
                },
                "title": "Iri Properties",
                "type": "object"
              },
              "source": {
                "anyOf": [
                  {
                    "maxLength": 512,
                    "minLength": 1,
                    "type": "string"
                  },
                  {
                    "$ref": "#/$defs/LPGNodeVariable"
                  }
                ],
                "title": "Source"
              },
              "target": {
                "anyOf": [
                  {
                    "maxLength": 512,
                    "minLength": 1,
                    "type": "string"
                  },
                  {
                    "$ref": "#/$defs/LPGNodeVariable"
                  }
                ],
                "title": "Target"
              },
              "edge_type": {
                "anyOf": [
                  {
                    "maxLength": 256,
                    "minLength": 1,
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "default": null,
                "title": "Edge Type"
              },
              "model": {
                "const": "lpg_edge",
                "title": "Model",
                "type": "string"
              }
            },
            "required": [
              "source",
              "target",
              "model"
            ],
            "title": "LPGEdgeReadPattern",
            "type": "object"
          },
          "LPGNodeReadPattern": {
            "additionalProperties": false,
            "properties": {
              "equals": {
                "additionalProperties": {
                  "anyOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "integer"
                    },
                    {
                      "type": "boolean"
                    },
                    {
                      "type": "number"
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "title": "Equals",
                "type": "object"
              },
              "iri_properties": {
                "additionalProperties": {
                  "anyOf": [
                    {
                      "$ref": "#/$defs/RDFTerm"
                    },
                    {
                      "$ref": "#/$defs/RDFVariable"
                    }
                  ]
                },
                "title": "Iri Properties",
                "type": "object"
              },
              "node_id": {
                "anyOf": [
                  {
                    "maxLength": 512,
                    "minLength": 1,
                    "type": "string"
                  },
                  {
                    "$ref": "#/$defs/LPGNodeVariable"
                  }
                ],
                "title": "Node Id"
              },
              "label": {
                "anyOf": [
                  {
                    "maxLength": 256,
                    "minLength": 1,
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "default": null,
                "title": "Label"
              },
              "model": {
                "const": "lpg",
                "title": "Model",
                "type": "string"
              }
            },
            "required": [
              "node_id",
              "model"
            ],
            "title": "LPGNodeReadPattern",
            "type": "object"
          },
          "LPGNodeVariable": {
            "additionalProperties": false,
            "description": "A tenant-local node ID binding, never an RDF term.",
            "properties": {
              "name": {
                "title": "Name",
                "type": "string"
              }
            },
            "required": [
              "name"
            ],
            "title": "LPGNodeVariable",
            "type": "object"
          },
          "RDFReadPattern": {
            "additionalProperties": false,
            "properties": {
              "subject": {
                "anyOf": [
                  {
                    "$ref": "#/$defs/RDFTerm"
                  },
                  {
                    "$ref": "#/$defs/RDFVariable"
                  }
                ],
                "title": "Subject"
              },
              "predicate": {
                "anyOf": [
                  {
                    "$ref": "#/$defs/RDFTerm"
                  },
                  {
                    "$ref": "#/$defs/RDFVariable"
                  }
                ],
                "title": "Predicate"
              },
              "object": {
                "anyOf": [
                  {
                    "$ref": "#/$defs/RDFTerm"
                  },
                  {
                    "$ref": "#/$defs/RDFVariable"
                  }
                ],
                "title": "Object"
              },
              "graph": {
                "anyOf": [
                  {
                    "$ref": "#/$defs/RDFTerm"
                  },
                  {
                    "$ref": "#/$defs/RDFVariable"
                  },
                  {
                    "$ref": "#/$defs/GraphSelection"
                  },
                  {
                    "type": "null"
                  }
                ],
                "default": null,
                "title": "Graph"
              },
              "model": {
                "const": "rdf",
                "title": "Model",
                "type": "string"
              }
            },
            "required": [
              "subject",
              "predicate",
              "object",
              "model"
            ],
            "title": "RDFReadPattern",
            "type": "object"
          },
          "RDFTerm": {
            "additionalProperties": false,
            "description": "An immutable RDF term; blank-node scope is explicit, never global.",
            "properties": {
              "kind": {
                "enum": [
                  "iri",
                  "blank",
                  "literal"
                ],
                "title": "Kind",
                "type": "string"
              },
              "value": {
                "title": "Value",
                "type": "string"
              },
              "datatype": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "default": null,
                "title": "Datatype"
              },
              "language": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "default": null,
                "title": "Language"
              },
              "scope": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "default": null,
                "title": "Scope"
              }
            },
            "required": [
              "kind",
              "value"
            ],
            "title": "RDFTerm",
            "type": "object"
          },
          "RDFVariable": {
            "additionalProperties": false,
            "description": "A shared term binding, named without a leading question mark.",
            "properties": {
              "name": {
                "title": "Name",
                "type": "string"
              }
            },
            "required": [
              "name"
            ],
            "title": "RDFVariable",
            "type": "object"
          },
          "SemanticQueryLimits": {
            "additionalProperties": false,
            "description": "Finite per-call work and result limits; exhaustion is an error.",
            "properties": {
              "max_candidates": {
                "default": 10000,
                "maximum": 1000000,
                "minimum": 1,
                "title": "Max Candidates",
                "type": "integer"
              },
              "max_index_entries": {
                "default": 10000,
                "maximum": 1000000,
                "minimum": 1,
                "title": "Max Index Entries",
                "type": "integer"
              },
              "max_expansions": {
                "default": 10000,
                "maximum": 1000000,
                "minimum": 1,
                "title": "Max Expansions",
                "type": "integer"
              },
              "max_result_bytes": {
                "default": 8388608,
                "maximum": 67108864,
                "minimum": 1,
                "title": "Max Result Bytes",
                "type": "integer"
              }
            },
            "title": "SemanticQueryLimits",
            "type": "object"
          }
        },
        "additionalProperties": false,
        "properties": {
          "patterns": {
            "items": {
              "discriminator": {
                "mapping": {
                  "lpg": "#/$defs/LPGNodeReadPattern",
                  "lpg_edge": "#/$defs/LPGEdgeReadPattern",
                  "rdf": "#/$defs/RDFReadPattern"
                },
                "propertyName": "model"
              },
              "oneOf": [
                {
                  "$ref": "#/$defs/RDFReadPattern"
                },
                {
                  "$ref": "#/$defs/LPGNodeReadPattern"
                },
                {
                  "$ref": "#/$defs/LPGEdgeReadPattern"
                }
              ]
            },
            "maxItems": 16,
            "minItems": 1,
            "title": "Patterns",
            "type": "array"
          },
          "bindings": {
            "anyOf": [
              {
                "additionalProperties": {
                  "$ref": "#/$defs/RDFTerm"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "title": "Bindings"
          },
          "node_bindings": {
            "anyOf": [
              {
                "additionalProperties": {
                  "type": "string"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "title": "Node Bindings"
          },
          "limit": {
            "default": 100,
            "maximum": 1000,
            "minimum": 1,
            "title": "Limit",
            "type": "integer"
          },
          "limits": {
            "$ref": "#/$defs/SemanticQueryLimits"
          },
          "max_output_bytes": {
            "default": 8388608,
            "maximum": 67108864,
            "minimum": 1,
            "title": "Max Output Bytes",
            "type": "integer"
          },
          "output_format": {
            "default": "json",
            "enum": [
              "json",
              "nquads"
            ],
            "title": "Output Format",
            "type": "string"
          }
        },
        "required": [
          "patterns"
        ],
        "title": "SemanticReadRequest",
        "type": "object"
      }
    },
    {
      "name": "graph.get_edge",
      "namespace": "graph",
      "description": "Fetch a single edge (relationship) by its edge_id, returning its type, source and target node IDs, and properties.  The edge counterpart of graph.get_node.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "edge_id"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "edge_id": {
            "type": "string",
            "description": "The unique edge identifier."
          }
        },
        "required": [
          "edge_id"
        ]
      }
    },
    {
      "name": "graph.delete_edge",
      "namespace": "graph",
      "description": "Delete a single edge (relationship) by its edge_id.  The edge counterpart of graph.delete_node \u2014 completes graph CRUD so an agent can remove a relationship without deleting either endpoint.  \u26a0 human_only \u2014 agents are blocked; a human operator must perform this action directly.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "edge_id"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "edge_id": {
            "type": "string",
            "description": "The unique edge identifier to delete."
          }
        },
        "required": [
          "edge_id"
        ]
      }
    },
    {
      "name": "graph.edges_exist",
      "namespace": "graph",
      "description": "Batch relationship-existence check (up to 500 pairs per call).  Given a list of directed pairs (each source_id + target_id, optional edge_type), returns which relationships already exist.  Use this before bulk edge creation to avoid duplicate relationships \u2014 the single most useful primitive for iterative graph building by an agent.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "pairs"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "pairs": {
            "type": "array",
            "description": "Up to 500 {source_id, target_id, edge_type?} objects to check.",
            "items": {
              "type": "object"
            }
          }
        },
        "required": [
          "pairs"
        ]
      }
    },
    {
      "name": "graph.shortest_path",
      "namespace": "graph",
      "description": "Find the shortest weighted path from one node to another (Dijkstra).  Returns the ordered node sequence and total cost, or a 404 if the target is unreachable.  A core reasoning primitive \u2014 'how is X connected to Y'.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "node_id",
        "target_id"
      ],
      "optional_params": [
        "weight_property",
        "edge_type"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "node_id": {
            "type": "string",
            "description": "Start node ID."
          },
          "target_id": {
            "type": "string",
            "description": "Destination node ID."
          },
          "weight_property": {
            "type": "string",
            "description": "Edge property to use as weight.  Omit for hop-count (unit weights)."
          },
          "edge_type": {
            "type": "string",
            "description": "Restrict traversal to a single edge type.  Omit to use all edges."
          }
        },
        "required": [
          "node_id",
          "target_id"
        ]
      }
    },
    {
      "name": "graph.morans_i",
      "namespace": "graph",
      "description": "Compute Moran's I global spatial autocorrelation statistic over a set of nodes.  Measures whether nodes with similar *value_property* cluster together (I > 0), are dispersed (I < 0), or are randomly arranged (I \u2248 0) across the adjacency graph defined by *weight_edge_type* edges.  Returns I, z-score, analytical p-value, permutation p-value, and a human-readable interpretation string.  Ideal for detecting geographic or structural clustering in knowledge graphs before running LISA (graph.local_morans_i).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "node_label",
        "value_property",
        "weight_edge_type"
      ],
      "optional_params": [
        "weight_property",
        "row_standardise",
        "permutations"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "node_label": {
            "type": "string",
            "description": "Node label to analyse (e.g. 'Country')."
          },
          "value_property": {
            "type": "string",
            "description": "Numeric property on each node (e.g. 'gdp_per_capita')."
          },
          "weight_edge_type": {
            "type": "string",
            "description": "Edge type encoding spatial adjacency (e.g. 'BORDERS')."
          },
          "weight_property": {
            "type": "string",
            "description": "Edge property for weight value. Default 'weight'."
          },
          "row_standardise": {
            "type": "boolean",
            "description": "Row-standardise the spatial weights matrix. Default true."
          },
          "permutations": {
            "type": "integer",
            "description": "Permutations for pseudo p-value (0 = analytical only). Default 999.",
            "minimum": 0,
            "maximum": 9999
          }
        },
        "required": [
          "node_label",
          "value_property",
          "weight_edge_type"
        ]
      }
    },
    {
      "name": "graph.local_morans_i",
      "namespace": "graph",
      "description": "Compute LISA (Local Indicators of Spatial Association) for every node in the graph \u2014 the local version of Moran's I.  Classifies each node as HH (hot spot), LL (cold spot), HL or LH (spatial outlier), or NS (not significant).  Returns per-node LISA scores, cluster types, p-values, and a cluster_summary dict.  Use after graph.morans_i confirms global clustering \u2014 LISA pinpoints exactly which nodes drive the pattern.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "node_label",
        "value_property",
        "weight_edge_type"
      ],
      "optional_params": [
        "weight_property",
        "row_standardise",
        "permutations",
        "significance_level"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "node_label": {
            "type": "string",
            "description": "Node label to analyse."
          },
          "value_property": {
            "type": "string",
            "description": "Numeric node property."
          },
          "weight_edge_type": {
            "type": "string",
            "description": "Edge type encoding spatial adjacency."
          },
          "weight_property": {
            "type": "string",
            "description": "Edge property for weight value. Default 'weight'."
          },
          "row_standardise": {
            "type": "boolean",
            "description": "Row-standardise the spatial weights matrix. Default true."
          },
          "permutations": {
            "type": "integer",
            "description": "Permutations for conditional pseudo p-value. Default 999.",
            "minimum": 0,
            "maximum": 9999
          },
          "significance_level": {
            "type": "number",
            "description": "Alpha for cluster classification. Default 0.05.",
            "minimum": 0.001,
            "maximum": 0.5
          }
        },
        "required": [
          "node_label",
          "value_property",
          "weight_edge_type"
        ]
      }
    },
    {
      "name": "graph.centrality",
      "namespace": "graph",
      "description": "Betweenness-centrality ranking (Brandes' algorithm, exact or approximate) \u2014 the nodes that lie on the most shortest paths, i.e. the graph's structural bottlenecks / brokers.  Pass sample_size > 0 and pivot_strategy ('random' or 'degree') for O(S\u00b7E) approximate betweenness on large graphs (Phase 7.4).  Scores are normalised 0\u20131 by default.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [
        "top_k",
        "normalise",
        "sample_size",
        "pivot_strategy"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "top_k": {
            "type": "integer",
            "description": "Return the top-K most central nodes.  Default 20.",
            "default": 20
          },
          "normalise": {
            "type": "boolean",
            "description": "Normalise scores to 0\u20131.  Default true."
          },
          "sample_size": {
            "type": "integer",
            "description": "Number of pivot nodes to sample for O(S\u00b7E) approximate betweenness (0 = exact Brandes).",
            "minimum": 0
          },
          "pivot_strategy": {
            "type": "string",
            "enum": [
              "random",
              "degree"
            ],
            "description": "Pivot selection strategy when sample_size > 0: 'random' or 'degree'."
          }
        },
        "required": []
      }
    },
    {
      "name": "graph.link_prediction",
      "namespace": "graph",
      "description": "Predict likely-but-missing edges for a node using a chosen similarity method: jaccard, adamic_adar, resource_allocation, preferential_attachment, common_neighbours, or personalised_pagerank.  Returns ranked candidate target nodes with scores \u2014 directly useful for recommendation, entity resolution, and knowledge-graph completion.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "node_id"
      ],
      "optional_params": [
        "method",
        "top_k",
        "label"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "node_id": {
            "type": "string",
            "description": "Node to predict new links for."
          },
          "method": {
            "type": "string",
            "description": "jaccard | adamic_adar | resource_allocation | preferential_attachment | common_neighbours | personalised_pagerank.  Default adamic_adar.",
            "default": "adamic_adar"
          },
          "top_k": {
            "type": "integer",
            "description": "Number of candidate links to return.  Default 10.",
            "default": 10
          },
          "label": {
            "type": "string",
            "description": "Restrict candidate targets to this label.  Omit for all."
          }
        },
        "required": [
          "node_id"
        ]
      }
    },
    {
      "name": "graph.personalised_pagerank",
      "namespace": "graph",
      "description": "Compute Personalised PageRank (PPR) rooted at a seed node (Phase 7.12).  Ranks nodes by random-walk proximity to seed_id with configurable damping alpha and max_iterations.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "seed_id"
      ],
      "optional_params": [
        "alpha",
        "max_iterations",
        "top_k"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "seed_id": {
            "type": "string",
            "description": "Seed node ID to personalise PageRank around."
          },
          "alpha": {
            "type": "number",
            "description": "Damping factor (0.0\u20131.0). Default 0.85.",
            "default": 0.85
          },
          "max_iterations": {
            "type": "integer",
            "description": "Maximum power-iteration steps. Default 100.",
            "default": 100
          },
          "top_k": {
            "type": "integer",
            "description": "Number of top-scoring nodes to return. Default 20.",
            "default": 20
          }
        },
        "required": [
          "seed_id"
        ]
      }
    },
    {
      "name": "graph.triangles",
      "namespace": "graph",
      "description": "Count triangles per node and compute local and global clustering coefficients across the graph (Phase 7.11).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    },
    {
      "name": "graph.bridges",
      "namespace": "graph",
      "description": "Find bridge edges whose removal disconnects the graph using iterative Tarjan DFS in O(V+E) time (Phase 7.11).  Identifies single-point-of-failure links in infrastructure, supply chains, or structural topologies.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    },
    {
      "name": "graph.articulation_points",
      "namespace": "graph",
      "description": "Find biconnected components and articulation points (cut vertices whose removal disconnects the graph) via Tarjan's algorithm (Phase 7.11).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    },
    {
      "name": "graph.bipartite_check",
      "namespace": "graph",
      "description": "Determine whether the graph (or a pair of node labels) is bipartite via BFS 2-colouring and return the two partitions (Phase 7.11).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [
        "label_a",
        "label_b"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "label_a": {
            "type": "string",
            "description": "Optional label for partition A."
          },
          "label_b": {
            "type": "string",
            "description": "Optional label for partition B."
          }
        },
        "required": []
      }
    },
    {
      "name": "graph.bipartite_matching",
      "namespace": "graph",
      "description": "Compute maximum cardinality bipartite matching between two node label partitions via Hopcroft-Karp in O(E \u221aV) (Phase 7.11).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "label_a",
        "label_b"
      ],
      "optional_params": [
        "edge_type"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "label_a": {
            "type": "string",
            "description": "Label of nodes in partition A."
          },
          "label_b": {
            "type": "string",
            "description": "Label of nodes in partition B."
          },
          "edge_type": {
            "type": "string",
            "description": "Optional edge type filter."
          }
        },
        "required": [
          "label_a",
          "label_b"
        ]
      }
    },
    {
      "name": "graph.mst",
      "namespace": "graph",
      "description": "Compute the Minimum Spanning Tree / Forest using Kruskal's algorithm + union-find (Phase 7.11).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [
        "weight_property"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "weight_property": {
            "type": "string",
            "description": "Edge property to use as weight. Omit for edge.weight."
          }
        },
        "required": []
      }
    },
    {
      "name": "graph.motifs",
      "namespace": "graph",
      "description": "Count directed 3-node triad motif patterns (feed-forward loops, cycles, mutual dyads, etc.) in the graph (Phase 7.11).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [
        "size",
        "node_limit"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "size": {
            "type": "integer",
            "description": "Motif size (3 supported). Default 3.",
            "default": 3
          },
          "node_limit": {
            "type": "integer",
            "description": "Max nodes to sample (10\u20135000). Default 500.",
            "default": 500
          }
        },
        "required": []
      }
    },
    {
      "name": "graph.temporal_pagerank",
      "namespace": "graph",
      "description": "Compute PageRank with exponential recency decay exp(-\u03bb \u00d7 age) on edge timestamps so recent relationships carry higher authority (Phase 7.3).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [
        "decay_lambda",
        "reference_time",
        "damping",
        "max_iterations",
        "tolerance",
        "top_k"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "decay_lambda": {
            "type": "number",
            "description": "Exponential decay rate \u03bb. Default 0.01.",
            "default": 0.01
          },
          "reference_time": {
            "type": "string",
            "description": "ISO-8601 reference timestamp. Omit for current UTC time."
          },
          "damping": {
            "type": "number",
            "description": "Damping factor (0.0\u20131.0). Default 0.85.",
            "default": 0.85
          },
          "max_iterations": {
            "type": "integer",
            "description": "Max iterations. Default 100.",
            "default": 100
          },
          "tolerance": {
            "type": "number",
            "description": "Convergence tolerance. Default 1e-6.",
            "default": 1e-06
          },
          "top_k": {
            "type": "integer",
            "description": "Top-K nodes to return. Default 20.",
            "default": 20
          }
        },
        "required": []
      }
    },
    {
      "name": "graph.dynamic_pagerank",
      "namespace": "graph",
      "description": "Incremental PageRank update after edge additions or removals (Phase 7.3).  Re-scores only the k-hop frontier of changed edges instead of recomputing the entire graph.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [
        "added_edges",
        "removed_edges",
        "prev_scores",
        "damping",
        "max_iterations",
        "tolerance",
        "top_k"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "added_edges": {
            "type": "array",
            "items": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "List of [source_id, target_id] pairs added since last run."
          },
          "removed_edges": {
            "type": "array",
            "items": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "List of [source_id, target_id] pairs removed since last run."
          },
          "prev_scores": {
            "type": "object",
            "description": "Optional previous node scores map."
          },
          "damping": {
            "type": "number",
            "default": 0.85
          },
          "max_iterations": {
            "type": "integer",
            "default": 20
          },
          "tolerance": {
            "type": "number",
            "default": 1e-06
          },
          "top_k": {
            "type": "integer",
            "default": 20
          }
        },
        "required": []
      }
    },
    {
      "name": "graph.dynamic_communities",
      "namespace": "graph",
      "description": "Incremental community detection after edge additions or removals (Phase 7.3).  Re-runs label propagation only on the 2-hop neighbourhood of affected nodes.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [
        "added_edges",
        "removed_edges",
        "prev_communities",
        "max_iterations",
        "seed"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "added_edges": {
            "type": "array",
            "items": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "List of [source_id, target_id] pairs added."
          },
          "removed_edges": {
            "type": "array",
            "items": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "List of [source_id, target_id] pairs removed."
          },
          "prev_communities": {
            "type": "object",
            "description": "Optional previous {node_id: community_id} map."
          },
          "max_iterations": {
            "type": "integer",
            "default": 10
          },
          "seed": {
            "type": "integer",
            "description": "Optional RNG seed."
          }
        },
        "required": []
      }
    },
    {
      "name": "graph.structural_roles",
      "namespace": "graph",
      "description": "Fingerprint nodes into structural role classes using logarithmic degree bins and clustering-coefficient bins (Phase 7.4).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [
        "degree_bins",
        "clustering_bins",
        "persist"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "degree_bins": {
            "type": "integer",
            "default": 8,
            "minimum": 2,
            "maximum": 64
          },
          "clustering_bins": {
            "type": "integer",
            "default": 8,
            "minimum": 2,
            "maximum": 64
          },
          "persist": {
            "type": "boolean",
            "default": true
          }
        },
        "required": []
      }
    },
    {
      "name": "graph.rolesim",
      "namespace": "graph",
      "description": "Find nodes with the highest structural role similarity to a query node (Phase 7.4 RoleSim) \u2014 identifies structurally equivalent brokers, hubs, or leaves even when they share no neighbours.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "node_id"
      ],
      "optional_params": [
        "top_k",
        "clustering_bins"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "node_id": {
            "type": "string",
            "description": "Query node ID."
          },
          "top_k": {
            "type": "integer",
            "default": 10,
            "minimum": 1,
            "maximum": 500
          },
          "clustering_bins": {
            "type": "integer",
            "default": 8,
            "minimum": 2,
            "maximum": 64
          }
        },
        "required": [
          "node_id"
        ]
      }
    },
    {
      "name": "graph.fraud_rings",
      "namespace": "graph",
      "description": "Detect dense-subgraph communities likely to represent collusive fraud rings (Phase 7.5).  Runs label propagation and returns communities whose internal edge density \u2265 min_density.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [
        "min_density",
        "min_ring_size",
        "max_iterations",
        "seed"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "min_density": {
            "type": "number",
            "default": 0.5,
            "minimum": 0.0,
            "maximum": 1.0,
            "description": "Minimum internal edge density (0.0\u20131.0). Default 0.5."
          },
          "min_ring_size": {
            "type": "integer",
            "default": 3,
            "minimum": 2,
            "description": "Minimum nodes in a ring. Default 3."
          },
          "max_iterations": {
            "type": "integer",
            "default": 50,
            "minimum": 1,
            "maximum": 500
          },
          "seed": {
            "type": "integer",
            "description": "Optional RNG seed."
          }
        },
        "required": []
      }
    },
    {
      "name": "graph.simrank",
      "namespace": "graph",
      "description": "Compute SimRank structural similarity scores relative to a query node for Sybil / synthetic-identity detection (Phase 7.5).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "node_id"
      ],
      "optional_params": [
        "top_k",
        "iterations",
        "decay"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "node_id": {
            "type": "string",
            "description": "Query node ID."
          },
          "top_k": {
            "type": "integer",
            "default": 20,
            "minimum": 1,
            "maximum": 1000
          },
          "iterations": {
            "type": "integer",
            "default": 5,
            "minimum": 1,
            "maximum": 50
          },
          "decay": {
            "type": "number",
            "default": 0.8,
            "exclusiveMinimum": 0.0,
            "maximum": 1.0
          }
        },
        "required": [
          "node_id"
        ]
      }
    },
    {
      "name": "graph.laundering_paths",
      "namespace": "graph",
      "description": "Enumerate all simple (cycle-free) directed fund-flow paths between source_id and target_id for AML / money-laundering investigations (Phase 7.5).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "source_id",
        "target_id"
      ],
      "optional_params": [
        "max_paths",
        "max_depth",
        "edge_type"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "source_id": {
            "type": "string",
            "description": "Origin node ID."
          },
          "target_id": {
            "type": "string",
            "description": "Destination node ID."
          },
          "max_paths": {
            "type": "integer",
            "default": 50,
            "minimum": 1,
            "maximum": 500
          },
          "max_depth": {
            "type": "integer",
            "default": 8,
            "minimum": 1,
            "maximum": 20
          },
          "edge_type": {
            "type": "string",
            "description": "Optional edge type filter."
          }
        },
        "required": [
          "source_id",
          "target_id"
        ]
      }
    },
    {
      "name": "graph.supply_chain_route",
      "namespace": "graph",
      "description": "Find the minimum-cost route between two nodes using multi-criteria A* search with optional edge cost_property and node heuristic_property (Phase 7.5).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "source_id",
        "target_id"
      ],
      "optional_params": [
        "cost_property",
        "heuristic_property",
        "edge_type"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "source_id": {
            "type": "string",
            "description": "Start node ID."
          },
          "target_id": {
            "type": "string",
            "description": "Destination node ID."
          },
          "cost_property": {
            "type": "string",
            "description": "Edge property for cost (falls back to edge.weight)."
          },
          "heuristic_property": {
            "type": "string",
            "description": "Node property for admissible heuristic h(n)."
          },
          "edge_type": {
            "type": "string",
            "description": "Optional edge type filter."
          }
        },
        "required": [
          "source_id",
          "target_id"
        ]
      }
    },
    {
      "name": "graph.attack_paths",
      "namespace": "graph",
      "description": "Enumerate and rank cybersecurity attack paths from entry_node to asset_node scored by the product of per-edge exploitability weights in descending risk order (Phase 7.5).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "entry_node",
        "asset_node"
      ],
      "optional_params": [
        "max_depth",
        "max_paths",
        "risk_property",
        "edge_type"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "entry_node": {
            "type": "string",
            "description": "Attack entry point node ID."
          },
          "asset_node": {
            "type": "string",
            "description": "Critical target asset node ID."
          },
          "max_depth": {
            "type": "integer",
            "default": 6,
            "minimum": 1,
            "maximum": 15
          },
          "max_paths": {
            "type": "integer",
            "default": 20,
            "minimum": 1,
            "maximum": 200
          },
          "risk_property": {
            "type": "string",
            "description": "Edge property for exploitability score."
          },
          "edge_type": {
            "type": "string",
            "description": "Optional edge type filter."
          }
        },
        "required": [
          "entry_node",
          "asset_node"
        ]
      }
    },
    {
      "name": "graph.recommend",
      "namespace": "graph",
      "description": "Generate collaborative-filtering item recommendations for user_node over bipartite user-item interaction edges (Phase 7.5).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "user_node"
      ],
      "optional_params": [
        "item_edge_type",
        "top_k"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "user_node": {
            "type": "string",
            "description": "User/entity node ID to generate recommendations for."
          },
          "item_edge_type": {
            "type": "string",
            "description": "Optional interaction edge type filter."
          },
          "top_k": {
            "type": "integer",
            "default": 20,
            "minimum": 1,
            "maximum": 1000
          }
        },
        "required": [
          "user_node"
        ]
      }
    },
    {
      "name": "graph.text_search",
      "namespace": "graph",
      "description": "Full-text BM25 / keyword search over graph nodes (zero embeddings or LLM required).  Returns policy-filtered matching nodes ranked by relevance score.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "q"
      ],
      "optional_params": [
        "k",
        "label"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "q": {
            "type": "string",
            "description": "Search query string or node ID."
          },
          "k": {
            "type": "integer",
            "default": 10,
            "minimum": 1,
            "maximum": 100,
            "description": "Max results to return. Default 10."
          },
          "label": {
            "type": "string",
            "description": "Optional node label filter."
          }
        },
        "required": [
          "q"
        ]
      }
    },
    {
      "name": "graph.explain_query",
      "namespace": "graph",
      "description": "Return the Cost-Based Query Planner execution plan and selected strategy (PROPERTY_INDEX_SCAN, LABEL_INDEX_SCAN, VECTOR_SEARCH, TRAVERSAL, FULL_SCAN, HYBRID) for a Cypher query without executing it.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "cypher"
      ],
      "optional_params": [
        "parameters"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "cypher": {
            "type": "string",
            "description": "Cypher query to explain."
          },
          "parameters": {
            "type": "object",
            "description": "Optional query parameters."
          }
        },
        "required": [
          "cypher"
        ]
      }
    },
    {
      "name": "graph.edges_count",
      "namespace": "graph",
      "description": "Return the total number of edges in the graph (the edge counterpart to graph.counts).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    },
    {
      "name": "graph.add_nodes_bulk",
      "namespace": "graph",
      "description": "Batch-insert up to 1,000 nodes in a single WAL-batched transaction (20x faster than individual graph.add_node calls).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "nodes"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "nodes": {
            "type": "array",
            "maxItems": 1000,
            "items": {
              "type": "object",
              "properties": {
                "node_id": {
                  "type": "string"
                },
                "node_type": {
                  "type": "string",
                  "description": "Primary node label."
                },
                "labels": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "properties": {
                  "type": "object"
                }
              },
              "required": [
                "node_id"
              ]
            }
          }
        },
        "required": [
          "nodes"
        ]
      }
    },
    {
      "name": "graph.add_edges_bulk",
      "namespace": "graph",
      "description": "Batch-insert up to 1,000 directed edges in a single WAL + Rayon batch (23.5x faster than individual graph.add_edge calls).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "edges"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "edges": {
            "type": "array",
            "maxItems": 1000,
            "items": {
              "type": "object",
              "properties": {
                "edge_id": {
                  "type": "string"
                },
                "edge_type": {
                  "type": "string"
                },
                "source_id": {
                  "type": "string"
                },
                "target_id": {
                  "type": "string"
                },
                "weight": {
                  "type": "number",
                  "default": 1.0
                },
                "properties": {
                  "type": "object"
                }
              },
              "required": [
                "edge_id",
                "edge_type",
                "source_id",
                "target_id"
              ]
            }
          }
        },
        "required": [
          "edges"
        ]
      }
    },
    {
      "name": "graph.counts",
      "namespace": "graph",
      "description": "Return the total number of nodes in the graph, optionally filtered by label.  A cheap situational-awareness call an agent can make before deciding how to query or ingest.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [
        "label"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "label": {
            "type": "string",
            "description": "Count only nodes with this label.  Omit for all nodes."
          }
        },
        "required": []
      }
    },
    {
      "name": "graph.labels",
      "namespace": "graph",
      "description": "List every node type (label) in the graph with how many nodes carry it, largest first.  Cheap \u2014 O(types), not O(nodes).  Call this first to learn what the graph contains (e.g. Person, Account, Invoice) before querying or filtering by label.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    },
    {
      "name": "schema.get",
      "namespace": "schema",
      "description": "Return the full graph schema snapshot for the current tenant \u2014 all node-type and edge-type definitions plus constraints and version.  Call this first to discover the data model before querying or ingesting.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    },
    {
      "name": "schema.validate",
      "namespace": "schema",
      "description": "Validate the tenant's live graph data against the defined schema.  Reports missing required properties, type/enum violations, edge source/target-type violations, and orphan labels (labels present in the graph but undefined in the schema).  Returns valid=true with empty violation lists when the graph conforms.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    },
    {
      "name": "schema.list_node_types",
      "namespace": "schema",
      "description": "List every defined node type for the current tenant.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    },
    {
      "name": "schema.get_node_type",
      "namespace": "schema",
      "description": "Fetch a single node-type definition by its type_name.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "type_name"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "type_name": {
            "type": "string",
            "description": "The node type's canonical name/label."
          }
        },
        "required": [
          "type_name"
        ]
      }
    },
    {
      "name": "schema.define_node_type",
      "namespace": "schema",
      "description": "Define a new node type \u2014 the primitive that lets an agent build the data model itself.  The type_name becomes the canonical label for nodes of this type.  Set app_id to make the type a per-app IAM boundary (only matching API keys may touch its nodes).  Declare properties with per-field type / required / enum constraints, and immutable_properties that cannot change after creation.  Fails 409 if the type already exists (use schema.update_node_type to change).",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "type_name"
      ],
      "optional_params": [
        "description",
        "app_id",
        "data_classification",
        "properties",
        "required_labels",
        "immutable_properties",
        "allowed_edge_types"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "type_name": {
            "type": "string",
            "description": "Canonical node label (1\u2013100 chars)."
          },
          "description": {
            "type": "string",
            "description": "Human-readable description of the type."
          },
          "app_id": {
            "type": "string",
            "description": "Owning application ID \u2014 makes this type an app-level IAM boundary.  Omit for tenant-wide types."
          },
          "data_classification": {
            "type": "string",
            "description": "public | internal | restricted | highly_restricted.  Default internal.",
            "default": "internal"
          },
          "properties": {
            "type": "object",
            "description": "Map of property name \u2192 definition.  Each definition may set: type (string|str|integer|int|float|number|boolean|bool|datetime|list|array|dict|object), required (bool), description, enum (list of allowed values), default, indexed (bool).",
            "additionalProperties": {
              "type": "object"
            }
          },
          "required_labels": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Additional labels every node of this type must carry."
          },
          "immutable_properties": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Properties that cannot be modified after node creation."
          },
          "allowed_edge_types": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Outgoing edge types this node type may participate in.  Omit for unrestricted."
          }
        },
        "required": [
          "type_name"
        ]
      }
    },
    {
      "name": "schema.update_node_type",
      "namespace": "schema",
      "description": "Update an existing node-type definition (full replace).  The type_name must match an existing type.  Does not migrate existing nodes \u2014 only the schema entry changes.  Fails 404 if the type is not defined.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "type_name"
      ],
      "optional_params": [
        "description",
        "app_id",
        "data_classification",
        "properties",
        "required_labels",
        "immutable_properties",
        "allowed_edge_types"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "type_name": {
            "type": "string",
            "description": "Canonical node label \u2014 must match an existing type."
          },
          "description": {
            "type": "string"
          },
          "app_id": {
            "type": "string"
          },
          "data_classification": {
            "type": "string",
            "description": "public | internal | restricted | highly_restricted."
          },
          "properties": {
            "type": "object",
            "description": "Map of property name \u2192 definition.  Each definition may set: type (string|str|integer|int|float|number|boolean|bool|datetime|list|array|dict|object), required (bool), description, enum (list of allowed values), default, indexed (bool).",
            "additionalProperties": {
              "type": "object"
            }
          },
          "required_labels": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "immutable_properties": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "allowed_edge_types": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "type_name"
        ]
      }
    },
    {
      "name": "schema.delete_node_type",
      "namespace": "schema",
      "description": "Remove a node-type definition.  Does NOT delete existing nodes \u2014 it only removes the schema entry, so nodes of this type become orphan-labelled until redefined.  \u26a0 human_only \u2014 agents are blocked; a human operator must perform this action directly.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "type_name"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "type_name": {
            "type": "string",
            "description": "The node type to remove."
          }
        },
        "required": [
          "type_name"
        ]
      }
    },
    {
      "name": "schema.list_edge_types",
      "namespace": "schema",
      "description": "List every defined edge type for the current tenant.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    },
    {
      "name": "schema.get_edge_type",
      "namespace": "schema",
      "description": "Fetch a single edge-type definition by its type_name.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "type_name"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "type_name": {
            "type": "string",
            "description": "The edge type's canonical name."
          }
        },
        "required": [
          "type_name"
        ]
      }
    },
    {
      "name": "schema.define_edge_type",
      "namespace": "schema",
      "description": "Define a new edge (relationship) type.  Constrain which node types may be the source/target, declare edge properties, and set cardinality (one_to_one | one_to_many | many_to_one | many_to_many).  Fails 409 if the type already exists.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "type_name"
      ],
      "optional_params": [
        "description",
        "app_id",
        "source_node_types",
        "target_node_types",
        "properties",
        "cardinality",
        "data_classification"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "type_name": {
            "type": "string",
            "description": "Canonical edge type name (1\u2013100 chars)."
          },
          "description": {
            "type": "string"
          },
          "app_id": {
            "type": "string"
          },
          "source_node_types": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Allowed source node types.  Omit for any."
          },
          "target_node_types": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Allowed target node types.  Omit for any."
          },
          "properties": {
            "type": "object",
            "description": "Map of property name \u2192 definition.  Each definition may set: type (string|str|integer|int|float|number|boolean|bool|datetime|list|array|dict|object), required (bool), description, enum (list of allowed values), default, indexed (bool).",
            "additionalProperties": {
              "type": "object"
            }
          },
          "cardinality": {
            "type": "string",
            "description": "one_to_one | one_to_many | many_to_one | many_to_many.  Default many_to_many.",
            "default": "many_to_many"
          },
          "data_classification": {
            "type": "string",
            "description": "public | internal | restricted | highly_restricted.  Default internal.",
            "default": "internal"
          }
        },
        "required": [
          "type_name"
        ]
      }
    },
    {
      "name": "schema.update_edge_type",
      "namespace": "schema",
      "description": "Update an existing edge-type definition (full replace).  The type_name must match an existing type.  Fails 404 if not defined.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "type_name"
      ],
      "optional_params": [
        "description",
        "app_id",
        "source_node_types",
        "target_node_types",
        "properties",
        "cardinality",
        "data_classification"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "type_name": {
            "type": "string",
            "description": "Canonical edge type name \u2014 must match an existing type."
          },
          "description": {
            "type": "string"
          },
          "app_id": {
            "type": "string"
          },
          "source_node_types": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "target_node_types": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "properties": {
            "type": "object",
            "description": "Map of property name \u2192 definition.  Each definition may set: type (string|str|integer|int|float|number|boolean|bool|datetime|list|array|dict|object), required (bool), description, enum (list of allowed values), default, indexed (bool).",
            "additionalProperties": {
              "type": "object"
            }
          },
          "cardinality": {
            "type": "string",
            "description": "one_to_one | one_to_many | many_to_one | many_to_many."
          },
          "data_classification": {
            "type": "string",
            "description": "public | internal | restricted | highly_restricted."
          }
        },
        "required": [
          "type_name"
        ]
      }
    },
    {
      "name": "schema.delete_edge_type",
      "namespace": "schema",
      "description": "Remove an edge-type definition.  Does NOT delete existing edges \u2014 only the schema entry is removed.  \u26a0 human_only \u2014 agents are blocked; a human operator must perform this action directly.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "type_name"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "type_name": {
            "type": "string",
            "description": "The edge type to remove."
          }
        },
        "required": [
          "type_name"
        ]
      }
    },
    {
      "name": "data.list_files",
      "namespace": "data",
      "description": "List stored files in the current tenant's File Library with pagination.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [
        "limit",
        "offset"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "limit": {
            "type": "integer",
            "default": 50,
            "minimum": 1,
            "maximum": 200
          },
          "offset": {
            "type": "integer",
            "default": 0,
            "minimum": 0
          }
        },
        "required": []
      }
    },
    {
      "name": "memory.history",
      "namespace": "memory",
      "description": "Retrieve the ordered message history for a session.  Use last_n to reconstruct the LLM context window on session resume.  Returns list of {seq, role, content, timestamp} dicts in ascending order.  Requires viewer role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "session_id"
      ],
      "optional_params": [
        "last_n"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "session_id": {
            "type": "string",
            "description": "Session ID to retrieve history for."
          },
          "last_n": {
            "type": "integer",
            "description": "Return only the last N turns.  Omit for full history.",
            "minimum": 1
          }
        },
        "required": [
          "session_id"
        ]
      }
    },
    {
      "name": "memory.search",
      "namespace": "memory",
      "description": "Semantic search across closed session summaries using vector similarity.  Returns the k most relevant past sessions for a given query.  Optionally filter by entity_id to scope to one user or agent.  This is the long-term memory recall path \u2014 query embeddings are compared against ChatSessionSummary nodes only (one per closed session).  Requires viewer role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "query"
      ],
      "optional_params": [
        "entity_id",
        "k"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string",
            "description": "Natural-language query to find relevant past sessions."
          },
          "entity_id": {
            "type": "string",
            "description": "Scope search to sessions belonging to this entity.  Omit for global search."
          },
          "k": {
            "type": "integer",
            "description": "Number of results to return.  Default 5.",
            "default": 5,
            "minimum": 1
          }
        },
        "required": [
          "query"
        ]
      }
    },
    {
      "name": "scheduler.add_trigger",
      "namespace": "scheduler",
      "description": "Register a temporal or event-driven trigger that fires an action.  Trigger types: 'interval' (every N seconds), 'cron' (5-field cron: 'm h dom mon dow'), or 'event' (a CDC event, optionally crossing a numeric threshold \u2014 this is how drift-crossing automations are built).  Action types: 'webhook' (HMAC-signed POST), 'emit_event' (chain a new CDC event onto the bus), or 'callback' (a named in-process handler such as starting/advancing a journey).  This is the time+condition entry point \u2014 no external scheduler needed.  Requires admin role.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "trigger_id",
        "trigger_type",
        "action_type"
      ],
      "optional_params": [
        "interval_seconds",
        "cron",
        "event_type",
        "condition",
        "tenant_id",
        "webhook_url",
        "signing_secret",
        "emit_event_type",
        "callback_name",
        "payload",
        "enabled"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "trigger_id": {
            "type": "string",
            "description": "Unique, URL-safe identifier."
          },
          "trigger_type": {
            "type": "string",
            "enum": [
              "interval",
              "cron",
              "event"
            ],
            "description": "When the trigger fires."
          },
          "action_type": {
            "type": "string",
            "enum": [
              "webhook",
              "emit_event",
              "callback"
            ],
            "description": "What happens when it fires."
          },
          "interval_seconds": {
            "type": "number",
            "description": "For trigger_type='interval': fire every N seconds.",
            "minimum": 0.001
          },
          "cron": {
            "type": "string",
            "description": "For trigger_type='cron': 5-field cron expression."
          },
          "event_type": {
            "type": "string",
            "description": "For trigger_type='event': CDC event type to match (e.g. 'node_added', 'feedback_recorded')."
          },
          "condition": {
            "type": "object",
            "description": "For event triggers: {field, op, value}, e.g. {'field':'data.drift','op':'ge','value':0.7}."
          },
          "tenant_id": {
            "type": "string",
            "description": "Restrict event triggers to one tenant.  Omit for all."
          },
          "webhook_url": {
            "type": "string",
            "description": "For action_type='webhook': destination URL."
          },
          "signing_secret": {
            "type": "string",
            "description": "For webhook: HMAC-SHA256 secret (X-Purple8-Signature)."
          },
          "emit_event_type": {
            "type": "string",
            "description": "For action_type='emit_event': CDC event type to publish."
          },
          "callback_name": {
            "type": "string",
            "description": "For action_type='callback': registered handler name."
          },
          "payload": {
            "type": "object",
            "description": "Static payload merged into the action body."
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the trigger is active.  Default true.",
            "default": true
          }
        },
        "required": [
          "trigger_id",
          "trigger_type",
          "action_type"
        ]
      }
    },
    {
      "name": "scheduler.list_triggers",
      "namespace": "scheduler",
      "description": "List all registered trigger ids on the scheduler.  Requires admin role.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {}
      }
    },
    {
      "name": "scheduler.remove_trigger",
      "namespace": "scheduler",
      "description": "Unregister a trigger by id.  Idempotent.  Requires admin role.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "trigger_id"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "trigger_id": {
            "type": "string",
            "description": "The trigger id to remove."
          }
        },
        "required": [
          "trigger_id"
        ]
      }
    },
    {
      "name": "scheduler.status",
      "namespace": "scheduler",
      "description": "Return scheduler running state, all trigger specs, and fire/error counters.  Use to verify automations are live.  Requires admin role.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {}
      }
    },
    {
      "name": "egress.add_sink",
      "namespace": "egress",
      "description": "Register an outbound webhook sink that delivers graph change events (nodes/edges/journeys) to an external system as HMAC-signed JSON.  The mirror image of inbound connectors \u2014 this is how Purple8 pushes changes out to downstream systems in real time.  Optionally filter by event types and tenant, and reshape the payload with field mappings.  Requires admin role.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "sink_id",
        "url"
      ],
      "optional_params": [
        "signing_secret",
        "event_types",
        "tenant_id",
        "headers"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "sink_id": {
            "type": "string",
            "description": "Unique, URL-safe identifier."
          },
          "url": {
            "type": "string",
            "description": "Destination HTTP(S) endpoint."
          },
          "signing_secret": {
            "type": "string",
            "description": "HMAC-SHA256 secret (X-Purple8-Signature). Empty disables signing."
          },
          "event_types": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Only deliver these CDC event types (e.g. 'node_added', 'node_updated', 'edge_added', 'journey_started', 'stage_advanced', 'journey_completed', 'sla_breached', 'hitl_created', 'hitl_completed', 'feedback_recorded').  Omit for all."
          },
          "tenant_id": {
            "type": "string",
            "description": "Only deliver this tenant's events.  Omit for all."
          },
          "headers": {
            "type": "object",
            "description": "Extra static headers (e.g. Authorization)."
          }
        },
        "required": [
          "sink_id",
          "url"
        ]
      }
    },
    {
      "name": "egress.list_sinks",
      "namespace": "egress",
      "description": "List all registered outbound sink ids.  Requires admin role.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {}
      }
    },
    {
      "name": "egress.remove_sink",
      "namespace": "egress",
      "description": "Unregister an outbound sink by id.  Idempotent.  Requires admin role.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "sink_id"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "sink_id": {
            "type": "string",
            "description": "The sink id to remove."
          }
        },
        "required": [
          "sink_id"
        ]
      }
    },
    {
      "name": "egress.status",
      "namespace": "egress",
      "description": "Return egress manager state, registered sinks, and delivery counters (delivered / failed / in-flight).  Requires admin role.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {}
      }
    },
    {
      "name": "feedback.record",
      "namespace": "feedback",
      "description": "Record human or agent feedback about any graph entity \u2014 a RAG answer, a retrieved node, an inferred edge, or a journey.  Stored as an immutable graph record that flows through CDC (so egress sinks and scheduler drift-triggers can react) and feeds learning loops.  Give a rating, a label ('correct'/'incorrect'), a free-text comment, or a suggested correction.  Requires editor role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "target_id"
      ],
      "optional_params": [
        "target_kind",
        "kind",
        "rating",
        "label",
        "comment",
        "correction",
        "source",
        "context",
        "link_to_target"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "target_id": {
            "type": "string",
            "description": "Entity the feedback is about (node/edge/journey/answer id)."
          },
          "target_kind": {
            "type": "string",
            "description": "answer | node | edge | journey | ...  Default 'answer'.",
            "default": "answer"
          },
          "kind": {
            "type": "string",
            "enum": [
              "rating",
              "label",
              "correction",
              "comment"
            ],
            "description": "Kind of judgement.  Default 'rating'.",
            "default": "rating"
          },
          "rating": {
            "type": "number",
            "description": "Numeric score (e.g. 1\u20135 or 0/1 thumbs)."
          },
          "label": {
            "type": "string",
            "description": "Categorical label, e.g. 'correct'/'incorrect'."
          },
          "comment": {
            "type": "string",
            "description": "Free-text feedback."
          },
          "correction": {
            "type": "string",
            "description": "Suggested replacement / fix."
          },
          "source": {
            "type": "string",
            "enum": [
              "human",
              "agent",
              "system"
            ],
            "description": "Who gave the feedback.  Default 'human'.",
            "default": "human"
          },
          "context": {
            "type": "object",
            "description": "Extra context (question text, model, etc.)."
          },
          "link_to_target": {
            "type": "boolean",
            "description": "Also create a FEEDBACK_ON edge to the target node.  Default true.",
            "default": true
          }
        },
        "required": [
          "target_id"
        ]
      }
    },
    {
      "name": "feedback.open",
      "namespace": "feedback",
      "description": "List unresolved feedback items for this tenant (newest first).  The agent's work queue for acting on ground-truth signal.  Requires viewer role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [
        "limit"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "limit": {
            "type": "integer",
            "description": "Max items to return.  Default 100.",
            "default": 100,
            "minimum": 1
          }
        }
      }
    },
    {
      "name": "feedback.summary",
      "namespace": "feedback",
      "description": "Aggregate feedback signal for this tenant: total/resolved counts, mean rating, and label + kind tallies.  Use to gauge answer quality drift over time.  Requires viewer role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {}
      }
    },
    {
      "name": "feedback.resolve",
      "namespace": "feedback",
      "description": "Mark a feedback item as handled, recording how it was addressed (mirrors HITL resolution).  Emits a feedback_resolved CDC event.  Requires editor role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "feedback_id",
        "resolution"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "feedback_id": {
            "type": "string",
            "description": "The feedback id to resolve."
          },
          "resolution": {
            "type": "string",
            "description": "How the feedback was addressed."
          }
        },
        "required": [
          "feedback_id",
          "resolution"
        ]
      }
    },
    {
      "name": "registry.register_tool",
      "namespace": "registry",
      "description": "Federate an EXTERNAL tool into this Purple8 gateway so every agent can call it alongside the built-in tools \u2014 Jira, a database HTTP API, Slack, a model endpoint, anything with an HTTP interface.  Purple8 holds the credential (envelope-encrypted) and proxies the call; the agent never sees the secret.  Give a namespaced name (e.g. 'jira.create_issue'), the transport ('rest' or 'mcp'), the base_url (SSRF-guarded), an optional credential and JSON input_schema, and the roles allowed to call it.  This is how the AI agent installs new capabilities for other agents.  Requires admin role.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "name",
        "base_url"
      ],
      "optional_params": [
        "transport",
        "description",
        "method",
        "credential",
        "input_schema",
        "static_headers",
        "required_roles",
        "timeout_s",
        "allow_insecure"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Namespaced tool name, e.g. 'jira.create_issue'."
          },
          "transport": {
            "type": "string",
            "enum": [
              "rest",
              "mcp",
              "a2a"
            ],
            "description": "How to reach the tool: rest, mcp (downstream MCP server) or a2a (peer agent's A2A JSON-RPC URL).  Default 'rest'.",
            "default": "rest"
          },
          "base_url": {
            "type": "string",
            "description": "External https endpoint (passes the SSRF guard)."
          },
          "description": {
            "type": "string",
            "description": "Human/agent-readable description of what the tool does."
          },
          "method": {
            "type": "string",
            "description": "HTTP method for rest transport.  Default 'POST'.",
            "default": "POST"
          },
          "credential": {
            "type": "object",
            "description": "{auth_type: none|bearer|api_key_header|basic, header_name, username, secret}.  Secret is encrypted at rest."
          },
          "input_schema": {
            "type": "object",
            "description": "JSON Schema for the tool's arguments (advertised to agents)."
          },
          "static_headers": {
            "type": "object",
            "description": "Extra static headers sent on every call."
          },
          "required_roles": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Roles allowed to invoke.  Default editor+admin+super_admin."
          },
          "timeout_s": {
            "type": "number",
            "description": "Per-call timeout seconds.  Default 20.",
            "default": 20
          },
          "allow_insecure": {
            "type": "boolean",
            "description": "Permit http:// (dev only).  Default false.",
            "default": false
          }
        },
        "required": [
          "name",
          "base_url"
        ]
      }
    },
    {
      "name": "registry.register_mcp_server",
      "namespace": "registry",
      "description": "Federate a whole downstream MCP server (any Model / IDE / Bedrock / vendor MCP endpoint that speaks JSON-RPC 2.0).  Purple8 calls tools/list on it and registers EVERY advertised tool under '{prefix}.{tool}', so a single call imports an entire external toolbelt.  This is how any model or IDE 'registers itself' into the gateway.  Requires admin role.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "prefix",
        "base_url"
      ],
      "optional_params": [
        "credential",
        "static_headers",
        "required_roles",
        "timeout_s",
        "allow_insecure"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "prefix": {
            "type": "string",
            "description": "Namespace prefix for the imported tools, e.g. 'bedrock'."
          },
          "base_url": {
            "type": "string",
            "description": "Downstream MCP server HTTP endpoint (SSRF-guarded)."
          },
          "credential": {
            "type": "object",
            "description": "Optional auth for the downstream server."
          },
          "static_headers": {
            "type": "object",
            "description": "Extra static headers."
          },
          "required_roles": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Roles allowed to invoke the imported tools."
          },
          "timeout_s": {
            "type": "number",
            "description": "Per-call timeout seconds.  Default 20.",
            "default": 20
          },
          "allow_insecure": {
            "type": "boolean",
            "description": "Permit http:// (dev only).  Default false.",
            "default": false
          }
        },
        "required": [
          "prefix",
          "base_url"
        ]
      }
    },
    {
      "name": "registry.register_a2a_agent",
      "namespace": "registry",
      "description": "Federate a peer AI agent that speaks the A2A (Agent2Agent) protocol.  Purple8 fetches its Agent Card and registers one tool per advertised skill as '{prefix}.{skill_id}'.  Calling such a tool delegates a task to the remote agent (args: message, optional data / skill / arguments / task_id / context_id) and returns {state, text, artifacts, task_id}.  Requires admin role.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "prefix",
        "card_url"
      ],
      "optional_params": [
        "credential",
        "static_headers",
        "required_roles",
        "timeout_s",
        "allow_insecure"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "prefix": {
            "type": "string",
            "description": "Namespace prefix for the agent's skills, e.g. 'billing_agent'."
          },
          "card_url": {
            "type": "string",
            "description": "Agent Card URL or the agent's base URL (SSRF-guarded)."
          },
          "credential": {
            "type": "object",
            "description": "Optional auth for the peer: {auth_type: none|bearer|api_key_header|basic, header_name, username, secret}."
          },
          "static_headers": {
            "type": "object",
            "description": "Extra static headers."
          },
          "required_roles": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Roles allowed to invoke the imported skills."
          },
          "timeout_s": {
            "type": "number",
            "description": "Max seconds to wait for a remote task.  Default 60.",
            "default": 60
          },
          "allow_insecure": {
            "type": "boolean",
            "description": "Permit http:// (dev only).  Default false.",
            "default": false
          }
        },
        "required": [
          "prefix",
          "card_url"
        ]
      }
    },
    {
      "name": "sentinel.list_findings",
      "namespace": "sentinel",
      "description": "List Sentinel findings \u2014 data drift, SOC threshold proposals, emerging threats \u2014 most severe first.  Each finding carries evidence, a DecisionGate trace and a proposed change awaiting HUMAN approval.  Agents cannot approve; surface open findings to the operator.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [
        "status",
        "source",
        "min_severity",
        "limit"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "open",
              "approved",
              "rejected",
              "applied",
              "apply_failed"
            ]
          },
          "source": {
            "type": "string",
            "description": "Prefix filter, e.g. 'drift' or 'soc'."
          },
          "min_severity": {
            "type": "string",
            "enum": [
              "low",
              "medium",
              "high",
              "critical"
            ]
          },
          "limit": {
            "type": "integer",
            "default": 50
          }
        }
      }
    },
    {
      "name": "sentinel.get_finding",
      "namespace": "sentinel",
      "description": "Fetch one Sentinel finding with full evidence, gate trace and proposal.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "finding_id"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "finding_id": {
            "type": "string"
          }
        },
        "required": [
          "finding_id"
        ]
      }
    },
    {
      "name": "sentinel.summary",
      "namespace": "sentinel",
      "description": "Counts of Sentinel findings by status, source and severity.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {}
      }
    },
    {
      "name": "sentinel.reject",
      "namespace": "sentinel",
      "description": "Dismiss an open Sentinel finding as noise, with a note.  (Approval is human-only and not available to agents.)",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "finding_id"
      ],
      "optional_params": [
        "note"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "finding_id": {
            "type": "string"
          },
          "note": {
            "type": "string"
          }
        },
        "required": [
          "finding_id"
        ]
      }
    },
    {
      "name": "sentinel.drift_check",
      "namespace": "sentinel",
      "description": "Compare current data against a stored baseline.  kind=distribution (values, PSI), embeddings (vectors, centroid shift) or quality (score, e.g. RAG F1).  Significant drift opens a finding for human review.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "kind",
        "name"
      ],
      "optional_params": [
        "values",
        "vectors",
        "score"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "distribution",
              "embeddings",
              "quality"
            ]
          },
          "name": {
            "type": "string"
          },
          "values": {
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "vectors": {
            "type": "array",
            "items": {
              "type": "array",
              "items": {
                "type": "number"
              }
            }
          },
          "score": {
            "type": "number"
          }
        },
        "required": [
          "kind",
          "name"
        ]
      }
    },
    {
      "name": "evolution.routing_policy",
      "namespace": "evolution",
      "description": "Internal intelligence: evolve the tenant's model-routing policy against observed outcomes ({profile: TaskProfile fields, tier: small|default|flagship, success: bool}, \u226510).  Optimises quality \u2212 cost_weight\u00d7cost.  Never applies: an improvement opens a Sentinel finding a human must approve.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "outcomes"
      ],
      "optional_params": [
        "cost_weight",
        "generations",
        "min_gain"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "outcomes": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "cost_weight": {
            "type": "number",
            "default": 0.3
          },
          "generations": {
            "type": "integer",
            "default": 25
          },
          "min_gain": {
            "type": "number",
            "default": 0.02
          }
        },
        "required": [
          "outcomes"
        ]
      }
    },
    {
      "name": "evolution.rag_retrieval",
      "namespace": "evolution",
      "description": "Internal intelligence: evolve hybrid-RAG retrieval params (fusion_alpha, max_hops, seed_k) against an eval set of question/expected_answer pairs (token-F1 on retrieved context).  An improvement opens a Sentinel finding; on human approval it is saved as collection profile profile_name.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "eval_set",
        "profile_name"
      ],
      "optional_params": [
        "label_filter",
        "generations"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "eval_set": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "question": {
                  "type": "string"
                },
                "expected_answer": {
                  "type": "string"
                }
              }
            }
          },
          "profile_name": {
            "type": "string"
          },
          "label_filter": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "generations": {
            "type": "integer",
            "default": 6
          }
        },
        "required": [
          "eval_set",
          "profile_name"
        ]
      }
    },
    {
      "name": "evolution.create_experiment",
      "namespace": "evolution",
      "description": "External intelligence: create an online experiment that evolves any parameters of your application from reported outcomes.  genes: list of {name, gene_type: float|int|bool, lo, hi, default} \u2014 defaults are today's production config.  Then loop evolution.suggest \u2192 use config \u2192 evolution.report.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "name",
        "genes"
      ],
      "optional_params": [
        "description",
        "maximize",
        "population_size",
        "min_trials"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "genes": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "description": {
            "type": "string"
          },
          "maximize": {
            "type": "boolean",
            "default": true
          },
          "population_size": {
            "type": "integer",
            "default": 8
          },
          "min_trials": {
            "type": "integer",
            "default": 5
          }
        },
        "required": [
          "name",
          "genes"
        ]
      }
    },
    {
      "name": "evolution.list_experiments",
      "namespace": "evolution",
      "description": "List the tenant's evolution experiments with generation, best and production scores.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {}
      }
    },
    {
      "name": "evolution.suggest",
      "namespace": "evolution",
      "description": "Get the next candidate config (genome_id + config) to try in an experiment.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "name"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          }
        },
        "required": [
          "name"
        ]
      }
    },
    {
      "name": "evolution.report",
      "namespace": "evolution",
      "description": "Report the observed score for a candidate returned by evolution.suggest.  When every candidate has min_trials reports, the next generation is bred.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "name",
        "genome_id",
        "score"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "genome_id": {
            "type": "string"
          },
          "score": {
            "type": "number"
          }
        },
        "required": [
          "name",
          "genome_id",
          "score"
        ]
      }
    },
    {
      "name": "evolution.production",
      "namespace": "evolution",
      "description": "The human-approved production config of an experiment \u2014 serve this outside the experiment.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "name"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          }
        },
        "required": [
          "name"
        ]
      }
    },
    {
      "name": "evolution.propose",
      "namespace": "evolution",
      "description": "Open a Sentinel finding to promote an experiment's best candidate if it beats production by min_gain (relative, default 0.05).  Promotion needs human approval.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "name"
      ],
      "optional_params": [
        "min_gain"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "min_gain": {
            "type": "number"
          }
        },
        "required": [
          "name"
        ]
      }
    },
    {
      "name": "registry.list_tools",
      "namespace": "registry",
      "description": "List the externally-federated tools registered on this gateway for the current tenant (credentials redacted).  Requires viewer role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {}
      }
    },
    {
      "name": "registry.remove_tool",
      "namespace": "registry",
      "description": "Deregister a federated tool by name.  Idempotent.  Requires admin role.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "name"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The federated tool name to remove."
          }
        },
        "required": [
          "name"
        ]
      }
    },
    {
      "name": "registry.test_tool",
      "namespace": "registry",
      "description": "Dry-run invoke a federated tool to validate connectivity and credentials before relying on it.  Returns the downstream response.  Requires admin role.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "name"
      ],
      "optional_params": [
        "arguments"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The federated tool name to test."
          },
          "arguments": {
            "type": "object",
            "description": "Arguments to send in the dry-run call."
          }
        },
        "required": [
          "name"
        ]
      }
    },
    {
      "name": "models.list",
      "namespace": "models",
      "description": "List the models the router may use for this tenant: built-in baseline overlaid by tenant-defined entries (source, tier, provider, context, cost, strengths, enabled).  Requires viewer role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {}
      }
    },
    {
      "name": "models.search_known",
      "namespace": "models",
      "description": "Search the public registry of 4,000+ known LLMs (context window, per-token cost, vision support) to find a model name to add.  Requires viewer role.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [
        "query",
        "provider",
        "limit"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string",
            "description": "Substring of the model name, e.g. 'claude' or 'gpt-5'."
          },
          "provider": {
            "type": "string",
            "description": "Optional provider filter, e.g. 'openai', 'anthropic'."
          },
          "limit": {
            "type": "integer",
            "description": "Max results (default 25)."
          }
        }
      }
    },
    {
      "name": "models.upsert",
      "namespace": "models",
      "description": "Add or replace a model in this tenant's catalogue.  Only 'model' is required; provider, tier, context_tokens, vision and cost are auto-filled from the known-model registry.  Set enabled=false to hide a built-in model.  Takes effect on the next request.  Requires admin role.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "model"
      ],
      "optional_params": [
        "provider",
        "tier",
        "context_tokens",
        "vision",
        "local",
        "strengths",
        "cost_in_per_mtok",
        "cost_out_per_mtok",
        "enabled",
        "notes"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "model": {
            "type": "string",
            "description": "Model name as the provider expects it."
          },
          "provider": {
            "type": "string"
          },
          "tier": {
            "type": "string",
            "enum": [
              "small",
              "default",
              "flagship"
            ]
          },
          "context_tokens": {
            "type": "integer"
          },
          "vision": {
            "type": "boolean"
          },
          "local": {
            "type": "boolean"
          },
          "strengths": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Task types this model is preferred for (e.g. extract, reason, code)."
          },
          "cost_in_per_mtok": {
            "type": "number"
          },
          "cost_out_per_mtok": {
            "type": "number"
          },
          "enabled": {
            "type": "boolean"
          },
          "notes": {
            "type": "string"
          }
        },
        "required": [
          "model"
        ]
      }
    },
    {
      "name": "models.remove",
      "namespace": "models",
      "description": "Remove a tenant-defined model entry.  If it overrode a built-in, the built-in reappears.  Requires admin role.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "model"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "model": {
            "type": "string"
          }
        },
        "required": [
          "model"
        ]
      }
    },
    {
      "name": "models.get_policy",
      "namespace": "models",
      "description": "Return this tenant's model-routing policy (signal weights, vetoes, hard tasks).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {}
      }
    },
    {
      "name": "models.set_policy",
      "namespace": "models",
      "description": "Replace the model-routing policy.  'policy' is a partial dict merged over defaults (weights, weight_thresholds, veto_signals, veto_thresholds, hard_tasks, base_score, conflict_band).  include_builtin=false routes only over tenant-defined models.  Requires admin role.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [
        "policy",
        "include_builtin"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "policy": {
            "type": "object"
          },
          "include_builtin": {
            "type": "boolean"
          }
        }
      }
    },
    {
      "name": "models.route_explain",
      "namespace": "models",
      "description": "Dry-run the model router: given a task description, return the chosen model, tier, fallback chain and the full decision trace.  No LLM call is made.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [
        "task_type",
        "input_tokens",
        "needs_vision",
        "needs_strict_json",
        "tool_count",
        "contains_pii",
        "require_local",
        "prior_failure_rate",
        "high_stakes",
        "provider"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "task_type": {
            "type": "string",
            "description": "classify, extract, summarise, generate, reason, code, rag_answer, agent_step."
          },
          "input_tokens": {
            "type": "integer"
          },
          "needs_vision": {
            "type": "boolean"
          },
          "needs_strict_json": {
            "type": "boolean"
          },
          "tool_count": {
            "type": "integer"
          },
          "contains_pii": {
            "type": "boolean"
          },
          "require_local": {
            "type": "boolean"
          },
          "prior_failure_rate": {
            "type": "number"
          },
          "high_stakes": {
            "type": "boolean"
          },
          "provider": {
            "type": "string"
          }
        }
      }
    },
    {
      "name": "guardrails.evaluate",
      "namespace": "guardrails",
      "description": "Run Purple8 AI guardrail checks on a text payload before writing it to the graph or passing it to an LLM.  Checks for prompt injection, scope escape, PII, token bombing, credential leaks (input); schema violations, credential leaks, and toxic content (output); and agent loop / cost runaway (structural).  Returns a GuardrailResult with passed, blocked, and a list of violations \u2014 each with guard name, severity (warn/flag/block), message, and evidence snippet.  REQUIRED: text (the payload to scan), check_type ('input'|'output'|'structural'). OPTIONAL: source_context (for hallucination probe), expected_schema (JSON Schema object for schema-violation check), call_stack (list of tool names for loop detection), total_tokens / retry_count / elapsed_s (for cost runaway). Agents SHOULD call this before data.ingest_text / data.ingest_file to catch prompt injection and credential leaks in user-supplied documents.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "text",
        "check_type"
      ],
      "optional_params": [
        "source_context",
        "expected_schema",
        "call_stack",
        "total_tokens",
        "retry_count",
        "elapsed_s"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string",
            "description": "Text payload to evaluate."
          },
          "check_type": {
            "type": "string",
            "enum": [
              "input",
              "output",
              "structural"
            ],
            "description": "Which layer to evaluate."
          },
          "source_context": {
            "type": "string",
            "description": "Source context for hallucination probe (output check only)."
          },
          "expected_schema": {
            "type": "object",
            "description": "JSON Schema to validate LLM output against (output check only)."
          },
          "call_stack": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Agent call-stack for loop detection (structural check)."
          },
          "total_tokens": {
            "type": "integer",
            "description": "Cumulative tokens consumed so far (structural check)."
          },
          "retry_count": {
            "type": "integer",
            "description": "Number of retries so far (structural check)."
          },
          "elapsed_s": {
            "type": "number",
            "description": "Elapsed seconds for the pipeline run (structural check)."
          }
        },
        "required": [
          "text",
          "check_type"
        ]
      }
    },
    {
      "name": "admin.smtp_status",
      "namespace": "admin",
      "description": "Return the current outbound email (SMTP) configuration status for this Purple8 instance.  Shows whether SMTP is active, the host, port, and FROM address.  The password is never returned.  Call this first to check whether email (password-reset, user-invite) is already configured before prompting the operator for credentials.  Requires admin+.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {}
      }
    },
    {
      "name": "admin.smtp_configure",
      "namespace": "admin",
      "description": "Configure outbound SMTP for this Purple8 instance so that password-reset and user-invite emails work.  HITL REQUIRED \u2014 you MUST ask the human operator for the SMTP credentials before calling this tool.  Never invent, guess, or reuse credentials from memory.  Present a form or prompt with: SMTP host, port (default 587), username, password, and optional from_name / from_address.  Only call this tool once the operator has explicitly provided all values.\n\nSettings take effect immediately for the running process.  Remind the operator to add EMAIL__SMTP_HOST / EMAIL__SMTP_USER / EMAIL__SMTP_PASSWORD / EMAIL__SMTP_PORT to their .env or Docker environment to persist across restarts.  Requires admin+.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "host",
        "username",
        "password"
      ],
      "optional_params": [
        "port",
        "from_name",
        "from_address"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "host": {
            "type": "string",
            "description": "SMTP hostname, e.g. smtp.postmarkapp.com or smtp.gmail.com"
          },
          "port": {
            "type": "integer",
            "description": "SMTP port \u2014 587 for STARTTLS (default), 465 for SSL",
            "default": 587
          },
          "username": {
            "type": "string",
            "description": "SMTP username \u2014 usually the full FROM email address"
          },
          "password": {
            "type": "string",
            "description": "SMTP password or app-password (obtain from the operator via HITL)"
          },
          "from_name": {
            "type": "string",
            "description": "Display name for outbound emails, e.g. 'Acme Platform'",
            "default": "Purple8"
          },
          "from_address": {
            "type": "string",
            "description": "FROM address (defaults to username if omitted)"
          }
        },
        "required": [
          "host",
          "username",
          "password"
        ]
      }
    },
    {
      "name": "admin.audit_verify",
      "namespace": "admin",
      "description": "Verify this tenant's hash-chained audit trail.  Recomputes every record's hash and link to the previous record, and checks signed anchors.  Returns ok, first_broken_seq and reason (hash_mismatch, missing_or_reordered, truncated, anchor_mismatch ...).  Read-only.  Requires admin+.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [
        "from_seq",
        "to_seq"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "from_seq": {
            "type": "integer",
            "minimum": 1,
            "default": 1
          },
          "to_seq": {
            "type": "integer",
            "minimum": 1
          }
        }
      }
    },
    {
      "name": "admin.recovery_status",
      "namespace": "admin",
      "description": "Read this tenant's storage recovery readiness and persistence capabilities. Reports WAL/cold-slab persistence, native snapshot availability and historical point-in-time restore support. Checks all physical shards where applicable. This is not process liveness or proof of backup/restore qualification. Requires admin+.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {}
      }
    },
    {
      "name": "admin.retention_list",
      "namespace": "admin",
      "description": "List this tenant's retention policies (labels, retain_days, action). Read-only.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {}
      }
    },
    {
      "name": "admin.retention_set",
      "namespace": "admin",
      "description": "Create or update a retention policy: nodes matching match.labels (required) and optional classification/properties, older than retain_days, are purged, archived (soft-deleted) or anonymised by the scheduled sweeper.  Records under a legal hold are never touched.  Pass policy_id to update.  Audited.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "match",
        "retain_days",
        "action"
      ],
      "optional_params": [
        "policy_id",
        "name",
        "age_field",
        "anonymise_fields",
        "enabled"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "policy_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "match": {
            "type": "object",
            "properties": {
              "labels": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "classification": {
                "type": "string"
              },
              "properties": {
                "type": "object"
              }
            },
            "required": [
              "labels"
            ]
          },
          "retain_days": {
            "type": "number",
            "exclusiveMinimum": 0
          },
          "action": {
            "type": "string",
            "enum": [
              "purge",
              "archive",
              "anonymise"
            ]
          },
          "age_field": {
            "type": "string"
          },
          "anonymise_fields": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "enabled": {
            "type": "boolean",
            "default": true
          }
        },
        "required": [
          "match",
          "retain_days",
          "action"
        ]
      }
    },
    {
      "name": "admin.retention_delete",
      "namespace": "admin",
      "description": "Delete a retention policy by policy_id.  Audited.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "policy_id"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "policy_id": {
            "type": "string"
          }
        },
        "required": [
          "policy_id"
        ]
      }
    },
    {
      "name": "admin.retention_sweep",
      "namespace": "admin",
      "description": "Run the retention sweeper now.  dry_run=true (default) only reports what would be purged/archived/anonymised and which legal holds blocked records.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [
        "dry_run",
        "max_actions"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "dry_run": {
            "type": "boolean",
            "default": true
          },
          "max_actions": {
            "type": "integer",
            "minimum": 1,
            "maximum": 10000
          }
        }
      }
    },
    {
      "name": "admin.hold_list",
      "namespace": "admin",
      "description": "List legal holds (active only unless include_released=true). Read-only.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [
        "include_released"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "include_released": {
            "type": "boolean",
            "default": false
          }
        }
      }
    },
    {
      "name": "admin.hold_place",
      "namespace": "admin",
      "description": "Place a legal hold.  Held records cannot be purged, hard-deleted or removed by retention until the hold is released.  Give node_ids and/or match {labels, classification, properties} and a reason.  Audited.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "reason"
      ],
      "optional_params": [
        "node_ids",
        "match"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "reason": {
            "type": "string",
            "minLength": 10
          },
          "node_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "match": {
            "type": "object"
          }
        },
        "required": [
          "reason"
        ]
      }
    },
    {
      "name": "admin.hold_release",
      "namespace": "admin",
      "description": "Release a legal hold by hold_id, with a reason.  Records become eligible again.  Audited.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "hold_id",
        "reason"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "hold_id": {
            "type": "string"
          },
          "reason": {
            "type": "string",
            "minLength": 10
          }
        },
        "required": [
          "hold_id",
          "reason"
        ]
      }
    },
    {
      "name": "admin.kms_status",
      "namespace": "admin",
      "description": "Return the current AES-256-GCM envelope encryption status, active KMS provider (local/vault/aws/gcp/azure), and key count.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    },
    {
      "name": "admin.storage_scrub",
      "namespace": "admin",
      "description": "Run an online non-destructive CRC32 integrity scrub over BrickWAL frames and cold slabs without taking the database offline.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    },
    {
      "name": "admin.lineage_get",
      "namespace": "admin",
      "description": "Retrieve full data provenance and transformation lineage events for an entity_id.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "entity_id"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "entity_id": {
            "type": "string",
            "description": "Node or entity ID to inspect lineage for."
          }
        },
        "required": [
          "entity_id"
        ]
      }
    },
    {
      "name": "aec.buildings_list",
      "namespace": "aec",
      "description": "List all stored BIM building models in the current tenant's graph (Phase 8).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    },
    {
      "name": "aec.buildings_analyses",
      "namespace": "aec",
      "description": "List all available analyses that can run against a stored BIM building (clashes, change_impact, compliance, egress, critical_members, rigidity, robustness, max_flow, fault_impact).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    },
    {
      "name": "aec.buildings_demo",
      "namespace": "aec",
      "description": "Create and persist a sample 2-storey BIM office building (footings, columns, beams, spaces, water pump/valves/outlets, pipes, ducts) in the graph so any Phase 8 AEC analysis can be executed immediately without uploading an IFC file.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [
        "name"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "default": "Demo office",
            "description": "Display name for the sample building."
          }
        },
        "required": []
      }
    },
    {
      "name": "aec.buildings_get",
      "namespace": "aec",
      "description": "Retrieve a stored BIM building summary and all its constituent BuildingElement nodes.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "building_id"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "building_id": {
            "type": "string",
            "description": "Building identifier."
          }
        },
        "required": [
          "building_id"
        ]
      }
    },
    {
      "name": "aec.buildings_delete",
      "namespace": "aec",
      "description": "Delete a stored BIM building and all its constituent elements.  \u26a0 human_only \u2014 agents are blocked; a human operator must perform this action directly.",
      "required_roles": [
        "admin",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "building_id"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "building_id": {
            "type": "string",
            "description": "Building identifier to remove."
          }
        },
        "required": [
          "building_id"
        ]
      }
    },
    {
      "name": "aec.buildings_run",
      "namespace": "aec",
      "description": "Run a Phase 8 AEC analysis against a stored building: clashes, change_impact, compliance, egress, critical_members, rigidity, robustness, max_flow, or fault_impact.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "building_id",
        "analysis"
      ],
      "optional_params": [
        "params"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "building_id": {
            "type": "string",
            "description": "Stored building identifier."
          },
          "analysis": {
            "type": "string",
            "enum": [
              "clashes",
              "change_impact",
              "compliance",
              "egress",
              "critical_members",
              "rigidity",
              "robustness",
              "max_flow",
              "fault_impact"
            ],
            "description": "Which AEC analysis to execute."
          },
          "params": {
            "type": "object",
            "description": "Optional analysis parameters (e.g. {'element_id': 'C1'})."
          }
        },
        "required": [
          "building_id",
          "analysis"
        ]
      }
    },
    {
      "name": "aec.vga_build",
      "namespace": "aec",
      "description": "Build a Space Syntax Visibility Graph (VGA) from a 2D floor plan boundary and obstacles (Phase 8.1).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "floor_plan"
      ],
      "optional_params": [
        "sample_points"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "floor_plan": {
            "type": "object",
            "properties": {
              "plan_id": {
                "type": "string",
                "default": ""
              },
              "boundary": {
                "type": "array",
                "items": {
                  "type": "array",
                  "items": {
                    "type": "number"
                  }
                }
              },
              "obstacles": {
                "type": "array",
                "items": {
                  "type": "array",
                  "items": {
                    "type": "array",
                    "items": {
                      "type": "number"
                    }
                  }
                }
              },
              "rooms": {
                "type": "object"
              },
              "entries": {
                "type": "array",
                "items": {
                  "type": "array",
                  "items": {
                    "type": "number"
                  }
                }
              },
              "grid_resolution": {
                "type": "number",
                "default": 0.5
              }
            }
          },
          "sample_points": {
            "type": "array",
            "items": {
              "type": "array",
              "items": {
                "type": "number"
              }
            }
          }
        },
        "required": [
          "floor_plan"
        ]
      }
    },
    {
      "name": "aec.structural_rigidity",
      "namespace": "aec",
      "description": "Evaluate 2D/3D Maxwell/Laman structural rigidity of a frame or truss graph (Phase 8.2).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "nodes",
        "edges"
      ],
      "optional_params": [
        "dimension"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "nodes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "node_id": {
                  "type": "string"
                },
                "node_type": {
                  "type": "string",
                  "default": "generic"
                },
                "x": {
                  "type": "number",
                  "default": 0.0
                },
                "y": {
                  "type": "number",
                  "default": 0.0
                },
                "z": {
                  "type": "number",
                  "default": 0.0
                },
                "properties": {
                  "type": "object"
                }
              },
              "required": [
                "node_id"
              ]
            },
            "description": "List of AEC graph nodes with 3D coordinates (x, y, z) and node_type."
          },
          "edges": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "edge_id": {
                  "type": "string"
                },
                "edge_type": {
                  "type": "string",
                  "default": "MEMBER"
                },
                "source_id": {
                  "type": "string"
                },
                "target_id": {
                  "type": "string"
                },
                "weight": {
                  "type": "number",
                  "default": 1.0
                },
                "capacity": {
                  "type": "number",
                  "default": 1.0
                },
                "properties": {
                  "type": "object"
                }
              },
              "required": [
                "edge_id",
                "source_id",
                "target_id"
              ]
            },
            "description": "List of AEC structural, spatial, or MEP edges."
          },
          "dimension": {
            "type": "integer",
            "enum": [
              2,
              3
            ],
            "default": 2
          }
        },
        "required": [
          "nodes",
          "edges"
        ]
      }
    },
    {
      "name": "aec.structural_critical_members",
      "namespace": "aec",
      "description": "Identify single-point-of-failure structural members (bridges) and biconnected components via iterative Tarjan DFS (Phase 8.2).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "nodes",
        "edges"
      ],
      "optional_params": [
        "dimension"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "nodes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "node_id": {
                  "type": "string"
                },
                "node_type": {
                  "type": "string",
                  "default": "generic"
                },
                "x": {
                  "type": "number",
                  "default": 0.0
                },
                "y": {
                  "type": "number",
                  "default": 0.0
                },
                "z": {
                  "type": "number",
                  "default": 0.0
                },
                "properties": {
                  "type": "object"
                }
              },
              "required": [
                "node_id"
              ]
            },
            "description": "List of AEC graph nodes with 3D coordinates (x, y, z) and node_type."
          },
          "edges": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "edge_id": {
                  "type": "string"
                },
                "edge_type": {
                  "type": "string",
                  "default": "MEMBER"
                },
                "source_id": {
                  "type": "string"
                },
                "target_id": {
                  "type": "string"
                },
                "weight": {
                  "type": "number",
                  "default": 1.0
                },
                "capacity": {
                  "type": "number",
                  "default": 1.0
                },
                "properties": {
                  "type": "object"
                }
              },
              "required": [
                "edge_id",
                "source_id",
                "target_id"
              ]
            },
            "description": "List of AEC structural, spatial, or MEP edges."
          },
          "dimension": {
            "type": "integer",
            "default": 2
          }
        },
        "required": [
          "nodes",
          "edges"
        ]
      }
    },
    {
      "name": "aec.bim_clashes",
      "namespace": "aec",
      "description": "Detect spatial/topological clashes between structural and MEP elements in a BIM graph (Phase 8.3).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "nodes",
        "edges"
      ],
      "optional_params": [
        "type_a",
        "type_b_prefix"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "nodes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "node_id": {
                  "type": "string"
                },
                "node_type": {
                  "type": "string",
                  "default": "generic"
                },
                "x": {
                  "type": "number",
                  "default": 0.0
                },
                "y": {
                  "type": "number",
                  "default": 0.0
                },
                "z": {
                  "type": "number",
                  "default": 0.0
                },
                "properties": {
                  "type": "object"
                }
              },
              "required": [
                "node_id"
              ]
            },
            "description": "List of AEC graph nodes with 3D coordinates (x, y, z) and node_type."
          },
          "edges": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "edge_id": {
                  "type": "string"
                },
                "edge_type": {
                  "type": "string",
                  "default": "MEMBER"
                },
                "source_id": {
                  "type": "string"
                },
                "target_id": {
                  "type": "string"
                },
                "weight": {
                  "type": "number",
                  "default": 1.0
                },
                "capacity": {
                  "type": "number",
                  "default": 1.0
                },
                "properties": {
                  "type": "object"
                }
              },
              "required": [
                "edge_id",
                "source_id",
                "target_id"
              ]
            },
            "description": "List of AEC structural, spatial, or MEP edges."
          },
          "type_a": {
            "type": "string",
            "default": "beam"
          },
          "type_b_prefix": {
            "type": "string",
            "default": "pipe"
          }
        },
        "required": [
          "nodes",
          "edges"
        ]
      }
    },
    {
      "name": "aec.design_egress",
      "namespace": "aec",
      "description": "Optimise emergency evacuation routes and bottleneck min-cuts from all spaces to exit_node_ids (Phase 8.4).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "nodes",
        "edges",
        "exit_node_ids"
      ],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {
          "nodes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "node_id": {
                  "type": "string"
                },
                "node_type": {
                  "type": "string",
                  "default": "generic"
                },
                "x": {
                  "type": "number",
                  "default": 0.0
                },
                "y": {
                  "type": "number",
                  "default": 0.0
                },
                "z": {
                  "type": "number",
                  "default": 0.0
                },
                "properties": {
                  "type": "object"
                }
              },
              "required": [
                "node_id"
              ]
            },
            "description": "List of AEC graph nodes with 3D coordinates (x, y, z) and node_type."
          },
          "edges": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "edge_id": {
                  "type": "string"
                },
                "edge_type": {
                  "type": "string",
                  "default": "MEMBER"
                },
                "source_id": {
                  "type": "string"
                },
                "target_id": {
                  "type": "string"
                },
                "weight": {
                  "type": "number",
                  "default": 1.0
                },
                "capacity": {
                  "type": "number",
                  "default": 1.0
                },
                "properties": {
                  "type": "object"
                }
              },
              "required": [
                "edge_id",
                "source_id",
                "target_id"
              ]
            },
            "description": "List of AEC structural, spatial, or MEP edges."
          },
          "exit_node_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "nodes",
          "edges",
          "exit_node_ids"
        ]
      }
    },
    {
      "name": "aec.mep_max_flow",
      "namespace": "aec",
      "description": "Compute Edmonds-Karp maximum flow and bottleneck capacity across an MEP utility network (Phase 8.5).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "nodes",
        "edges",
        "source_id",
        "sink_id"
      ],
      "optional_params": [
        "system_type"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "nodes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "node_id": {
                  "type": "string"
                },
                "node_type": {
                  "type": "string",
                  "default": "generic"
                },
                "x": {
                  "type": "number",
                  "default": 0.0
                },
                "y": {
                  "type": "number",
                  "default": 0.0
                },
                "z": {
                  "type": "number",
                  "default": 0.0
                },
                "properties": {
                  "type": "object"
                }
              },
              "required": [
                "node_id"
              ]
            },
            "description": "List of AEC graph nodes with 3D coordinates (x, y, z) and node_type."
          },
          "edges": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "edge_id": {
                  "type": "string"
                },
                "edge_type": {
                  "type": "string",
                  "default": "MEMBER"
                },
                "source_id": {
                  "type": "string"
                },
                "target_id": {
                  "type": "string"
                },
                "weight": {
                  "type": "number",
                  "default": 1.0
                },
                "capacity": {
                  "type": "number",
                  "default": 1.0
                },
                "properties": {
                  "type": "object"
                }
              },
              "required": [
                "edge_id",
                "source_id",
                "target_id"
              ]
            },
            "description": "List of AEC structural, spatial, or MEP edges."
          },
          "source_id": {
            "type": "string"
          },
          "sink_id": {
            "type": "string"
          },
          "system_type": {
            "type": "string",
            "default": "water_supply"
          }
        },
        "required": [
          "nodes",
          "edges",
          "source_id",
          "sink_id"
        ]
      }
    },
    {
      "name": "aec.spectral_fiedler",
      "namespace": "aec",
      "description": "Compute the Graph Laplacian algebraic connectivity (\u03bb\u2082 Fiedler value and Fiedler vector) for structural robustness (Phase 8.7).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "nodes",
        "edges"
      ],
      "optional_params": [
        "normalised",
        "safety_threshold",
        "graph_id"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "nodes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "node_id": {
                  "type": "string"
                },
                "node_type": {
                  "type": "string",
                  "default": "generic"
                },
                "x": {
                  "type": "number",
                  "default": 0.0
                },
                "y": {
                  "type": "number",
                  "default": 0.0
                },
                "z": {
                  "type": "number",
                  "default": 0.0
                },
                "properties": {
                  "type": "object"
                }
              },
              "required": [
                "node_id"
              ]
            },
            "description": "List of AEC graph nodes with 3D coordinates (x, y, z) and node_type."
          },
          "edges": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "edge_id": {
                  "type": "string"
                },
                "edge_type": {
                  "type": "string",
                  "default": "MEMBER"
                },
                "source_id": {
                  "type": "string"
                },
                "target_id": {
                  "type": "string"
                },
                "weight": {
                  "type": "number",
                  "default": 1.0
                },
                "capacity": {
                  "type": "number",
                  "default": 1.0
                },
                "properties": {
                  "type": "object"
                }
              },
              "required": [
                "edge_id",
                "source_id",
                "target_id"
              ]
            },
            "description": "List of AEC structural, spatial, or MEP edges."
          },
          "normalised": {
            "type": "boolean",
            "default": false
          },
          "safety_threshold": {
            "type": "number",
            "default": 0.01
          },
          "graph_id": {
            "type": "string",
            "default": "structural"
          }
        },
        "required": [
          "nodes",
          "edges"
        ]
      }
    },
    {
      "name": "aec.topo_optimise",
      "namespace": "aec",
      "description": "Start a 3D SIMP-on-graph structural topology optimisation job over a bounding-box volume mesh (Phase 8.8).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "bounding_box"
      ],
      "optional_params": [
        "resolution",
        "load_node_ids",
        "support_node_ids",
        "volume_fraction",
        "max_iter"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "bounding_box": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "minItems": 6,
            "maxItems": 6
          },
          "resolution": {
            "type": "number",
            "default": 1.0
          },
          "load_node_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "support_node_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "volume_fraction": {
            "type": "number",
            "default": 0.4
          },
          "max_iter": {
            "type": "integer",
            "default": 50
          }
        },
        "required": [
          "bounding_box"
        ]
      }
    },
    {
      "name": "aec.morl_generate",
      "namespace": "aec",
      "description": "Train a Multi-Objective Reinforcement Learning (MORL) GCN policy and return the Pareto-optimal spatial layout (Phase 8.9).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin"
      ],
      "human_only": false,
      "required_params": [
        "nodes",
        "edges"
      ],
      "optional_params": [
        "zone_labels",
        "reward_weights",
        "episodes",
        "seed"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "nodes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "node_id": {
                  "type": "string"
                },
                "node_type": {
                  "type": "string",
                  "default": "generic"
                },
                "x": {
                  "type": "number",
                  "default": 0.0
                },
                "y": {
                  "type": "number",
                  "default": 0.0
                },
                "z": {
                  "type": "number",
                  "default": 0.0
                },
                "properties": {
                  "type": "object"
                }
              },
              "required": [
                "node_id"
              ]
            },
            "description": "List of AEC graph nodes with 3D coordinates (x, y, z) and node_type."
          },
          "edges": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "edge_id": {
                  "type": "string"
                },
                "edge_type": {
                  "type": "string",
                  "default": "MEMBER"
                },
                "source_id": {
                  "type": "string"
                },
                "target_id": {
                  "type": "string"
                },
                "weight": {
                  "type": "number",
                  "default": 1.0
                },
                "capacity": {
                  "type": "number",
                  "default": 1.0
                },
                "properties": {
                  "type": "object"
                }
              },
              "required": [
                "edge_id",
                "source_id",
                "target_id"
              ]
            },
            "description": "List of AEC structural, spatial, or MEP edges."
          },
          "zone_labels": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "reward_weights": {
            "type": "object"
          },
          "episodes": {
            "type": "integer",
            "default": 20
          },
          "seed": {
            "type": "integer",
            "default": 42
          }
        },
        "required": [
          "nodes",
          "edges"
        ]
      }
    },
    {
      "name": "aec.mpnn_propagate",
      "namespace": "aec",
      "description": "Run the pure-numpy Message-Passing Neural Network (MPNN) physics surrogate to predict nodal displacements and stress proxies (Phase 8.10).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "nodes",
        "edges"
      ],
      "optional_params": [
        "load_vector",
        "hidden_dim",
        "message_steps",
        "graph_id"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "nodes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "node_id": {
                  "type": "string"
                },
                "node_type": {
                  "type": "string",
                  "default": "generic"
                },
                "x": {
                  "type": "number",
                  "default": 0.0
                },
                "y": {
                  "type": "number",
                  "default": 0.0
                },
                "z": {
                  "type": "number",
                  "default": 0.0
                },
                "properties": {
                  "type": "object"
                }
              },
              "required": [
                "node_id"
              ]
            },
            "description": "List of AEC graph nodes with 3D coordinates (x, y, z) and node_type."
          },
          "edges": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "edge_id": {
                  "type": "string"
                },
                "edge_type": {
                  "type": "string",
                  "default": "MEMBER"
                },
                "source_id": {
                  "type": "string"
                },
                "target_id": {
                  "type": "string"
                },
                "weight": {
                  "type": "number",
                  "default": 1.0
                },
                "capacity": {
                  "type": "number",
                  "default": 1.0
                },
                "properties": {
                  "type": "object"
                }
              },
              "required": [
                "edge_id",
                "source_id",
                "target_id"
              ]
            },
            "description": "List of AEC structural, spatial, or MEP edges."
          },
          "load_vector": {
            "type": "object"
          },
          "hidden_dim": {
            "type": "integer",
            "default": 16
          },
          "message_steps": {
            "type": "integer",
            "default": 3
          },
          "graph_id": {
            "type": "string",
            "default": "structural"
          }
        },
        "required": [
          "nodes",
          "edges"
        ]
      }
    },
    {
      "name": "aec.hypergraph_build",
      "namespace": "aec",
      "description": "Expand multi-way AEC hyperedges (joints, zones, assemblies) via clique or star expansion (Phase 8.11).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "nodes",
        "hyperedges"
      ],
      "optional_params": [
        "method"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "nodes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "node_id": {
                  "type": "string"
                },
                "node_type": {
                  "type": "string",
                  "default": "generic"
                },
                "x": {
                  "type": "number",
                  "default": 0.0
                },
                "y": {
                  "type": "number",
                  "default": 0.0
                },
                "z": {
                  "type": "number",
                  "default": 0.0
                },
                "properties": {
                  "type": "object"
                }
              },
              "required": [
                "node_id"
              ]
            },
            "description": "List of AEC graph nodes with 3D coordinates (x, y, z) and node_type."
          },
          "hyperedges": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "hyperedge_id": {
                  "type": "string"
                },
                "node_ids": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "edge_type": {
                  "type": "string",
                  "default": "generic"
                },
                "weight": {
                  "type": "number",
                  "default": 1.0
                }
              },
              "required": [
                "hyperedge_id",
                "node_ids"
              ]
            }
          },
          "method": {
            "type": "string",
            "enum": [
              "clique",
              "star"
            ],
            "default": "clique"
          }
        },
        "required": [
          "nodes",
          "hyperedges"
        ]
      }
    },
    {
      "name": "aec.ifc_rewrite",
      "namespace": "aec",
      "description": "Rewrite a raw IFC BIM graph into a domain-specific analytical graph ('structural', 'vga', or 'mep') via declarative rules (Phase 8.12).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "nodes",
        "edges"
      ],
      "optional_params": [
        "target"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "nodes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "node_id": {
                  "type": "string"
                },
                "node_type": {
                  "type": "string",
                  "default": "generic"
                },
                "x": {
                  "type": "number",
                  "default": 0.0
                },
                "y": {
                  "type": "number",
                  "default": 0.0
                },
                "z": {
                  "type": "number",
                  "default": 0.0
                },
                "properties": {
                  "type": "object"
                }
              },
              "required": [
                "node_id"
              ]
            },
            "description": "List of AEC graph nodes with 3D coordinates (x, y, z) and node_type."
          },
          "edges": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "edge_id": {
                  "type": "string"
                },
                "edge_type": {
                  "type": "string",
                  "default": "MEMBER"
                },
                "source_id": {
                  "type": "string"
                },
                "target_id": {
                  "type": "string"
                },
                "weight": {
                  "type": "number",
                  "default": 1.0
                },
                "capacity": {
                  "type": "number",
                  "default": 1.0
                },
                "properties": {
                  "type": "object"
                }
              },
              "required": [
                "edge_id",
                "source_id",
                "target_id"
              ]
            },
            "description": "List of AEC structural, spatial, or MEP edges."
          },
          "target": {
            "type": "string",
            "enum": [
              "structural",
              "vga",
              "mep"
            ],
            "default": "structural"
          }
        },
        "required": [
          "nodes",
          "edges"
        ]
      }
    },
    {
      "name": "soc.stats",
      "namespace": "soc",
      "description": "Return autonomous Security Operations Center (SOC) threat detection and containment statistics (critical/high active containments, total released).",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    },
    {
      "name": "soc.containments_active",
      "namespace": "soc",
      "description": "List currently active SOC threat containments and quarantined actor sessions.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    },
    {
      "name": "soc.audit_log",
      "namespace": "soc",
      "description": "Retrieve the SOC security incident and autonomous containment audit log.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [
        "limit"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "limit": {
            "type": "integer",
            "default": 50,
            "minimum": 1,
            "maximum": 500
          }
        },
        "required": []
      }
    },
    {
      "name": "supergraph.peers_list",
      "namespace": "supergraph",
      "description": "List declared regional/domain Purple8 SuperGraph federation peers and their approval status.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [],
      "optional_params": [],
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    },
    {
      "name": "supergraph.query",
      "namespace": "supergraph",
      "description": "Execute an approved federated query across stitched SuperGraph peer instances.",
      "required_roles": [
        "admin",
        "contributor",
        "editor",
        "super_admin",
        "viewer"
      ],
      "human_only": false,
      "required_params": [
        "query"
      ],
      "optional_params": [
        "params",
        "domains",
        "journey_id",
        "deduplicate"
      ],
      "inputSchema": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string",
            "description": "Cypher query to execute across approved peers."
          },
          "params": {
            "type": "object",
            "description": "Optional query parameters."
          },
          "domains": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Optional domain filter."
          },
          "journey_id": {
            "type": "string"
          },
          "deduplicate": {
            "type": "boolean",
            "default": true
          }
        },
        "required": [
          "query"
        ]
      }
    }
  ]
}