Skip to main content
Glama

Consequential actions

destructive
Destructive

Operations that require extra caution or confirmation. dedupe_knowledge is a read-only candidate scan; the remaining actions are consequential. Action names carry their resource because this tool spans resources. action = cancel_task | force_claim_task | dedupe_knowledge | dedupe_pair | unlink | restore_node_version | retire_objective | merge_workspace | cherry_pick_workspace | archive_workspace | archive_component | merge_topics | run_loop_attempt | doctor. run_loop_attempt executes the exact declared shell command supplied in the approval arguments with a scrubbed environment when trusted local repository execution is available; hosted MCP fails closed.

Input Schema

NameRequiredDescriptionDefault

No arguments

Output Schema

NameRequiredDescriptionDefault
dataYesThe action-specific result returned by Stele.
actionYesThe action that produced this result.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changed
    • changedInput schema / anyOf
      Previous value: -[
      -  {
      -    "additionalProperties": false,
      -    "description": "action=\"cancel_task\": Cancel a task (→ cancelled) with a required `reason` (appended to the body). For wrong/duplicate/obsolete tasks — not ones you merely couldn't finish (use release). Like complete, may surface nearby nodes to re-verify.",
      -    "properties": {
      -      "action": {
      -        "const": "cancel_task",
      -        "type": "string"
      -      },
      -      "node_id": {
      -        "description": "REQUIRED for cancel_task/force_claim_task/restore_node_version/archive_component — shareable id of the target (TASK-N / KNOW-N / COMP-N / …).",
      -        "type": "string"
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "reason": {
      -        "description": "REQUIRED for cancel_task — why this task is being cancelled.",
      -        "minLength": 1,
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug",
      -      "node_id",
      -      "reason"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "description": "action=\"force_claim_task\": Emergency override: take over a task in any state. Use only when the prior claimer is abandoned (check destructive(action=\"doctor\") first) or the user asks. Returns the prior claimer's identity so you can notify them; concurrent force-claims are last-write-wins.",
      -    "properties": {
      -      "action": {
      -        "const": "force_claim_task",
      -        "type": "string"
      -      },
      -      "dispatched_with": {
      -        "description": "(force_claim_task only) Operator's full briefing prompt when this force-claim is from a dispatched sub-agent. Up to 16 KB.",
      -        "type": "string"
      -      },
      -      "node_id": {
      -        "description": "Task shareable id (e.g. TASK-42).",
      -        "type": "string"
      -      },
      -      "parent_task_id": {
      -        "description": "(force_claim_task only) Operator's claimed task id when this force-claim is from a dispatched sub-agent. Leave null for direct claims.",
      -        "type": "string"
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug",
      -      "node_id"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "description": "action=\"dedupe_knowledge\": Find near-duplicate knowledge nodes by fuzzy title similarity (pg_trgm). Read-only — never deletes or merges; returns candidate pairs sorted by similarity for the caller to act on (use node(action=\"update\") to archive the dup side).",
      -    "properties": {
      -      "action": {
      -        "const": "dedupe_knowledge",
      -        "type": "string"
      -      },
      -      "category": {
      -        "description": "(dedupe_knowledge only) Restrict the scan to one knowledge category. Default: all categories.",
      -        "enum": [
      -          "decision",
      -          "architecture",
      -          "goal",
      -          "risk",
      -          "gap",
      -          "fyi",
      -          "opportunity",
      -          "priority",
      -          "lesson"
      -        ],
      -        "type": "string"
      -      },
      -      "limit": {
      -        "description": "(dedupe_knowledge only) Max pairs to return. Default 20.",
      -        "maximum": 200,
      -        "minimum": 1,
      -        "type": "integer"
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "threshold": {
      -        "description": "(dedupe_knowledge only) Similarity threshold (0–1). Default 0.7. Raise toward 1 for stricter matches.",
      -        "maximum": 1,
      -        "minimum": 0,
      -        "type": "number"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "description": "action=\"dedupe_pair\": Mark `drop_id` as a duplicate of `keep_id`. Atomically rewires every edge that touches the drop onto the keep (skipping conflicts on the unique (src,dst,relation) constraint), deletes any stragglers, archives the drop, and appends a `## Deduped` pointer to its body — all in one transaction. Returns the kept node and the pre-conflict count of edges that touched the drop. DESTRUCTIVE (the drop is archived). Find the candidate pair first (a duplicate scan or a search); this action merges one.",
      -    "properties": {
      -      "action": {
      -        "const": "dedupe_pair",
      -        "type": "string"
      -      },
      -      "drop_id": {
      -        "description": "REQUIRED for dedupe_pair — the duplicate to archive; its edges are rewired onto keep_id.",
      -        "type": "string"
      -      },
      -      "keep_id": {
      -        "description": "REQUIRED for dedupe_pair — the node to keep.",
      -        "type": "string"
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug",
      -      "keep_id",
      -      "drop_id"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "description": "action=\"unlink\": Remove the (src, dst, relation) edge if it exists; no-op if it doesn't. To preserve what the edge USED to mean, prefer link with `supersedes` over removing it.",
      -    "properties": {
      -      "action": {
      -        "const": "unlink",
      -        "type": "string"
      -      },
      -      "dst_id": {
      -        "description": "REQUIRED for unlink — destination node shareable id.",
      -        "type": "string"
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "relation": {
      -        "description": "REQUIRED for unlink — edge type to remove.",
      -        "enum": [
      -          "relates-to",
      -          "blocks",
      -          "fulfills",
      -          "contradicts",
      -          "supersedes",
      -          "caused-by",
      -          "expires-on"
      -        ],
      -        "type": "string"
      -      },
      -      "src_id": {
      -        "description": "REQUIRED for unlink — source node shareable id.",
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug",
      -      "src_id",
      -      "dst_id",
      -      "relation"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "description": "action=\"restore_node_version\": Restore a prior version's content as the new live content. APPEND, NEVER DESTRUCTIVE: restoring v2 over a live v3 writes v2 as a new live v4, snapshotting v3 into history first — both stay recoverable, so a bad restore is just another restore. Recorded with restored_from_version so history shows it was a restore, not a fresh edit.",
      -    "properties": {
      -      "action": {
      -        "const": "restore_node_version",
      -        "type": "string"
      -      },
      -      "node_id": {
      -        "description": "Node shareable id (e.g. KNOW-42).",
      -        "type": "string"
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "version": {
      -        "description": "REQUIRED for restore_node_version — the version number to restore as the new live content.",
      -        "exclusiveMinimum": 0,
      -        "type": "integer"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug",
      -      "node_id",
      -      "version"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "description": "action=\"retire_objective\": Retire an objective: cancels it (its status reads as 'superseded') and, when a replacement objective is named, records a `supersedes` edge so the chain stays navigable.",
      -    "properties": {
      -      "action": {
      -        "const": "retire_objective",
      -        "type": "string"
      -      },
      -      "objective_id": {
      -        "description": "REQUIRED for retire_objective — the objective being retired (TASK-N).",
      -        "type": "string"
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "replaced_by": {
      -        "description": "(retire_objective only) Optional replacement objective (TASK-N) — records a `supersedes` edge.",
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug",
      -      "objective_id"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "description": "action=\"merge_workspace\": Promote ALL of a workspace's scoped knowledge to trunk (shared truth), then mark the workspace 'merged'. Each promoted node flips to trunk and is stamped with provenance (which workspace + when). To graduate only SOME items, use destructive(action=\"cherry_pick_workspace\") instead. Permanent (domain) workspaces cannot be merged — they never graduate.",
      -    "properties": {
      -      "action": {
      -        "const": "merge_workspace",
      -        "type": "string"
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "workspace": {
      -        "description": "REQUIRED for merge_workspace/cherry_pick_workspace/archive_workspace — the workspace to act on — its NAME (e.g. \"Billing\") or its uuid. NOT a short-id (workspaces aren't nodes).",
      -        "minLength": 1,
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug",
      -      "workspace"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "description": "action=\"cherry_pick_workspace\": Promote ONLY the named knowledge/tasks from a workspace to trunk, leaving everything else scoped and the workspace active — the partial-merge / salvage case. Each promoted node flips to trunk and is stamped with provenance (which workspace + when). The workspace itself is NOT changed (archive or merge it separately). Ids not scoped to this workspace are ignored.",
      -    "properties": {
      -      "action": {
      -        "const": "cherry_pick_workspace",
      -        "type": "string"
      -      },
      -      "node_ids": {
      -        "description": "REQUIRED for cherry_pick_workspace — short-ids of the nodes to promote (KNOW-N / TASK-N / DOC-N / …). Only items currently scoped to this workspace are promoted.",
      -        "items": {
      -          "type": "string"
      -        },
      -        "minItems": 1,
      -        "type": "array"
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "workspace": {
      -        "description": "The workspace to act on — its NAME (e.g. \"Billing\") or its uuid. NOT a short-id (workspaces aren't nodes).",
      -        "minLength": 1,
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug",
      -      "workspace",
      -      "node_ids"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "description": "action=\"archive_workspace\": Archive a workspace (abandon it). RECOVERABLE — the workspace and ALL its scoped knowledge are kept as-is and can be reactivated; never deletes. Salvage anything worth keeping with destructive(action=\"cherry_pick_workspace\") FIRST — those items graduate to trunk and survive the archive.",
      -    "properties": {
      -      "action": {
      -        "const": "archive_workspace",
      -        "type": "string"
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "workspace": {
      -        "description": "REQUIRED for merge_workspace/cherry_pick_workspace/archive_workspace — the workspace to act on — its NAME (e.g. \"Billing\") or its uuid. NOT a short-id (workspaces aren't nodes).",
      -        "minLength": 1,
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug",
      -      "workspace"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "description": "action=\"archive_component\": Archive a component (soft-delete). If it has any ACTIVE children (sub-components, knowledge, or tasks), `reparent_children_to` is REQUIRED — they move to that target. We never silently orphan or cascade-delete.",
      -    "properties": {
      -      "action": {
      -        "const": "archive_component",
      -        "type": "string"
      -      },
      -      "node_id": {
      -        "description": "Component shareable id to archive.",
      -        "type": "string"
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "reparent_children_to": {
      -        "description": "(archive_component only) Component to reparent active children under. Required if any active children exist.",
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug",
      -      "node_id"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "description": "action=\"merge_topics\": Merge multiple source topics into a single target across every knowledge AND task node in the active project — like rename_topic once per source, in one transaction with the same dedup semantics. Sources equal to the target (or empty) are silently skipped. Members-only.",
      -    "properties": {
      -      "action": {
      -        "const": "merge_topics",
      -        "type": "string"
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "sources": {
      -        "description": "REQUIRED for merge_topics — list of source topics to merge into target. Must be non-empty.",
      -        "items": {
      -          "minLength": 1,
      -          "type": "string"
      -        },
      -        "minItems": 1,
      -        "type": "array"
      -      },
      -      "target": {
      -        "description": "REQUIRED for merge_topics — target topic. Must be non-empty.",
      -        "minLength": 1,
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug",
      -      "sources",
      -      "target"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "description": "action=\"run_loop_attempt\": Locally execute the task's declared Check in the worker branch's registered worktree, challenge its protected wrapper with a fresh nonce, accept only a versioned STELE_LOOP_EVIDENCE JSON line, persist exact counts/output on the task, and halt on the same failure twice or five failed attempts. Hosted MCP fails closed because it cannot execute the repository.",
      -    "properties": {
      -      "action": {
      -        "const": "run_loop_attempt",
      -        "type": "string"
      -      },
      -      "base": {
      -        "description": "Base git ref (default main).",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "branch": {
      -        "description": "Worker branch git ref (default HEAD).",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "command": {
      -        "description": "Exact declared check command. It is shown at the destructive approval boundary and must match the task contract.",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "node_id": {
      -        "description": "Task whose declared Check and Check paths form the loop contract.",
      -        "pattern": "^TASK-\\d+$",
      -        "type": "string"
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug",
      -      "node_id",
      -      "command"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "description": "action=\"doctor\": Run health checks on the active project, returning grouped issue buckets (stale/archivable/expired/superseded knowledge, stale claims, oversized/dangling/orphaned components, overdue or unbound risks, unverified load-bearing decisions, duplicates, empty bodies, over-fulfilled tasks). Run periodically — especially before destructive(action=\"force_claim_task\") on a task you suspect is abandoned. fix=true applies safe auto-fixes (archives archivable/expired/superseded knowledge and expire-on-close risks); all other buckets are reported only. expensive=true (alias deep=true) also runs costly fuzzy/trigram near-duplicate detection, folded into the duplicates bucket.",
      -    "properties": {
      -      "action": {
      -        "const": "doctor",
      -        "type": "string"
      -      },
      -      "deep": {
      -        "description": "(doctor only) Alias for `expensive`. Default false.",
      -        "type": "boolean"
      -      },
      -      "expensive": {
      -        "description": "(doctor only) Run costly checks too (fuzzy near-duplicate detection, folded into the duplicates bucket). Default false.",
      -        "type": "boolean"
      -      },
      -      "fix": {
      -        "description": "Apply safe auto-fixes: archive stale, expired and superseded knowledge, and risks bound to closed tasks. Default false.",
      -        "type": "boolean"
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug"
      -    ],
      -    "type": "object"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": false,
      +    "description": "destructive action \"cancel_task\".",
      +    "properties": {
      +      "action": {
      +        "const": "cancel_task",
      +        "description": "Run the cancel_task action.",
      +        "type": "string"
      +      },
      +      "node_id": {
      +        "description": "REQUIRED for cancel_task/force_claim_task/restore_node_version/archive_component — shareable id of the target (TASK-N / KNOW-N / COMP-N / …).",
      +        "type": "string"
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "reason": {
      +        "description": "REQUIRED for cancel_task — why this task is being cancelled.",
      +        "minLength": 1,
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug",
      +      "node_id",
      +      "reason"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "description": "destructive action \"force_claim_task\".",
      +    "properties": {
      +      "action": {
      +        "const": "force_claim_task",
      +        "description": "Run the force_claim_task action.",
      +        "type": "string"
      +      },
      +      "dispatched_with": {
      +        "description": "(force_claim_task only) Operator's full briefing prompt when this force-claim is from a dispatched sub-agent. Up to 16 KB.",
      +        "type": "string"
      +      },
      +      "node_id": {
      +        "description": "Task shareable id (e.g. TASK-42).",
      +        "type": "string"
      +      },
      +      "parent_task_id": {
      +        "description": "(force_claim_task only) Operator's claimed task id when this force-claim is from a dispatched sub-agent. Leave null for direct claims.",
      +        "type": "string"
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug",
      +      "node_id"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "description": "destructive action \"dedupe_knowledge\".",
      +    "properties": {
      +      "action": {
      +        "const": "dedupe_knowledge",
      +        "description": "Run the dedupe_knowledge action.",
      +        "type": "string"
      +      },
      +      "category": {
      +        "description": "(dedupe_knowledge only) Restrict the scan to one knowledge category. Default: all categories.",
      +        "enum": [
      +          "decision",
      +          "architecture",
      +          "goal",
      +          "risk",
      +          "gap",
      +          "fyi",
      +          "opportunity",
      +          "priority",
      +          "lesson"
      +        ],
      +        "type": "string"
      +      },
      +      "limit": {
      +        "description": "(dedupe_knowledge only) Max pairs to return. Default 20.",
      +        "maximum": 200,
      +        "minimum": 1,
      +        "type": "integer"
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "threshold": {
      +        "description": "(dedupe_knowledge only) Similarity threshold (0–1). Default 0.7. Raise toward 1 for stricter matches.",
      +        "maximum": 1,
      +        "minimum": 0,
      +        "type": "number"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "description": "destructive action \"dedupe_pair\".",
      +    "properties": {
      +      "action": {
      +        "const": "dedupe_pair",
      +        "description": "Run the dedupe_pair action.",
      +        "type": "string"
      +      },
      +      "drop_id": {
      +        "description": "REQUIRED for dedupe_pair — the duplicate to archive; its edges are rewired onto keep_id.",
      +        "type": "string"
      +      },
      +      "keep_id": {
      +        "description": "REQUIRED for dedupe_pair — the node to keep.",
      +        "type": "string"
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug",
      +      "keep_id",
      +      "drop_id"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "description": "destructive action \"unlink\".",
      +    "properties": {
      +      "action": {
      +        "const": "unlink",
      +        "description": "Run the unlink action.",
      +        "type": "string"
      +      },
      +      "dst_id": {
      +        "description": "REQUIRED for unlink — destination node shareable id.",
      +        "type": "string"
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "relation": {
      +        "description": "REQUIRED for unlink — edge type to remove.",
      +        "enum": [
      +          "relates-to",
      +          "blocks",
      +          "fulfills",
      +          "contradicts",
      +          "supersedes",
      +          "caused-by",
      +          "expires-on"
      +        ],
      +        "type": "string"
      +      },
      +      "src_id": {
      +        "description": "REQUIRED for unlink — source node shareable id.",
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug",
      +      "src_id",
      +      "dst_id",
      +      "relation"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "description": "destructive action \"restore_node_version\".",
      +    "properties": {
      +      "action": {
      +        "const": "restore_node_version",
      +        "description": "Run the restore_node_version action.",
      +        "type": "string"
      +      },
      +      "node_id": {
      +        "description": "Node shareable id (e.g. KNOW-42).",
      +        "type": "string"
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "version": {
      +        "description": "REQUIRED for restore_node_version — the version number to restore as the new live content.",
      +        "exclusiveMinimum": 0,
      +        "type": "integer"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug",
      +      "node_id",
      +      "version"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "description": "destructive action \"retire_objective\".",
      +    "properties": {
      +      "action": {
      +        "const": "retire_objective",
      +        "description": "Run the retire_objective action.",
      +        "type": "string"
      +      },
      +      "objective_id": {
      +        "description": "REQUIRED for retire_objective — the objective being retired (TASK-N).",
      +        "type": "string"
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "replaced_by": {
      +        "description": "(retire_objective only) Optional replacement objective (TASK-N) — records a `supersedes` edge.",
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug",
      +      "objective_id"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "description": "destructive action \"merge_workspace\".",
      +    "properties": {
      +      "action": {
      +        "const": "merge_workspace",
      +        "description": "Run the merge_workspace action.",
      +        "type": "string"
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "workspace": {
      +        "description": "REQUIRED for merge_workspace/cherry_pick_workspace/archive_workspace — the workspace to act on — its NAME (e.g. \"Billing\") or its uuid. NOT a short-id (workspaces aren't nodes).",
      +        "minLength": 1,
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug",
      +      "workspace"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "description": "destructive action \"cherry_pick_workspace\".",
      +    "properties": {
      +      "action": {
      +        "const": "cherry_pick_workspace",
      +        "description": "Run the cherry_pick_workspace action.",
      +        "type": "string"
      +      },
      +      "node_ids": {
      +        "description": "REQUIRED for cherry_pick_workspace — short-ids of the nodes to promote (KNOW-N / TASK-N / DOC-N / …). Only items currently scoped to this workspace are promoted.",
      +        "items": {
      +          "type": "string"
      +        },
      +        "minItems": 1,
      +        "type": "array"
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "workspace": {
      +        "description": "The workspace to act on — its NAME (e.g. \"Billing\") or its uuid. NOT a short-id (workspaces aren't nodes).",
      +        "minLength": 1,
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug",
      +      "workspace",
      +      "node_ids"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "description": "destructive action \"archive_workspace\".",
      +    "properties": {
      +      "action": {
      +        "const": "archive_workspace",
      +        "description": "Run the archive_workspace action.",
      +        "type": "string"
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "workspace": {
      +        "description": "REQUIRED for merge_workspace/cherry_pick_workspace/archive_workspace — the workspace to act on — its NAME (e.g. \"Billing\") or its uuid. NOT a short-id (workspaces aren't nodes).",
      +        "minLength": 1,
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug",
      +      "workspace"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "description": "destructive action \"archive_component\".",
      +    "properties": {
      +      "action": {
      +        "const": "archive_component",
      +        "description": "Run the archive_component action.",
      +        "type": "string"
      +      },
      +      "node_id": {
      +        "description": "Component shareable id to archive.",
      +        "type": "string"
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "reparent_children_to": {
      +        "description": "(archive_component only) Component to reparent active children under. Required if any active children exist.",
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug",
      +      "node_id"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "description": "destructive action \"merge_topics\".",
      +    "properties": {
      +      "action": {
      +        "const": "merge_topics",
      +        "description": "Run the merge_topics action.",
      +        "type": "string"
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "sources": {
      +        "description": "REQUIRED for merge_topics — list of source topics to merge into target. Must be non-empty.",
      +        "items": {
      +          "minLength": 1,
      +          "type": "string"
      +        },
      +        "minItems": 1,
      +        "type": "array"
      +      },
      +      "target": {
      +        "description": "REQUIRED for merge_topics — target topic. Must be non-empty.",
      +        "minLength": 1,
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug",
      +      "sources",
      +      "target"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "description": "destructive action \"run_loop_attempt\".",
      +    "properties": {
      +      "action": {
      +        "const": "run_loop_attempt",
      +        "description": "Run the run_loop_attempt action.",
      +        "type": "string"
      +      },
      +      "base": {
      +        "description": "Base git ref (default main).",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "branch": {
      +        "description": "Worker branch git ref (default HEAD).",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "command": {
      +        "description": "Exact declared check command. It is shown at the destructive approval boundary and must match the task contract.",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "node_id": {
      +        "description": "Task whose declared Check and Check paths form the loop contract.",
      +        "pattern": "^TASK-\\d+$",
      +        "type": "string"
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug",
      +      "node_id",
      +      "command"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "description": "destructive action \"doctor\".",
      +    "properties": {
      +      "action": {
      +        "const": "doctor",
      +        "description": "Run the doctor action.",
      +        "type": "string"
      +      },
      +      "deep": {
      +        "description": "(doctor only) Alias for `expensive`. Default false.",
      +        "type": "boolean"
      +      },
      +      "expensive": {
      +        "description": "(doctor only) Run costly checks too (fuzzy near-duplicate detection, folded into the duplicates bucket). Default false.",
      +        "type": "boolean"
      +      },
      +      "fix": {
      +        "description": "Apply safe auto-fixes: archive stale, expired and superseded knowledge, and risks bound to closed tasks. Default false.",
      +        "type": "boolean"
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug"
      +    ],
      +    "type": "object"
      +  }
      +]
  2. Changed1 schema field changed
    • changedInput schema / anyOf
      Previous value: -[
      -  {
      -    "additionalProperties": false,
      -    "description": "destructive action \"cancel_task\".",
      -    "properties": {
      -      "action": {
      -        "const": "cancel_task",
      -        "description": "Run the cancel_task action.",
      -        "type": "string"
      -      },
      -      "node_id": {
      -        "description": "REQUIRED for cancel_task/force_claim_task/restore_node_version/archive_component — shareable id of the target (TASK-N / KNOW-N / COMP-N / …).",
      -        "type": "string"
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "reason": {
      -        "description": "REQUIRED for cancel_task — why this task is being cancelled.",
      -        "minLength": 1,
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug",
      -      "node_id",
      -      "reason"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "description": "destructive action \"force_claim_task\".",
      -    "properties": {
      -      "action": {
      -        "const": "force_claim_task",
      -        "description": "Run the force_claim_task action.",
      -        "type": "string"
      -      },
      -      "dispatched_with": {
      -        "description": "(force_claim_task only) Operator's full briefing prompt when this force-claim is from a dispatched sub-agent. Up to 16 KB.",
      -        "type": "string"
      -      },
      -      "node_id": {
      -        "description": "Task shareable id (e.g. TASK-42).",
      -        "type": "string"
      -      },
      -      "parent_task_id": {
      -        "description": "(force_claim_task only) Operator's claimed task id when this force-claim is from a dispatched sub-agent. Leave null for direct claims.",
      -        "type": "string"
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug",
      -      "node_id"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "description": "destructive action \"dedupe_knowledge\".",
      -    "properties": {
      -      "action": {
      -        "const": "dedupe_knowledge",
      -        "description": "Run the dedupe_knowledge action.",
      -        "type": "string"
      -      },
      -      "category": {
      -        "description": "(dedupe_knowledge only) Restrict the scan to one knowledge category. Default: all categories.",
      -        "enum": [
      -          "decision",
      -          "architecture",
      -          "goal",
      -          "risk",
      -          "gap",
      -          "fyi",
      -          "opportunity",
      -          "priority",
      -          "lesson"
      -        ],
      -        "type": "string"
      -      },
      -      "limit": {
      -        "description": "(dedupe_knowledge only) Max pairs to return. Default 20.",
      -        "maximum": 200,
      -        "minimum": 1,
      -        "type": "integer"
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "threshold": {
      -        "description": "(dedupe_knowledge only) Similarity threshold (0–1). Default 0.7. Raise toward 1 for stricter matches.",
      -        "maximum": 1,
      -        "minimum": 0,
      -        "type": "number"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "description": "destructive action \"dedupe_pair\".",
      -    "properties": {
      -      "action": {
      -        "const": "dedupe_pair",
      -        "description": "Run the dedupe_pair action.",
      -        "type": "string"
      -      },
      -      "drop_id": {
      -        "description": "REQUIRED for dedupe_pair — the duplicate to archive; its edges are rewired onto keep_id.",
      -        "type": "string"
      -      },
      -      "keep_id": {
      -        "description": "REQUIRED for dedupe_pair — the node to keep.",
      -        "type": "string"
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug",
      -      "keep_id",
      -      "drop_id"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "description": "destructive action \"unlink\".",
      -    "properties": {
      -      "action": {
      -        "const": "unlink",
      -        "description": "Run the unlink action.",
      -        "type": "string"
      -      },
      -      "dst_id": {
      -        "description": "REQUIRED for unlink — destination node shareable id.",
      -        "type": "string"
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "relation": {
      -        "description": "REQUIRED for unlink — edge type to remove.",
      -        "enum": [
      -          "relates-to",
      -          "blocks",
      -          "fulfills",
      -          "contradicts",
      -          "supersedes",
      -          "caused-by",
      -          "expires-on"
      -        ],
      -        "type": "string"
      -      },
      -      "src_id": {
      -        "description": "REQUIRED for unlink — source node shareable id.",
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug",
      -      "src_id",
      -      "dst_id",
      -      "relation"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "description": "destructive action \"restore_node_version\".",
      -    "properties": {
      -      "action": {
      -        "const": "restore_node_version",
      -        "description": "Run the restore_node_version action.",
      -        "type": "string"
      -      },
      -      "node_id": {
      -        "description": "Node shareable id (e.g. KNOW-42).",
      -        "type": "string"
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "version": {
      -        "description": "REQUIRED for restore_node_version — the version number to restore as the new live content.",
      -        "exclusiveMinimum": 0,
      -        "type": "integer"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug",
      -      "node_id",
      -      "version"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "description": "destructive action \"retire_objective\".",
      -    "properties": {
      -      "action": {
      -        "const": "retire_objective",
      -        "description": "Run the retire_objective action.",
      -        "type": "string"
      -      },
      -      "objective_id": {
      -        "description": "REQUIRED for retire_objective — the objective being retired (TASK-N).",
      -        "type": "string"
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "replaced_by": {
      -        "description": "(retire_objective only) Optional replacement objective (TASK-N) — records a `supersedes` edge.",
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug",
      -      "objective_id"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "description": "destructive action \"merge_workspace\".",
      -    "properties": {
      -      "action": {
      -        "const": "merge_workspace",
      -        "description": "Run the merge_workspace action.",
      -        "type": "string"
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "workspace": {
      -        "description": "REQUIRED for merge_workspace/cherry_pick_workspace/archive_workspace — the workspace to act on — its NAME (e.g. \"Billing\") or its uuid. NOT a short-id (workspaces aren't nodes).",
      -        "minLength": 1,
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug",
      -      "workspace"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "description": "destructive action \"cherry_pick_workspace\".",
      -    "properties": {
      -      "action": {
      -        "const": "cherry_pick_workspace",
      -        "description": "Run the cherry_pick_workspace action.",
      -        "type": "string"
      -      },
      -      "node_ids": {
      -        "description": "REQUIRED for cherry_pick_workspace — short-ids of the nodes to promote (KNOW-N / TASK-N / DOC-N / …). Only items currently scoped to this workspace are promoted.",
      -        "items": {
      -          "type": "string"
      -        },
      -        "minItems": 1,
      -        "type": "array"
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "workspace": {
      -        "description": "The workspace to act on — its NAME (e.g. \"Billing\") or its uuid. NOT a short-id (workspaces aren't nodes).",
      -        "minLength": 1,
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug",
      -      "workspace",
      -      "node_ids"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "description": "destructive action \"archive_workspace\".",
      -    "properties": {
      -      "action": {
      -        "const": "archive_workspace",
      -        "description": "Run the archive_workspace action.",
      -        "type": "string"
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "workspace": {
      -        "description": "REQUIRED for merge_workspace/cherry_pick_workspace/archive_workspace — the workspace to act on — its NAME (e.g. \"Billing\") or its uuid. NOT a short-id (workspaces aren't nodes).",
      -        "minLength": 1,
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug",
      -      "workspace"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "description": "destructive action \"archive_component\".",
      -    "properties": {
      -      "action": {
      -        "const": "archive_component",
      -        "description": "Run the archive_component action.",
      -        "type": "string"
      -      },
      -      "node_id": {
      -        "description": "Component shareable id to archive.",
      -        "type": "string"
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "reparent_children_to": {
      -        "description": "(archive_component only) Component to reparent active children under. Required if any active children exist.",
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug",
      -      "node_id"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "description": "destructive action \"merge_topics\".",
      -    "properties": {
      -      "action": {
      -        "const": "merge_topics",
      -        "description": "Run the merge_topics action.",
      -        "type": "string"
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "sources": {
      -        "description": "REQUIRED for merge_topics — list of source topics to merge into target. Must be non-empty.",
      -        "items": {
      -          "minLength": 1,
      -          "type": "string"
      -        },
      -        "minItems": 1,
      -        "type": "array"
      -      },
      -      "target": {
      -        "description": "REQUIRED for merge_topics — target topic. Must be non-empty.",
      -        "minLength": 1,
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug",
      -      "sources",
      -      "target"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "description": "destructive action \"run_loop_attempt\".",
      -    "properties": {
      -      "action": {
      -        "const": "run_loop_attempt",
      -        "description": "Run the run_loop_attempt action.",
      -        "type": "string"
      -      },
      -      "base": {
      -        "description": "Base git ref (default main).",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "branch": {
      -        "description": "Worker branch git ref (default HEAD).",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "command": {
      -        "description": "Exact declared check command. It is shown at the destructive approval boundary and must match the task contract.",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "node_id": {
      -        "description": "Task whose declared Check and Check paths form the loop contract.",
      -        "pattern": "^TASK-\\d+$",
      -        "type": "string"
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug",
      -      "node_id",
      -      "command"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "description": "destructive action \"doctor\".",
      -    "properties": {
      -      "action": {
      -        "const": "doctor",
      -        "description": "Run the doctor action.",
      -        "type": "string"
      -      },
      -      "deep": {
      -        "description": "(doctor only) Alias for `expensive`. Default false.",
      -        "type": "boolean"
      -      },
      -      "expensive": {
      -        "description": "(doctor only) Run costly checks too (fuzzy near-duplicate detection, folded into the duplicates bucket). Default false.",
      -        "type": "boolean"
      -      },
      -      "fix": {
      -        "description": "(doctor only) Apply safe auto-fixes (archive >90d-stale knowledge). Default false.",
      -        "type": "boolean"
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug"
      -    ],
      -    "type": "object"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": false,
      +    "description": "action=\"cancel_task\": Cancel a task (→ cancelled) with a required `reason` (appended to the body). For wrong/duplicate/obsolete tasks — not ones you merely couldn't finish (use release). Like complete, may surface nearby nodes to re-verify.",
      +    "properties": {
      +      "action": {
      +        "const": "cancel_task",
      +        "type": "string"
      +      },
      +      "node_id": {
      +        "description": "REQUIRED for cancel_task/force_claim_task/restore_node_version/archive_component — shareable id of the target (TASK-N / KNOW-N / COMP-N / …).",
      +        "type": "string"
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "reason": {
      +        "description": "REQUIRED for cancel_task — why this task is being cancelled.",
      +        "minLength": 1,
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug",
      +      "node_id",
      +      "reason"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "description": "action=\"force_claim_task\": Emergency override: take over a task in any state. Use only when the prior claimer is abandoned (check destructive(action=\"doctor\") first) or the user asks. Returns the prior claimer's identity so you can notify them; concurrent force-claims are last-write-wins.",
      +    "properties": {
      +      "action": {
      +        "const": "force_claim_task",
      +        "type": "string"
      +      },
      +      "dispatched_with": {
      +        "description": "(force_claim_task only) Operator's full briefing prompt when this force-claim is from a dispatched sub-agent. Up to 16 KB.",
      +        "type": "string"
      +      },
      +      "node_id": {
      +        "description": "Task shareable id (e.g. TASK-42).",
      +        "type": "string"
      +      },
      +      "parent_task_id": {
      +        "description": "(force_claim_task only) Operator's claimed task id when this force-claim is from a dispatched sub-agent. Leave null for direct claims.",
      +        "type": "string"
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug",
      +      "node_id"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "description": "action=\"dedupe_knowledge\": Find near-duplicate knowledge nodes by fuzzy title similarity (pg_trgm). Read-only — never deletes or merges; returns candidate pairs sorted by similarity for the caller to act on (use node(action=\"update\") to archive the dup side).",
      +    "properties": {
      +      "action": {
      +        "const": "dedupe_knowledge",
      +        "type": "string"
      +      },
      +      "category": {
      +        "description": "(dedupe_knowledge only) Restrict the scan to one knowledge category. Default: all categories.",
      +        "enum": [
      +          "decision",
      +          "architecture",
      +          "goal",
      +          "risk",
      +          "gap",
      +          "fyi",
      +          "opportunity",
      +          "priority",
      +          "lesson"
      +        ],
      +        "type": "string"
      +      },
      +      "limit": {
      +        "description": "(dedupe_knowledge only) Max pairs to return. Default 20.",
      +        "maximum": 200,
      +        "minimum": 1,
      +        "type": "integer"
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "threshold": {
      +        "description": "(dedupe_knowledge only) Similarity threshold (0–1). Default 0.7. Raise toward 1 for stricter matches.",
      +        "maximum": 1,
      +        "minimum": 0,
      +        "type": "number"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "description": "action=\"dedupe_pair\": Mark `drop_id` as a duplicate of `keep_id`. Atomically rewires every edge that touches the drop onto the keep (skipping conflicts on the unique (src,dst,relation) constraint), deletes any stragglers, archives the drop, and appends a `## Deduped` pointer to its body — all in one transaction. Returns the kept node and the pre-conflict count of edges that touched the drop. DESTRUCTIVE (the drop is archived). Find the candidate pair first (a duplicate scan or a search); this action merges one.",
      +    "properties": {
      +      "action": {
      +        "const": "dedupe_pair",
      +        "type": "string"
      +      },
      +      "drop_id": {
      +        "description": "REQUIRED for dedupe_pair — the duplicate to archive; its edges are rewired onto keep_id.",
      +        "type": "string"
      +      },
      +      "keep_id": {
      +        "description": "REQUIRED for dedupe_pair — the node to keep.",
      +        "type": "string"
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug",
      +      "keep_id",
      +      "drop_id"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "description": "action=\"unlink\": Remove the (src, dst, relation) edge if it exists; no-op if it doesn't. To preserve what the edge USED to mean, prefer link with `supersedes` over removing it.",
      +    "properties": {
      +      "action": {
      +        "const": "unlink",
      +        "type": "string"
      +      },
      +      "dst_id": {
      +        "description": "REQUIRED for unlink — destination node shareable id.",
      +        "type": "string"
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "relation": {
      +        "description": "REQUIRED for unlink — edge type to remove.",
      +        "enum": [
      +          "relates-to",
      +          "blocks",
      +          "fulfills",
      +          "contradicts",
      +          "supersedes",
      +          "caused-by",
      +          "expires-on"
      +        ],
      +        "type": "string"
      +      },
      +      "src_id": {
      +        "description": "REQUIRED for unlink — source node shareable id.",
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug",
      +      "src_id",
      +      "dst_id",
      +      "relation"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "description": "action=\"restore_node_version\": Restore a prior version's content as the new live content. APPEND, NEVER DESTRUCTIVE: restoring v2 over a live v3 writes v2 as a new live v4, snapshotting v3 into history first — both stay recoverable, so a bad restore is just another restore. Recorded with restored_from_version so history shows it was a restore, not a fresh edit.",
      +    "properties": {
      +      "action": {
      +        "const": "restore_node_version",
      +        "type": "string"
      +      },
      +      "node_id": {
      +        "description": "Node shareable id (e.g. KNOW-42).",
      +        "type": "string"
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "version": {
      +        "description": "REQUIRED for restore_node_version — the version number to restore as the new live content.",
      +        "exclusiveMinimum": 0,
      +        "type": "integer"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug",
      +      "node_id",
      +      "version"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "description": "action=\"retire_objective\": Retire an objective: cancels it (its status reads as 'superseded') and, when a replacement objective is named, records a `supersedes` edge so the chain stays navigable.",
      +    "properties": {
      +      "action": {
      +        "const": "retire_objective",
      +        "type": "string"
      +      },
      +      "objective_id": {
      +        "description": "REQUIRED for retire_objective — the objective being retired (TASK-N).",
      +        "type": "string"
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "replaced_by": {
      +        "description": "(retire_objective only) Optional replacement objective (TASK-N) — records a `supersedes` edge.",
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug",
      +      "objective_id"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "description": "action=\"merge_workspace\": Promote ALL of a workspace's scoped knowledge to trunk (shared truth), then mark the workspace 'merged'. Each promoted node flips to trunk and is stamped with provenance (which workspace + when). To graduate only SOME items, use destructive(action=\"cherry_pick_workspace\") instead. Permanent (domain) workspaces cannot be merged — they never graduate.",
      +    "properties": {
      +      "action": {
      +        "const": "merge_workspace",
      +        "type": "string"
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "workspace": {
      +        "description": "REQUIRED for merge_workspace/cherry_pick_workspace/archive_workspace — the workspace to act on — its NAME (e.g. \"Billing\") or its uuid. NOT a short-id (workspaces aren't nodes).",
      +        "minLength": 1,
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug",
      +      "workspace"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "description": "action=\"cherry_pick_workspace\": Promote ONLY the named knowledge/tasks from a workspace to trunk, leaving everything else scoped and the workspace active — the partial-merge / salvage case. Each promoted node flips to trunk and is stamped with provenance (which workspace + when). The workspace itself is NOT changed (archive or merge it separately). Ids not scoped to this workspace are ignored.",
      +    "properties": {
      +      "action": {
      +        "const": "cherry_pick_workspace",
      +        "type": "string"
      +      },
      +      "node_ids": {
      +        "description": "REQUIRED for cherry_pick_workspace — short-ids of the nodes to promote (KNOW-N / TASK-N / DOC-N / …). Only items currently scoped to this workspace are promoted.",
      +        "items": {
      +          "type": "string"
      +        },
      +        "minItems": 1,
      +        "type": "array"
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "workspace": {
      +        "description": "The workspace to act on — its NAME (e.g. \"Billing\") or its uuid. NOT a short-id (workspaces aren't nodes).",
      +        "minLength": 1,
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug",
      +      "workspace",
      +      "node_ids"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "description": "action=\"archive_workspace\": Archive a workspace (abandon it). RECOVERABLE — the workspace and ALL its scoped knowledge are kept as-is and can be reactivated; never deletes. Salvage anything worth keeping with destructive(action=\"cherry_pick_workspace\") FIRST — those items graduate to trunk and survive the archive.",
      +    "properties": {
      +      "action": {
      +        "const": "archive_workspace",
      +        "type": "string"
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "workspace": {
      +        "description": "REQUIRED for merge_workspace/cherry_pick_workspace/archive_workspace — the workspace to act on — its NAME (e.g. \"Billing\") or its uuid. NOT a short-id (workspaces aren't nodes).",
      +        "minLength": 1,
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug",
      +      "workspace"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "description": "action=\"archive_component\": Archive a component (soft-delete). If it has any ACTIVE children (sub-components, knowledge, or tasks), `reparent_children_to` is REQUIRED — they move to that target. We never silently orphan or cascade-delete.",
      +    "properties": {
      +      "action": {
      +        "const": "archive_component",
      +        "type": "string"
      +      },
      +      "node_id": {
      +        "description": "Component shareable id to archive.",
      +        "type": "string"
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "reparent_children_to": {
      +        "description": "(archive_component only) Component to reparent active children under. Required if any active children exist.",
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug",
      +      "node_id"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "description": "action=\"merge_topics\": Merge multiple source topics into a single target across every knowledge AND task node in the active project — like rename_topic once per source, in one transaction with the same dedup semantics. Sources equal to the target (or empty) are silently skipped. Members-only.",
      +    "properties": {
      +      "action": {
      +        "const": "merge_topics",
      +        "type": "string"
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "sources": {
      +        "description": "REQUIRED for merge_topics — list of source topics to merge into target. Must be non-empty.",
      +        "items": {
      +          "minLength": 1,
      +          "type": "string"
      +        },
      +        "minItems": 1,
      +        "type": "array"
      +      },
      +      "target": {
      +        "description": "REQUIRED for merge_topics — target topic. Must be non-empty.",
      +        "minLength": 1,
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug",
      +      "sources",
      +      "target"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "description": "action=\"run_loop_attempt\": Locally execute the task's declared Check in the worker branch's registered worktree, challenge its protected wrapper with a fresh nonce, accept only a versioned STELE_LOOP_EVIDENCE JSON line, persist exact counts/output on the task, and halt on the same failure twice or five failed attempts. Hosted MCP fails closed because it cannot execute the repository.",
      +    "properties": {
      +      "action": {
      +        "const": "run_loop_attempt",
      +        "type": "string"
      +      },
      +      "base": {
      +        "description": "Base git ref (default main).",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "branch": {
      +        "description": "Worker branch git ref (default HEAD).",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "command": {
      +        "description": "Exact declared check command. It is shown at the destructive approval boundary and must match the task contract.",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "node_id": {
      +        "description": "Task whose declared Check and Check paths form the loop contract.",
      +        "pattern": "^TASK-\\d+$",
      +        "type": "string"
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug",
      +      "node_id",
      +      "command"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "description": "action=\"doctor\": Run health checks on the active project, returning grouped issue buckets (stale/archivable/expired/superseded knowledge, stale claims, oversized/dangling/orphaned components, overdue or unbound risks, unverified load-bearing decisions, duplicates, empty bodies, over-fulfilled tasks). Run periodically — especially before destructive(action=\"force_claim_task\") on a task you suspect is abandoned. fix=true applies safe auto-fixes (archives archivable/expired/superseded knowledge and expire-on-close risks); all other buckets are reported only. expensive=true (alias deep=true) also runs costly fuzzy/trigram near-duplicate detection, folded into the duplicates bucket.",
      +    "properties": {
      +      "action": {
      +        "const": "doctor",
      +        "type": "string"
      +      },
      +      "deep": {
      +        "description": "(doctor only) Alias for `expensive`. Default false.",
      +        "type": "boolean"
      +      },
      +      "expensive": {
      +        "description": "(doctor only) Run costly checks too (fuzzy near-duplicate detection, folded into the duplicates bucket). Default false.",
      +        "type": "boolean"
      +      },
      +      "fix": {
      +        "description": "Apply safe auto-fixes: archive stale, expired and superseded knowledge, and risks bound to closed tasks. Default false.",
      +        "type": "boolean"
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug"
      +    ],
      +    "type": "object"
      +  }
      +]
  3. First observed

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With annotations already declaring destructiveHint=true, readOnlyHint=false, and openWorldHint=true, the description adds meaningful context: confirmation/caution expectations, the read-only nature of dedupe_knowledge, and run_loop_attempt's execution with a scrubbed environment under trusted local execution, failing closed on hosted MCP. It does not detail what each destructive action destroys or any auth/rate-limit behavior, keeping it from a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the safety/confirmation framing and then supplies the action enumeration, which is necessary for a multiplexer spanning many resources. It is dense but not padded, and the run_loop_attempt caveat is appropriately included. Slightly more structure could improve scanability across 14 actions.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the output schema exists and annotations cover the safety profile, the description provides enough context to understand the tool's overall purpose, the read-only dedupe_knowledge exception, and the special run_loop_attempt execution model. It does not enumerate what each destructive action does beyond its name, but the resource-bearing action names and rich schema make this reasonably complete for selection.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the detailed anyOf schema already documents per-action parameters thoroughly. The description adds only limited parameter-level meaning, mainly clarifying that action names carry resource context and that run_loop_attempt uses the exact declared shell command. That is a baseline 3 given the schema already does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly frames the tool as a collection of consequential actions requiring caution or confirmation, and lists every action name. It distinguishes the tool from siblings by noting that action names carry their resource because the tool spans resources, and it calls out dedupe_knowledge as a read-only exception. The only slight gap is that the opening phrase is abstract rather than a direct verb+resource statement, but the action list resolves that.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It states when the tool is relevant: operations requiring extra caution or confirmation. It also gives a specific exception for dedupe_knowledge (read-only candidate scan) and a condition for run_loop_attempt (trusted local repository execution; hosted MCP fails closed). It does not name alternative tools or provide broader when-not-to-use guidance, so it falls short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.