Skip to main content
Glama

Capture knowledge

knowledge

Capture or curate knowledge. action = create (file a typed fact — decision, lesson, risk, …) | review (mark a node re-verified against current reality). create files one fact under a component; it requires a lifecycle choice (expires_on_task, expires_at, due_at — pass null to skip each), and durable decisions and architecture usually skip all three. Merging duplicate knowledge lives in the destructive tool.

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=\"create\": Add a knowledge node under an existing active component (component_id is\nREQUIRED) — prefer an existing component over creating one. Search before\nadding: if a near-match exists, update it with node(action=\"update\") instead of duplicating. Always\ninclude topics (without them the node won't surface in topic queries) and link\nrelated nodes — isolated nodes are nearly invisible.\n\n## The knowledge categories\n\nPick the one that matches what the fact *is*, and give the body the shape it wants. Thin one-liners\ndilute the graph — a node that restates its own title helps nobody.\n\n| Category | It is | Body shape |\n|---|---|---|\n| `decision` | A choice that was made, and could have gone another way. | ## Context / ## Alternatives considered / ## Why this won / ## Consequences |\n| `architecture` | A structural fact about how the system is built. | ## What / ## How it works / ## Why this shape |\n| `goal` | What success looks like. | ## Outcome / ## Why it matters / ## How we'll know we're done |\n| `risk` | Something that might go wrong, and hasn't yet. | ## Risk / ## Likelihood & impact / ## Mitigation / ## Trigger |\n| `gap` | A known missing piece — real, but not yet work anyone has committed to. | ## Gap / ## Why it matters / ## What needs to happen to close it |\n| `lesson` | Something learned the hard way, usually from a failure. | ## Symptom / ## Root cause / ## Fix / ## Why this matters |\n| `opportunity` | Possible future work worth considering. | ## Opportunity / ## Why now / ## What it would take |\n| `priority` | What the focus is right now, and what it is not. | ## Focus / ## Why this and not X / ## Time horizon |\n| `fyi` | Context worth remembering that calls for no action. | A paragraph or two; short is fine. |\n\nTwo that get confused: a **`gap`** is a hole someone still has to decide what to do about; once the work\nis agreed it is a **task**, not a gap. A **`risk`** has not happened; a **`lesson`** already did.\n\n**A lesson from a bug is worth little without its trigger.** Put the literal error message, the failing\nsymbol, the command that broke, into the body. The graph resurfaces knowledge by matching it against\nwhat an agent is doing, so a lesson carrying the real error string reappears the moment someone hits that\nerror again. Worded abstractly, it stays invisible exactly when it would have helped.\n\n\nLIFECYCLE IS REQUIRED. Decide all three — expires_on_task, expires_at,\ndue_at — every time; pass null to skip any (durable decision/architecture\nusually skip all three). Bound nodes retire themselves, which is what keeps\nthe graph self-maintaining — that's why these aren't optional.",
      -    "properties": {
      -      "action": {
      -        "const": "create",
      -        "type": "string"
      -      },
      -      "anchor_files": {
      -        "description": "(create only) Repo-relative file paths this note is about (e.g. 'src/auth/session.ts'). When someone later edits a file named here, this node surfaces to them. Set it on a lesson/risk/gap scoped to specific code so it resurfaces exactly when that code is touched.",
      -        "items": {
      -          "type": "string"
      -        },
      -        "type": "array"
      -      },
      -      "anchor_symbols": {
      -        "description": "(create only) Symbol names this note is about — function / class / constant / env var (e.g. 'refreshToken', 'SESSION_TTL'). Same purpose as anchor_files: a precise hook so the note resurfaces when that symbol's code is touched.",
      -        "items": {
      -          "type": "string"
      -        },
      -        "type": "array"
      -      },
      -      "body": {
      -        "description": "(create only) Markdown body with sections that fit the category: a decision's context, alternatives, and why it won; a lesson's symptom, root cause, and fix; a risk's likelihood, impact, and mitigation. Thin one-sentence bodies are discouraged. Write it in plain style: one idea per sentence, active voice, lead with the condition, one term per concept, exact technical names.",
      -        "type": "string"
      -      },
      -      "category": {
      -        "description": "REQUIRED for create — what the fact is: decision (a choice that could have gone otherwise), architecture (how the system is built), goal, risk (may go wrong, hasn't yet), lesson (already went wrong; include the literal error or symbol), gap (missing, not yet committed work), opportunity, priority, fyi.",
      -        "enum": [
      -          "decision",
      -          "architecture",
      -          "goal",
      -          "risk",
      -          "gap",
      -          "fyi",
      -          "opportunity",
      -          "priority",
      -          "lesson"
      -        ],
      -        "type": "string"
      -      },
      -      "component_id": {
      -        "description": "REQUIRED for create — parent component shareable id.",
      -        "type": "string"
      -      },
      -      "due_at": {
      -        "anyOf": [
      -          {
      -            "anyOf": [
      -              {
      -                "type": "string"
      -              },
      -              {
      -                "const": "none",
      -                "type": "string"
      -              }
      -            ]
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "REQUIRED for create (pass null to skip) — a date (2026-12-31) or an ISO-8601 timestamp. A deadline; active knowledge past its due_at surfaces as an overdue commitment. Set it on anything carrying a real deadline. Distinct from expires_at (a reminder, never auto-archived)."
      -      },
      -      "expires_at": {
      -        "anyOf": [
      -          {
      -            "anyOf": [
      -              {
      -                "type": "string"
      -              },
      -              {
      -                "const": "none",
      -                "type": "string"
      -              }
      -            ]
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "REQUIRED for create (pass null to skip) — a date (2026-12-31) or an ISO-8601 timestamp (date TTL): once the date passes the node is reported as expired, and the next health-check run with fix archives it. Use it for EPHEMERAL knowledge (fyi notes, temporary workarounds). Do NOT set on decision/architecture (those retire by supersession, not a date)."
      -      },
      -      "expires_on_task": {
      -        "anyOf": [
      -          {
      -            "anyOf": [
      -              {
      -                "description": "Shareable id: TASK-N (task), KNOW-N (knowledge), COMP-N (component), DOC-N (document), or NODE-N (any).",
      -                "type": "string"
      -              },
      -              {
      -                "const": "none",
      -                "type": "string"
      -              }
      -            ],
      -            "description": "Shareable id: TASK-N (task), KNOW-N (knowledge), COMP-N (component), DOC-N (document), or NODE-N (any)."
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "REQUIRED for create (pass null to skip) — bind a TEMPORARY risk/gap to the OPEN task (TASK-N) that will resolve it: the node auto-archives when that task completes or cancels — no manual cleanup. Durable decisions/lessons/architecture must NOT bind (they retire by supersession, not a task closing) — pass null. Binding to an already-closed task is a dead trigger and is dropped with a warning."
      -      },
      -      "privacy_bypass": {
      -        "description": "true writes despite a privacy flag. Only meaningful after a flag; the user decides whether the content can be written.",
      -        "type": "boolean"
      -      },
      -      "privacy_false_positive": {
      -        "description": "With privacy_bypass: true reports the privacy flag as wrong.",
      -        "type": "boolean"
      -      },
      -      "privacy_judgement_id": {
      -        "description": "With privacy_bypass: the judgement_id the privacy flag returned.",
      -        "type": "string"
      -      },
      -      "privacy_note": {
      -        "description": "With privacy_bypass: an optional short reason, kept with the bypass.",
      -        "maxLength": 500,
      -        "type": "string"
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "scope": {
      -        "description": "(create only) Workspace scope. Omit or 'auto' = scope to the workspace mapped to the current git branch, else trunk (shared truth). 'trunk' = force shared truth even on a branch. Or pass a workspace name/id to target it. Branch-scoped writes are invisible to collaborators off that workspace.",
      -        "type": "string"
      -      },
      -      "source": {
      -        "description": "(create only) Optional free-form provenance label — where this fact came from. Conventional formats: 'workplace:cdi-fyi', 'meeting:1on1-aaron', 'pr:stele#117', 'doc:rfc-042'. Include this whenever the knowledge originates outside the agent's own reasoning (chat thread, meeting, doc, PR). Omit when the fact is derived from the agent reading code or running tools in this session.",
      -        "maxLength": 500,
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "source_type": {
      -        "description": "(create only) Provenance / trust signal. Defaults to 'claude' from MCP (agent-authored). Pass 'human' only when transcribing a user-verified fact, or 'import' for bulk-imported entries.",
      -        "enum": [
      -          "human",
      -          "claude",
      -          "import"
      -        ],
      -        "type": "string"
      -      },
      -      "source_url": {
      -        "description": "(create only) Optional canonical URL for the source — Slack permalink, PR url, doc link. Rendered as a link icon on the knowledge detail page.",
      -        "format": "uri",
      -        "type": "string"
      -      },
      -      "title": {
      -        "description": "REQUIRED for create — one-line summary.",
      -        "maxLength": 300,
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "topics": {
      -        "description": "(create only) Short tag list (\"oauth\", \"perf\", \"v2\").",
      -        "items": {
      -          "type": "string"
      -        },
      -        "type": "array"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug",
      -      "component_id",
      -      "category",
      -      "title",
      -      "expires_on_task",
      -      "due_at",
      -      "expires_at"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "description": "action=\"review\": Verify a knowledge node: record that you deliberately confirmed its claims are STILL TRUE against current reality, stamping `last_verified_at` to now. This verification axis is orthogonal to freshness — the only signal that catches a recently-written yet factually-wrong node. Actually check it first; if it's wrong, do NOT verify — use node(action=\"update\") or a supersedes edge instead. Does NOT change content, freshness, or source_type. Knowledge only; tasks/components are rejected.",
      -    "properties": {
      -      "action": {
      -        "const": "review",
      -        "type": "string"
      -      },
      -      "node_id": {
      -        "description": "REQUIRED for review — knowledge shareable id (e.g. KNOW-7). Tasks/components are rejected.",
      -        "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"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": false,
      +    "description": "knowledge action \"create\".",
      +    "properties": {
      +      "action": {
      +        "const": "create",
      +        "description": "Run the create action.",
      +        "type": "string"
      +      },
      +      "anchor_files": {
      +        "description": "(create only) Repo-relative file paths this note is about (e.g. 'src/auth/session.ts'). When someone later edits a file named here, this node surfaces to them. Set it on a lesson/risk/gap scoped to specific code so it resurfaces exactly when that code is touched.",
      +        "items": {
      +          "type": "string"
      +        },
      +        "type": "array"
      +      },
      +      "anchor_symbols": {
      +        "description": "(create only) Symbol names this note is about — function / class / constant / env var (e.g. 'refreshToken', 'SESSION_TTL'). Same purpose as anchor_files: a precise hook so the note resurfaces when that symbol's code is touched.",
      +        "items": {
      +          "type": "string"
      +        },
      +        "type": "array"
      +      },
      +      "body": {
      +        "description": "(create only) Markdown body with sections that fit the category: a decision's context, alternatives, and why it won; a lesson's symptom, root cause, and fix; a risk's likelihood, impact, and mitigation. Thin one-sentence bodies are discouraged. Write it in plain style: one idea per sentence, active voice, lead with the condition, one term per concept, exact technical names.",
      +        "type": "string"
      +      },
      +      "category": {
      +        "description": "REQUIRED for create — what the fact is: decision (a choice that could have gone otherwise), architecture (how the system is built), goal, risk (may go wrong, hasn't yet), lesson (already went wrong; include the literal error or symbol), gap (missing, not yet committed work), opportunity, priority, fyi.",
      +        "enum": [
      +          "decision",
      +          "architecture",
      +          "goal",
      +          "risk",
      +          "gap",
      +          "fyi",
      +          "opportunity",
      +          "priority",
      +          "lesson"
      +        ],
      +        "type": "string"
      +      },
      +      "component_id": {
      +        "description": "REQUIRED for create — parent component shareable id.",
      +        "type": "string"
      +      },
      +      "due_at": {
      +        "anyOf": [
      +          {
      +            "anyOf": [
      +              {
      +                "type": "string"
      +              },
      +              {
      +                "const": "none",
      +                "type": "string"
      +              }
      +            ]
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "REQUIRED for create (pass null to skip) — a date (2026-12-31) or an ISO-8601 timestamp. A deadline; active knowledge past its due_at surfaces as an overdue commitment. Set it on anything carrying a real deadline. Distinct from expires_at (a reminder, never auto-archived)."
      +      },
      +      "expires_at": {
      +        "anyOf": [
      +          {
      +            "anyOf": [
      +              {
      +                "type": "string"
      +              },
      +              {
      +                "const": "none",
      +                "type": "string"
      +              }
      +            ]
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "REQUIRED for create (pass null to skip) — a date (2026-12-31) or an ISO-8601 timestamp (date TTL): once the date passes the node is reported as expired, and the next health-check run with fix archives it. Use it for EPHEMERAL knowledge (fyi notes, temporary workarounds). Do NOT set on decision/architecture (those retire by supersession, not a date)."
      +      },
      +      "expires_on_task": {
      +        "anyOf": [
      +          {
      +            "anyOf": [
      +              {
      +                "description": "Shareable id: TASK-N (task), KNOW-N (knowledge), COMP-N (component), DOC-N (document), or NODE-N (any).",
      +                "type": "string"
      +              },
      +              {
      +                "const": "none",
      +                "type": "string"
      +              }
      +            ],
      +            "description": "Shareable id: TASK-N (task), KNOW-N (knowledge), COMP-N (component), DOC-N (document), or NODE-N (any)."
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "REQUIRED for create (pass null to skip) — bind a TEMPORARY risk/gap to the OPEN task (TASK-N) that will resolve it: the node auto-archives when that task completes or cancels — no manual cleanup. Durable decisions/lessons/architecture must NOT bind (they retire by supersession, not a task closing) — pass null. Binding to an already-closed task is a dead trigger and is dropped with a warning."
      +      },
      +      "privacy_bypass": {
      +        "description": "true writes despite a privacy flag. Only meaningful after a flag; the user decides whether the content can be written.",
      +        "type": "boolean"
      +      },
      +      "privacy_false_positive": {
      +        "description": "With privacy_bypass: true reports the privacy flag as wrong.",
      +        "type": "boolean"
      +      },
      +      "privacy_judgement_id": {
      +        "description": "With privacy_bypass: the judgement_id the privacy flag returned.",
      +        "type": "string"
      +      },
      +      "privacy_note": {
      +        "description": "With privacy_bypass: an optional short reason, kept with the bypass.",
      +        "maxLength": 500,
      +        "type": "string"
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "scope": {
      +        "description": "(create only) Workspace scope. Omit or 'auto' = scope to the workspace mapped to the current git branch, else trunk (shared truth). 'trunk' = force shared truth even on a branch. Or pass a workspace name/id to target it. Branch-scoped writes are invisible to collaborators off that workspace.",
      +        "type": "string"
      +      },
      +      "source": {
      +        "description": "(create only) Optional free-form provenance label — where this fact came from. Conventional formats: 'workplace:cdi-fyi', 'meeting:1on1-aaron', 'pr:stele#117', 'doc:rfc-042'. Include this whenever the knowledge originates outside the agent's own reasoning (chat thread, meeting, doc, PR). Omit when the fact is derived from the agent reading code or running tools in this session.",
      +        "maxLength": 500,
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "source_type": {
      +        "description": "(create only) Provenance / trust signal. Defaults to 'claude' from MCP (agent-authored). Pass 'human' only when transcribing a user-verified fact, or 'import' for bulk-imported entries.",
      +        "enum": [
      +          "human",
      +          "claude",
      +          "import"
      +        ],
      +        "type": "string"
      +      },
      +      "source_url": {
      +        "description": "(create only) Optional canonical URL for the source — Slack permalink, PR url, doc link. Rendered as a link icon on the knowledge detail page.",
      +        "format": "uri",
      +        "type": "string"
      +      },
      +      "title": {
      +        "description": "REQUIRED for create — one-line summary.",
      +        "maxLength": 300,
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "topics": {
      +        "description": "(create only) Short tag list (\"oauth\", \"perf\", \"v2\").",
      +        "items": {
      +          "type": "string"
      +        },
      +        "type": "array"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug",
      +      "component_id",
      +      "category",
      +      "title",
      +      "expires_on_task",
      +      "due_at",
      +      "expires_at"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "description": "knowledge action \"review\".",
      +    "properties": {
      +      "action": {
      +        "const": "review",
      +        "description": "Run the review action.",
      +        "type": "string"
      +      },
      +      "node_id": {
      +        "description": "REQUIRED for review — knowledge shareable id (e.g. KNOW-7). Tasks/components are rejected.",
      +        "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"
      +  }
      +]
  2. Changed1 schema field changed
    • changedInput schema / anyOf
      Previous value: -[
      -  {
      -    "additionalProperties": false,
      -    "description": "action=\"create\": Add a knowledge node under an existing active component (component_id is\nREQUIRED) — prefer an existing component over creating one. Search before\nadding: if a near-match exists, update it with node(action=\"update\") instead of duplicating. Always\ninclude topics (without them the node won't surface in topic queries) and link\nrelated nodes — isolated nodes are nearly invisible.\n\n## The knowledge categories\n\nPick the one that matches what the fact *is*, and give the body the shape it wants. Thin one-liners\ndilute the graph — a node that restates its own title helps nobody.\n\n| Category | It is | Body shape |\n|---|---|---|\n| `decision` | A choice that was made, and could have gone another way. | ## Context / ## Alternatives considered / ## Why this won / ## Consequences |\n| `architecture` | A structural fact about how the system is built. | ## What / ## How it works / ## Why this shape |\n| `goal` | What success looks like. | ## Outcome / ## Why it matters / ## How we'll know we're done |\n| `risk` | Something that might go wrong, and hasn't yet. | ## Risk / ## Likelihood & impact / ## Mitigation / ## Trigger |\n| `gap` | A known missing piece — real, but not yet work anyone has committed to. | ## Gap / ## Why it matters / ## What needs to happen to close it |\n| `lesson` | Something learned the hard way, usually from a failure. | ## Symptom / ## Root cause / ## Fix / ## Why this matters |\n| `opportunity` | Possible future work worth considering. | ## Opportunity / ## Why now / ## What it would take |\n| `priority` | What the focus is right now, and what it is not. | ## Focus / ## Why this and not X / ## Time horizon |\n| `fyi` | Context worth remembering that calls for no action. | A paragraph or two; short is fine. |\n\nTwo that get confused: a **`gap`** is a hole someone still has to decide what to do about; once the work\nis agreed it is a **task**, not a gap. A **`risk`** has not happened; a **`lesson`** already did.\n\n**A lesson from a bug is worth little without its trigger.** Put the literal error message, the failing\nsymbol, the command that broke, into the body. The graph resurfaces knowledge by matching it against\nwhat an agent is doing, so a lesson carrying the real error string reappears the moment someone hits that\nerror again. Worded abstractly, it stays invisible exactly when it would have helped.\n\n\nLIFECYCLE IS REQUIRED. Decide all three — expires_on_task, expires_at,\ndue_at — every time; pass null to skip any (durable decision/architecture\nusually skip all three). Bound nodes retire themselves, which is what keeps\nthe graph self-maintaining — that's why these aren't optional.",
      -    "properties": {
      -      "action": {
      -        "const": "create",
      -        "type": "string"
      -      },
      -      "anchor_files": {
      -        "description": "(create only) Repo-relative file paths this note is about (e.g. 'src/auth/session.ts'). When someone later edits a file named here, this node surfaces to them. Set it on a lesson/risk/gap scoped to specific code so it resurfaces exactly when that code is touched.",
      -        "items": {
      -          "type": "string"
      -        },
      -        "type": "array"
      -      },
      -      "anchor_symbols": {
      -        "description": "(create only) Symbol names this note is about — function / class / constant / env var (e.g. 'refreshToken', 'SESSION_TTL'). Same purpose as anchor_files: a precise hook so the note resurfaces when that symbol's code is touched.",
      -        "items": {
      -          "type": "string"
      -        },
      -        "type": "array"
      -      },
      -      "body": {
      -        "description": "(create only) Markdown body with sections that fit the category: a decision's context, alternatives, and why it won; a lesson's symptom, root cause, and fix; a risk's likelihood, impact, and mitigation. Thin one-sentence bodies are discouraged. Write it in plain style: one idea per sentence, active voice, lead with the condition, one term per concept, exact technical names.",
      -        "type": "string"
      -      },
      -      "category": {
      -        "description": "REQUIRED for create — what the fact is: decision (a choice that could have gone otherwise), architecture (how the system is built), goal, risk (may go wrong, hasn't yet), lesson (already went wrong; include the literal error or symbol), gap (missing, not yet committed work), opportunity, priority, fyi.",
      -        "enum": [
      -          "decision",
      -          "architecture",
      -          "goal",
      -          "risk",
      -          "gap",
      -          "fyi",
      -          "opportunity",
      -          "priority",
      -          "lesson"
      -        ],
      -        "type": "string"
      -      },
      -      "component_id": {
      -        "description": "REQUIRED for create — parent component shareable id.",
      -        "type": "string"
      -      },
      -      "due_at": {
      -        "anyOf": [
      -          {
      -            "anyOf": [
      -              {
      -                "type": "string"
      -              },
      -              {
      -                "const": "none",
      -                "type": "string"
      -              }
      -            ]
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "REQUIRED for create (pass null to skip) — a date (2026-12-31) or an ISO-8601 timestamp. A deadline; active knowledge past its due_at surfaces as an overdue commitment. Set it on anything carrying a real deadline. Distinct from expires_at (a reminder, never auto-archived)."
      -      },
      -      "expires_at": {
      -        "anyOf": [
      -          {
      -            "anyOf": [
      -              {
      -                "type": "string"
      -              },
      -              {
      -                "const": "none",
      -                "type": "string"
      -              }
      -            ]
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "REQUIRED for create (pass null to skip) — a date (2026-12-31) or an ISO-8601 timestamp (date TTL): once the date passes the node is reported as expired, and the next health-check run with fix archives it. Use it for EPHEMERAL knowledge (fyi notes, temporary workarounds). Do NOT set on decision/architecture (those retire by supersession, not a date)."
      -      },
      -      "expires_on_task": {
      -        "anyOf": [
      -          {
      -            "anyOf": [
      -              {
      -                "description": "Shareable id: TASK-N (task), KNOW-N (knowledge), COMP-N (component), DOC-N (document), or NODE-N (any).",
      -                "type": "string"
      -              },
      -              {
      -                "const": "none",
      -                "type": "string"
      -              }
      -            ],
      -            "description": "Shareable id: TASK-N (task), KNOW-N (knowledge), COMP-N (component), DOC-N (document), or NODE-N (any)."
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "REQUIRED for create (pass null to skip) — bind a TEMPORARY risk/gap to the OPEN task (TASK-N) that will resolve it: the node auto-archives when that task completes or cancels — no manual cleanup. Durable decisions/lessons/architecture must NOT bind (they retire by supersession, not a task closing) — pass null. Binding to an already-closed task is a dead trigger and is dropped with a warning."
      -      },
      -      "privacy_bypass": {
      -        "description": "true writes despite a privacy flag on a public project. Only meaningful after a flag; the user decides whether the content can be public.",
      -        "type": "boolean"
      -      },
      -      "privacy_false_positive": {
      -        "description": "With privacy_bypass: true reports the privacy flag as wrong.",
      -        "type": "boolean"
      -      },
      -      "privacy_judgement_id": {
      -        "description": "With privacy_bypass: the judgement_id the privacy flag returned.",
      -        "type": "string"
      -      },
      -      "privacy_note": {
      -        "description": "With privacy_bypass: an optional short reason, kept with the bypass.",
      -        "maxLength": 500,
      -        "type": "string"
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "scope": {
      -        "description": "(create only) Workspace scope. Omit or 'auto' = scope to the workspace mapped to the current git branch, else trunk (shared truth). 'trunk' = force shared truth even on a branch. Or pass a workspace name/id to target it. Branch-scoped writes are invisible to collaborators off that workspace.",
      -        "type": "string"
      -      },
      -      "source": {
      -        "description": "(create only) Optional free-form provenance label — where this fact came from. Conventional formats: 'workplace:cdi-fyi', 'meeting:1on1-aaron', 'pr:stele#117', 'doc:rfc-042'. Include this whenever the knowledge originates outside the agent's own reasoning (chat thread, meeting, doc, PR). Omit when the fact is derived from the agent reading code or running tools in this session.",
      -        "maxLength": 500,
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "source_type": {
      -        "description": "(create only) Provenance / trust signal. Defaults to 'claude' from MCP (agent-authored). Pass 'human' only when transcribing a user-verified fact, or 'import' for bulk-imported entries.",
      -        "enum": [
      -          "human",
      -          "claude",
      -          "import"
      -        ],
      -        "type": "string"
      -      },
      -      "source_url": {
      -        "description": "(create only) Optional canonical URL for the source — Slack permalink, PR url, doc link. Rendered as a link icon on the knowledge detail page.",
      -        "format": "uri",
      -        "type": "string"
      -      },
      -      "title": {
      -        "description": "REQUIRED for create — one-line summary.",
      -        "maxLength": 300,
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "topics": {
      -        "description": "(create only) Short tag list (\"oauth\", \"perf\", \"v2\").",
      -        "items": {
      -          "type": "string"
      -        },
      -        "type": "array"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug",
      -      "component_id",
      -      "category",
      -      "title",
      -      "expires_on_task",
      -      "due_at",
      -      "expires_at"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "description": "action=\"review\": Verify a knowledge node: record that you deliberately confirmed its claims are STILL TRUE against current reality, stamping `last_verified_at` to now. This verification axis is orthogonal to freshness — the only signal that catches a recently-written yet factually-wrong node. Actually check it first; if it's wrong, do NOT verify — use node(action=\"update\") or a supersedes edge instead. Does NOT change content, freshness, or source_type. Knowledge only; tasks/components are rejected.",
      -    "properties": {
      -      "action": {
      -        "const": "review",
      -        "type": "string"
      -      },
      -      "node_id": {
      -        "description": "REQUIRED for review — knowledge shareable id (e.g. KNOW-7). Tasks/components are rejected.",
      -        "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"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": false,
      +    "description": "action=\"create\": Add a knowledge node under an existing active component (component_id is\nREQUIRED) — prefer an existing component over creating one. Search before\nadding: if a near-match exists, update it with node(action=\"update\") instead of duplicating. Always\ninclude topics (without them the node won't surface in topic queries) and link\nrelated nodes — isolated nodes are nearly invisible.\n\n## The knowledge categories\n\nPick the one that matches what the fact *is*, and give the body the shape it wants. Thin one-liners\ndilute the graph — a node that restates its own title helps nobody.\n\n| Category | It is | Body shape |\n|---|---|---|\n| `decision` | A choice that was made, and could have gone another way. | ## Context / ## Alternatives considered / ## Why this won / ## Consequences |\n| `architecture` | A structural fact about how the system is built. | ## What / ## How it works / ## Why this shape |\n| `goal` | What success looks like. | ## Outcome / ## Why it matters / ## How we'll know we're done |\n| `risk` | Something that might go wrong, and hasn't yet. | ## Risk / ## Likelihood & impact / ## Mitigation / ## Trigger |\n| `gap` | A known missing piece — real, but not yet work anyone has committed to. | ## Gap / ## Why it matters / ## What needs to happen to close it |\n| `lesson` | Something learned the hard way, usually from a failure. | ## Symptom / ## Root cause / ## Fix / ## Why this matters |\n| `opportunity` | Possible future work worth considering. | ## Opportunity / ## Why now / ## What it would take |\n| `priority` | What the focus is right now, and what it is not. | ## Focus / ## Why this and not X / ## Time horizon |\n| `fyi` | Context worth remembering that calls for no action. | A paragraph or two; short is fine. |\n\nTwo that get confused: a **`gap`** is a hole someone still has to decide what to do about; once the work\nis agreed it is a **task**, not a gap. A **`risk`** has not happened; a **`lesson`** already did.\n\n**A lesson from a bug is worth little without its trigger.** Put the literal error message, the failing\nsymbol, the command that broke, into the body. The graph resurfaces knowledge by matching it against\nwhat an agent is doing, so a lesson carrying the real error string reappears the moment someone hits that\nerror again. Worded abstractly, it stays invisible exactly when it would have helped.\n\n\nLIFECYCLE IS REQUIRED. Decide all three — expires_on_task, expires_at,\ndue_at — every time; pass null to skip any (durable decision/architecture\nusually skip all three). Bound nodes retire themselves, which is what keeps\nthe graph self-maintaining — that's why these aren't optional.",
      +    "properties": {
      +      "action": {
      +        "const": "create",
      +        "type": "string"
      +      },
      +      "anchor_files": {
      +        "description": "(create only) Repo-relative file paths this note is about (e.g. 'src/auth/session.ts'). When someone later edits a file named here, this node surfaces to them. Set it on a lesson/risk/gap scoped to specific code so it resurfaces exactly when that code is touched.",
      +        "items": {
      +          "type": "string"
      +        },
      +        "type": "array"
      +      },
      +      "anchor_symbols": {
      +        "description": "(create only) Symbol names this note is about — function / class / constant / env var (e.g. 'refreshToken', 'SESSION_TTL'). Same purpose as anchor_files: a precise hook so the note resurfaces when that symbol's code is touched.",
      +        "items": {
      +          "type": "string"
      +        },
      +        "type": "array"
      +      },
      +      "body": {
      +        "description": "(create only) Markdown body with sections that fit the category: a decision's context, alternatives, and why it won; a lesson's symptom, root cause, and fix; a risk's likelihood, impact, and mitigation. Thin one-sentence bodies are discouraged. Write it in plain style: one idea per sentence, active voice, lead with the condition, one term per concept, exact technical names.",
      +        "type": "string"
      +      },
      +      "category": {
      +        "description": "REQUIRED for create — what the fact is: decision (a choice that could have gone otherwise), architecture (how the system is built), goal, risk (may go wrong, hasn't yet), lesson (already went wrong; include the literal error or symbol), gap (missing, not yet committed work), opportunity, priority, fyi.",
      +        "enum": [
      +          "decision",
      +          "architecture",
      +          "goal",
      +          "risk",
      +          "gap",
      +          "fyi",
      +          "opportunity",
      +          "priority",
      +          "lesson"
      +        ],
      +        "type": "string"
      +      },
      +      "component_id": {
      +        "description": "REQUIRED for create — parent component shareable id.",
      +        "type": "string"
      +      },
      +      "due_at": {
      +        "anyOf": [
      +          {
      +            "anyOf": [
      +              {
      +                "type": "string"
      +              },
      +              {
      +                "const": "none",
      +                "type": "string"
      +              }
      +            ]
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "REQUIRED for create (pass null to skip) — a date (2026-12-31) or an ISO-8601 timestamp. A deadline; active knowledge past its due_at surfaces as an overdue commitment. Set it on anything carrying a real deadline. Distinct from expires_at (a reminder, never auto-archived)."
      +      },
      +      "expires_at": {
      +        "anyOf": [
      +          {
      +            "anyOf": [
      +              {
      +                "type": "string"
      +              },
      +              {
      +                "const": "none",
      +                "type": "string"
      +              }
      +            ]
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "REQUIRED for create (pass null to skip) — a date (2026-12-31) or an ISO-8601 timestamp (date TTL): once the date passes the node is reported as expired, and the next health-check run with fix archives it. Use it for EPHEMERAL knowledge (fyi notes, temporary workarounds). Do NOT set on decision/architecture (those retire by supersession, not a date)."
      +      },
      +      "expires_on_task": {
      +        "anyOf": [
      +          {
      +            "anyOf": [
      +              {
      +                "description": "Shareable id: TASK-N (task), KNOW-N (knowledge), COMP-N (component), DOC-N (document), or NODE-N (any).",
      +                "type": "string"
      +              },
      +              {
      +                "const": "none",
      +                "type": "string"
      +              }
      +            ],
      +            "description": "Shareable id: TASK-N (task), KNOW-N (knowledge), COMP-N (component), DOC-N (document), or NODE-N (any)."
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "REQUIRED for create (pass null to skip) — bind a TEMPORARY risk/gap to the OPEN task (TASK-N) that will resolve it: the node auto-archives when that task completes or cancels — no manual cleanup. Durable decisions/lessons/architecture must NOT bind (they retire by supersession, not a task closing) — pass null. Binding to an already-closed task is a dead trigger and is dropped with a warning."
      +      },
      +      "privacy_bypass": {
      +        "description": "true writes despite a privacy flag. Only meaningful after a flag; the user decides whether the content can be written.",
      +        "type": "boolean"
      +      },
      +      "privacy_false_positive": {
      +        "description": "With privacy_bypass: true reports the privacy flag as wrong.",
      +        "type": "boolean"
      +      },
      +      "privacy_judgement_id": {
      +        "description": "With privacy_bypass: the judgement_id the privacy flag returned.",
      +        "type": "string"
      +      },
      +      "privacy_note": {
      +        "description": "With privacy_bypass: an optional short reason, kept with the bypass.",
      +        "maxLength": 500,
      +        "type": "string"
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "scope": {
      +        "description": "(create only) Workspace scope. Omit or 'auto' = scope to the workspace mapped to the current git branch, else trunk (shared truth). 'trunk' = force shared truth even on a branch. Or pass a workspace name/id to target it. Branch-scoped writes are invisible to collaborators off that workspace.",
      +        "type": "string"
      +      },
      +      "source": {
      +        "description": "(create only) Optional free-form provenance label — where this fact came from. Conventional formats: 'workplace:cdi-fyi', 'meeting:1on1-aaron', 'pr:stele#117', 'doc:rfc-042'. Include this whenever the knowledge originates outside the agent's own reasoning (chat thread, meeting, doc, PR). Omit when the fact is derived from the agent reading code or running tools in this session.",
      +        "maxLength": 500,
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "source_type": {
      +        "description": "(create only) Provenance / trust signal. Defaults to 'claude' from MCP (agent-authored). Pass 'human' only when transcribing a user-verified fact, or 'import' for bulk-imported entries.",
      +        "enum": [
      +          "human",
      +          "claude",
      +          "import"
      +        ],
      +        "type": "string"
      +      },
      +      "source_url": {
      +        "description": "(create only) Optional canonical URL for the source — Slack permalink, PR url, doc link. Rendered as a link icon on the knowledge detail page.",
      +        "format": "uri",
      +        "type": "string"
      +      },
      +      "title": {
      +        "description": "REQUIRED for create — one-line summary.",
      +        "maxLength": 300,
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "topics": {
      +        "description": "(create only) Short tag list (\"oauth\", \"perf\", \"v2\").",
      +        "items": {
      +          "type": "string"
      +        },
      +        "type": "array"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug",
      +      "component_id",
      +      "category",
      +      "title",
      +      "expires_on_task",
      +      "due_at",
      +      "expires_at"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "description": "action=\"review\": Verify a knowledge node: record that you deliberately confirmed its claims are STILL TRUE against current reality, stamping `last_verified_at` to now. This verification axis is orthogonal to freshness — the only signal that catches a recently-written yet factually-wrong node. Actually check it first; if it's wrong, do NOT verify — use node(action=\"update\") or a supersedes edge instead. Does NOT change content, freshness, or source_type. Knowledge only; tasks/components are rejected.",
      +    "properties": {
      +      "action": {
      +        "const": "review",
      +        "type": "string"
      +      },
      +      "node_id": {
      +        "description": "REQUIRED for review — knowledge shareable id (e.g. KNOW-7). Tasks/components are rejected.",
      +        "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"
      +  }
      +]
  3. Changed1 schema field changed
    • changedInput schema / anyOf
      Previous value: -[
      -  {
      -    "additionalProperties": false,
      -    "description": "action=\"create\": Add a knowledge node under an existing active component (component_id is\nREQUIRED) — prefer an existing component over creating one. Search before\nadding: if a near-match exists, update it with node(action=\"update\") instead of duplicating. Always\ninclude topics (without them the node won't surface in topic queries) and link\nrelated nodes — isolated nodes are nearly invisible.\n\n## The knowledge categories\n\nPick the one that matches what the fact *is*, and give the body the shape it wants. Thin one-liners\ndilute the graph — a node that restates its own title helps nobody.\n\n| Category | It is | Body shape |\n|---|---|---|\n| `decision` | A choice that was made, and could have gone another way. | ## Context / ## Alternatives considered / ## Why this won / ## Consequences |\n| `architecture` | A structural fact about how the system is built. | ## What / ## How it works / ## Why this shape |\n| `goal` | What success looks like. | ## Outcome / ## Why it matters / ## How we'll know we're done |\n| `risk` | Something that might go wrong, and hasn't yet. | ## Risk / ## Likelihood & impact / ## Mitigation / ## Trigger |\n| `gap` | A known missing piece — real, but not yet work anyone has committed to. | ## Gap / ## Why it matters / ## What needs to happen to close it |\n| `lesson` | Something learned the hard way, usually from a failure. | ## Symptom / ## Root cause / ## Fix / ## Why this matters |\n| `opportunity` | Possible future work worth considering. | ## Opportunity / ## Why now / ## What it would take |\n| `priority` | What the focus is right now, and what it is not. | ## Focus / ## Why this and not X / ## Time horizon |\n| `fyi` | Context worth remembering that calls for no action. | A paragraph or two; short is fine. |\n\nTwo that get confused: a **`gap`** is a hole someone still has to decide what to do about; once the work\nis agreed it is a **task**, not a gap. A **`risk`** has not happened; a **`lesson`** already did.\n\n**A lesson from a bug is worth little without its trigger.** Put the literal error message, the failing\nsymbol, the command that broke, into the body. The graph resurfaces knowledge by matching it against\nwhat an agent is doing, so a lesson carrying the real error string reappears the moment someone hits that\nerror again. Worded abstractly, it stays invisible exactly when it would have helped.\n\n\nLIFECYCLE IS REQUIRED. Decide all three — expires_on_task, expires_at,\ndue_at — every time; pass null to skip any (durable decision/architecture\nusually skip all three). Bound nodes retire themselves, which is what keeps\nthe graph self-maintaining — that's why these aren't optional.",
      -    "properties": {
      -      "action": {
      -        "const": "create",
      -        "type": "string"
      -      },
      -      "anchor_files": {
      -        "description": "(create only) Repo-relative file paths this note is about (e.g. 'src/auth/session.ts'). When someone later edits a file named here, this node surfaces to them. Set it on a lesson/risk/gap scoped to specific code so it resurfaces exactly when that code is touched.",
      -        "items": {
      -          "type": "string"
      -        },
      -        "type": "array"
      -      },
      -      "anchor_symbols": {
      -        "description": "(create only) Symbol names this note is about — function / class / constant / env var (e.g. 'refreshToken', 'SESSION_TTL'). Same purpose as anchor_files: a precise hook so the note resurfaces when that symbol's code is touched.",
      -        "items": {
      -          "type": "string"
      -        },
      -        "type": "array"
      -      },
      -      "body": {
      -        "description": "(create only) Markdown body with sections that fit the category: a decision's context, alternatives, and why it won; a lesson's symptom, root cause, and fix; a risk's likelihood, impact, and mitigation. Thin one-sentence bodies are discouraged. Write it in plain style: one idea per sentence, active voice, lead with the condition, one term per concept, exact technical names.",
      -        "type": "string"
      -      },
      -      "category": {
      -        "description": "REQUIRED for create — what the fact is: decision (a choice that could have gone otherwise), architecture (how the system is built), goal, risk (may go wrong, hasn't yet), lesson (already went wrong; include the literal error or symbol), gap (missing, not yet committed work), opportunity, priority, fyi.",
      -        "enum": [
      -          "decision",
      -          "architecture",
      -          "goal",
      -          "risk",
      -          "gap",
      -          "fyi",
      -          "opportunity",
      -          "priority",
      -          "lesson"
      -        ],
      -        "type": "string"
      -      },
      -      "component_id": {
      -        "description": "REQUIRED for create — parent component shareable id.",
      -        "type": "string"
      -      },
      -      "due_at": {
      -        "anyOf": [
      -          {
      -            "anyOf": [
      -              {
      -                "type": "string"
      -              },
      -              {
      -                "const": "none",
      -                "type": "string"
      -              }
      -            ]
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "REQUIRED for create (pass null to skip) — a date (2026-12-31) or an ISO-8601 timestamp. A deadline; active knowledge past its due_at surfaces as an overdue commitment. Set it on anything carrying a real deadline. Distinct from expires_at (a reminder, never auto-archived)."
      -      },
      -      "expires_at": {
      -        "anyOf": [
      -          {
      -            "anyOf": [
      -              {
      -                "type": "string"
      -              },
      -              {
      -                "const": "none",
      -                "type": "string"
      -              }
      -            ]
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "REQUIRED for create (pass null to skip) — a date (2026-12-31) or an ISO-8601 timestamp (date TTL): once the date passes the node is reported as expired, and the next health-check run with fix archives it. Use it for EPHEMERAL knowledge (fyi notes, temporary workarounds). Do NOT set on decision/architecture (those retire by supersession, not a date)."
      -      },
      -      "expires_on_task": {
      -        "anyOf": [
      -          {
      -            "anyOf": [
      -              {
      -                "description": "Shareable id: TASK-N (task), KNOW-N (knowledge), COMP-N (component), DOC-N (document), or NODE-N (any).",
      -                "type": "string"
      -              },
      -              {
      -                "const": "none",
      -                "type": "string"
      -              }
      -            ],
      -            "description": "Shareable id: TASK-N (task), KNOW-N (knowledge), COMP-N (component), DOC-N (document), or NODE-N (any)."
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "REQUIRED for create (pass null to skip) — bind a TEMPORARY risk/gap to the OPEN task (TASK-N) that will resolve it: the node auto-archives when that task completes or cancels — no manual cleanup. Durable decisions/lessons/architecture must NOT bind (they retire by supersession, not a task closing) — pass null. Binding to an already-closed task is a dead trigger and is dropped with a warning."
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "scope": {
      -        "description": "(create only) Workspace scope. Omit or 'auto' = scope to the workspace mapped to the current git branch, else trunk (shared truth). 'trunk' = force shared truth even on a branch. Or pass a workspace name/id to target it. Branch-scoped writes are invisible to collaborators off that workspace.",
      -        "type": "string"
      -      },
      -      "source": {
      -        "description": "(create only) Optional free-form provenance label — where this fact came from. Conventional formats: 'workplace:cdi-fyi', 'meeting:1on1-aaron', 'pr:stele#117', 'doc:rfc-042'. Include this whenever the knowledge originates outside the agent's own reasoning (chat thread, meeting, doc, PR). Omit when the fact is derived from the agent reading code or running tools in this session.",
      -        "maxLength": 500,
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "source_type": {
      -        "description": "(create only) Provenance / trust signal. Defaults to 'claude' from MCP (agent-authored). Pass 'human' only when transcribing a user-verified fact, or 'import' for bulk-imported entries.",
      -        "enum": [
      -          "human",
      -          "claude",
      -          "import"
      -        ],
      -        "type": "string"
      -      },
      -      "source_url": {
      -        "description": "(create only) Optional canonical URL for the source — Slack permalink, PR url, doc link. Rendered as a link icon on the knowledge detail page.",
      -        "format": "uri",
      -        "type": "string"
      -      },
      -      "title": {
      -        "description": "REQUIRED for create — one-line summary.",
      -        "maxLength": 300,
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "topics": {
      -        "description": "(create only) Short tag list (\"oauth\", \"perf\", \"v2\").",
      -        "items": {
      -          "type": "string"
      -        },
      -        "type": "array"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug",
      -      "component_id",
      -      "category",
      -      "title",
      -      "expires_on_task",
      -      "due_at",
      -      "expires_at"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "description": "action=\"review\": Verify a knowledge node: record that you deliberately confirmed its claims are STILL TRUE against current reality, stamping `last_verified_at` to now. This verification axis is orthogonal to freshness — the only signal that catches a recently-written yet factually-wrong node. Actually check it first; if it's wrong, do NOT verify — use node(action=\"update\") or a supersedes edge instead. Does NOT change content, freshness, or source_type. Knowledge only; tasks/components are rejected.",
      -    "properties": {
      -      "action": {
      -        "const": "review",
      -        "type": "string"
      -      },
      -      "node_id": {
      -        "description": "REQUIRED for review — knowledge shareable id (e.g. KNOW-7). Tasks/components are rejected.",
      -        "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"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": false,
      +    "description": "action=\"create\": Add a knowledge node under an existing active component (component_id is\nREQUIRED) — prefer an existing component over creating one. Search before\nadding: if a near-match exists, update it with node(action=\"update\") instead of duplicating. Always\ninclude topics (without them the node won't surface in topic queries) and link\nrelated nodes — isolated nodes are nearly invisible.\n\n## The knowledge categories\n\nPick the one that matches what the fact *is*, and give the body the shape it wants. Thin one-liners\ndilute the graph — a node that restates its own title helps nobody.\n\n| Category | It is | Body shape |\n|---|---|---|\n| `decision` | A choice that was made, and could have gone another way. | ## Context / ## Alternatives considered / ## Why this won / ## Consequences |\n| `architecture` | A structural fact about how the system is built. | ## What / ## How it works / ## Why this shape |\n| `goal` | What success looks like. | ## Outcome / ## Why it matters / ## How we'll know we're done |\n| `risk` | Something that might go wrong, and hasn't yet. | ## Risk / ## Likelihood & impact / ## Mitigation / ## Trigger |\n| `gap` | A known missing piece — real, but not yet work anyone has committed to. | ## Gap / ## Why it matters / ## What needs to happen to close it |\n| `lesson` | Something learned the hard way, usually from a failure. | ## Symptom / ## Root cause / ## Fix / ## Why this matters |\n| `opportunity` | Possible future work worth considering. | ## Opportunity / ## Why now / ## What it would take |\n| `priority` | What the focus is right now, and what it is not. | ## Focus / ## Why this and not X / ## Time horizon |\n| `fyi` | Context worth remembering that calls for no action. | A paragraph or two; short is fine. |\n\nTwo that get confused: a **`gap`** is a hole someone still has to decide what to do about; once the work\nis agreed it is a **task**, not a gap. A **`risk`** has not happened; a **`lesson`** already did.\n\n**A lesson from a bug is worth little without its trigger.** Put the literal error message, the failing\nsymbol, the command that broke, into the body. The graph resurfaces knowledge by matching it against\nwhat an agent is doing, so a lesson carrying the real error string reappears the moment someone hits that\nerror again. Worded abstractly, it stays invisible exactly when it would have helped.\n\n\nLIFECYCLE IS REQUIRED. Decide all three — expires_on_task, expires_at,\ndue_at — every time; pass null to skip any (durable decision/architecture\nusually skip all three). Bound nodes retire themselves, which is what keeps\nthe graph self-maintaining — that's why these aren't optional.",
      +    "properties": {
      +      "action": {
      +        "const": "create",
      +        "type": "string"
      +      },
      +      "anchor_files": {
      +        "description": "(create only) Repo-relative file paths this note is about (e.g. 'src/auth/session.ts'). When someone later edits a file named here, this node surfaces to them. Set it on a lesson/risk/gap scoped to specific code so it resurfaces exactly when that code is touched.",
      +        "items": {
      +          "type": "string"
      +        },
      +        "type": "array"
      +      },
      +      "anchor_symbols": {
      +        "description": "(create only) Symbol names this note is about — function / class / constant / env var (e.g. 'refreshToken', 'SESSION_TTL'). Same purpose as anchor_files: a precise hook so the note resurfaces when that symbol's code is touched.",
      +        "items": {
      +          "type": "string"
      +        },
      +        "type": "array"
      +      },
      +      "body": {
      +        "description": "(create only) Markdown body with sections that fit the category: a decision's context, alternatives, and why it won; a lesson's symptom, root cause, and fix; a risk's likelihood, impact, and mitigation. Thin one-sentence bodies are discouraged. Write it in plain style: one idea per sentence, active voice, lead with the condition, one term per concept, exact technical names.",
      +        "type": "string"
      +      },
      +      "category": {
      +        "description": "REQUIRED for create — what the fact is: decision (a choice that could have gone otherwise), architecture (how the system is built), goal, risk (may go wrong, hasn't yet), lesson (already went wrong; include the literal error or symbol), gap (missing, not yet committed work), opportunity, priority, fyi.",
      +        "enum": [
      +          "decision",
      +          "architecture",
      +          "goal",
      +          "risk",
      +          "gap",
      +          "fyi",
      +          "opportunity",
      +          "priority",
      +          "lesson"
      +        ],
      +        "type": "string"
      +      },
      +      "component_id": {
      +        "description": "REQUIRED for create — parent component shareable id.",
      +        "type": "string"
      +      },
      +      "due_at": {
      +        "anyOf": [
      +          {
      +            "anyOf": [
      +              {
      +                "type": "string"
      +              },
      +              {
      +                "const": "none",
      +                "type": "string"
      +              }
      +            ]
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "REQUIRED for create (pass null to skip) — a date (2026-12-31) or an ISO-8601 timestamp. A deadline; active knowledge past its due_at surfaces as an overdue commitment. Set it on anything carrying a real deadline. Distinct from expires_at (a reminder, never auto-archived)."
      +      },
      +      "expires_at": {
      +        "anyOf": [
      +          {
      +            "anyOf": [
      +              {
      +                "type": "string"
      +              },
      +              {
      +                "const": "none",
      +                "type": "string"
      +              }
      +            ]
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "REQUIRED for create (pass null to skip) — a date (2026-12-31) or an ISO-8601 timestamp (date TTL): once the date passes the node is reported as expired, and the next health-check run with fix archives it. Use it for EPHEMERAL knowledge (fyi notes, temporary workarounds). Do NOT set on decision/architecture (those retire by supersession, not a date)."
      +      },
      +      "expires_on_task": {
      +        "anyOf": [
      +          {
      +            "anyOf": [
      +              {
      +                "description": "Shareable id: TASK-N (task), KNOW-N (knowledge), COMP-N (component), DOC-N (document), or NODE-N (any).",
      +                "type": "string"
      +              },
      +              {
      +                "const": "none",
      +                "type": "string"
      +              }
      +            ],
      +            "description": "Shareable id: TASK-N (task), KNOW-N (knowledge), COMP-N (component), DOC-N (document), or NODE-N (any)."
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "REQUIRED for create (pass null to skip) — bind a TEMPORARY risk/gap to the OPEN task (TASK-N) that will resolve it: the node auto-archives when that task completes or cancels — no manual cleanup. Durable decisions/lessons/architecture must NOT bind (they retire by supersession, not a task closing) — pass null. Binding to an already-closed task is a dead trigger and is dropped with a warning."
      +      },
      +      "privacy_bypass": {
      +        "description": "true writes despite a privacy flag on a public project. Only meaningful after a flag; the user decides whether the content can be public.",
      +        "type": "boolean"
      +      },
      +      "privacy_false_positive": {
      +        "description": "With privacy_bypass: true reports the privacy flag as wrong.",
      +        "type": "boolean"
      +      },
      +      "privacy_judgement_id": {
      +        "description": "With privacy_bypass: the judgement_id the privacy flag returned.",
      +        "type": "string"
      +      },
      +      "privacy_note": {
      +        "description": "With privacy_bypass: an optional short reason, kept with the bypass.",
      +        "maxLength": 500,
      +        "type": "string"
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "scope": {
      +        "description": "(create only) Workspace scope. Omit or 'auto' = scope to the workspace mapped to the current git branch, else trunk (shared truth). 'trunk' = force shared truth even on a branch. Or pass a workspace name/id to target it. Branch-scoped writes are invisible to collaborators off that workspace.",
      +        "type": "string"
      +      },
      +      "source": {
      +        "description": "(create only) Optional free-form provenance label — where this fact came from. Conventional formats: 'workplace:cdi-fyi', 'meeting:1on1-aaron', 'pr:stele#117', 'doc:rfc-042'. Include this whenever the knowledge originates outside the agent's own reasoning (chat thread, meeting, doc, PR). Omit when the fact is derived from the agent reading code or running tools in this session.",
      +        "maxLength": 500,
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "source_type": {
      +        "description": "(create only) Provenance / trust signal. Defaults to 'claude' from MCP (agent-authored). Pass 'human' only when transcribing a user-verified fact, or 'import' for bulk-imported entries.",
      +        "enum": [
      +          "human",
      +          "claude",
      +          "import"
      +        ],
      +        "type": "string"
      +      },
      +      "source_url": {
      +        "description": "(create only) Optional canonical URL for the source — Slack permalink, PR url, doc link. Rendered as a link icon on the knowledge detail page.",
      +        "format": "uri",
      +        "type": "string"
      +      },
      +      "title": {
      +        "description": "REQUIRED for create — one-line summary.",
      +        "maxLength": 300,
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "topics": {
      +        "description": "(create only) Short tag list (\"oauth\", \"perf\", \"v2\").",
      +        "items": {
      +          "type": "string"
      +        },
      +        "type": "array"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug",
      +      "component_id",
      +      "category",
      +      "title",
      +      "expires_on_task",
      +      "due_at",
      +      "expires_at"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "description": "action=\"review\": Verify a knowledge node: record that you deliberately confirmed its claims are STILL TRUE against current reality, stamping `last_verified_at` to now. This verification axis is orthogonal to freshness — the only signal that catches a recently-written yet factually-wrong node. Actually check it first; if it's wrong, do NOT verify — use node(action=\"update\") or a supersedes edge instead. Does NOT change content, freshness, or source_type. Knowledge only; tasks/components are rejected.",
      +    "properties": {
      +      "action": {
      +        "const": "review",
      +        "type": "string"
      +      },
      +      "node_id": {
      +        "description": "REQUIRED for review — knowledge shareable id (e.g. KNOW-7). Tasks/components are rejected.",
      +        "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"
      +  }
      +]
  4. Changed1 schema field changed
    • changedInput schema / anyOf
      Previous value: -[
      -  {
      -    "additionalProperties": false,
      -    "description": "knowledge action \"create\".",
      -    "properties": {
      -      "action": {
      -        "const": "create",
      -        "description": "Run the create action.",
      -        "type": "string"
      -      },
      -      "anchor_files": {
      -        "description": "(create only) Repo-relative file paths this note is about (e.g. 'src/auth/session.ts'). When someone later edits a file named here, this node surfaces to them. Set it on a lesson/risk/gap scoped to specific code so it resurfaces exactly when that code is touched.",
      -        "items": {
      -          "type": "string"
      -        },
      -        "type": "array"
      -      },
      -      "anchor_symbols": {
      -        "description": "(create only) Symbol names this note is about — function / class / constant / env var (e.g. 'refreshToken', 'SESSION_TTL'). Same purpose as anchor_files: a precise hook so the note resurfaces when that symbol's code is touched.",
      -        "items": {
      -          "type": "string"
      -        },
      -        "type": "array"
      -      },
      -      "body": {
      -        "description": "(create only) Markdown body with sections that fit the category: a decision's context, alternatives, and why it won; a lesson's symptom, root cause, and fix; a risk's likelihood, impact, and mitigation. Thin one-sentence bodies are discouraged. Write it in plain style: one idea per sentence, active voice, lead with the condition, one term per concept, exact technical names.",
      -        "type": "string"
      -      },
      -      "category": {
      -        "description": "REQUIRED for create — what the fact is: decision (a choice that could have gone otherwise), architecture (how the system is built), goal, risk (may go wrong, hasn't yet), lesson (already went wrong; include the literal error or symbol), gap (missing, not yet committed work), opportunity, priority, fyi.",
      -        "enum": [
      -          "decision",
      -          "architecture",
      -          "goal",
      -          "risk",
      -          "gap",
      -          "fyi",
      -          "opportunity",
      -          "priority",
      -          "lesson"
      -        ],
      -        "type": "string"
      -      },
      -      "component_id": {
      -        "description": "REQUIRED for create — parent component shareable id.",
      -        "type": "string"
      -      },
      -      "due_at": {
      -        "anyOf": [
      -          {
      -            "anyOf": [
      -              {
      -                "type": "string"
      -              },
      -              {
      -                "const": "none",
      -                "type": "string"
      -              }
      -            ]
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "REQUIRED for create (pass null to skip) — a date (2026-12-31) or an ISO-8601 timestamp. A deadline; active knowledge past its due_at surfaces as an overdue commitment. Set it on anything carrying a real deadline. Distinct from expires_at (a reminder, never auto-archived)."
      -      },
      -      "expires_at": {
      -        "anyOf": [
      -          {
      -            "anyOf": [
      -              {
      -                "type": "string"
      -              },
      -              {
      -                "const": "none",
      -                "type": "string"
      -              }
      -            ]
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "REQUIRED for create (pass null to skip) — a date (2026-12-31) or an ISO-8601 timestamp (date TTL): the node auto-archives once the date passes — for EPHEMERAL knowledge (fyi notes, temporary workarounds). Do NOT set on decision/architecture (those retire by supersession, not a date)."
      -      },
      -      "expires_on_task": {
      -        "anyOf": [
      -          {
      -            "anyOf": [
      -              {
      -                "description": "Shareable id: TASK-N (task), KNOW-N (knowledge), COMP-N (component), DOC-N (document), or NODE-N (any).",
      -                "type": "string"
      -              },
      -              {
      -                "const": "none",
      -                "type": "string"
      -              }
      -            ],
      -            "description": "Shareable id: TASK-N (task), KNOW-N (knowledge), COMP-N (component), DOC-N (document), or NODE-N (any)."
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "REQUIRED for create (pass null to skip) — bind a TEMPORARY risk/gap to the OPEN task (TASK-N) that will resolve it: the node auto-archives when that task completes or cancels — no manual cleanup. Durable decisions/lessons/architecture must NOT bind (they retire by supersession, not a task closing) — pass null. Binding to an already-closed task is a dead trigger and is dropped with a warning."
      -      },
      -      "project_slug": {
      -        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "scope": {
      -        "description": "(create only) Workspace scope. Omit or 'auto' = scope to the workspace mapped to the current git branch, else trunk (shared truth). 'trunk' = force shared truth even on a branch. Or pass a workspace name/id to target it. Branch-scoped writes are invisible to collaborators off that workspace.",
      -        "type": "string"
      -      },
      -      "source": {
      -        "description": "(create only) Optional free-form provenance label — where this fact came from. Conventional formats: 'workplace:cdi-fyi', 'meeting:1on1-aaron', 'pr:stele#117', 'doc:rfc-042'. Include this whenever the knowledge originates outside the agent's own reasoning (chat thread, meeting, doc, PR). Omit when the fact is derived from the agent reading code or running tools in this session.",
      -        "maxLength": 500,
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "source_type": {
      -        "description": "(create only) Provenance / trust signal. Defaults to 'claude' from MCP (agent-authored). Pass 'human' only when transcribing a user-verified fact, or 'import' for bulk-imported entries.",
      -        "enum": [
      -          "human",
      -          "claude",
      -          "import"
      -        ],
      -        "type": "string"
      -      },
      -      "source_url": {
      -        "description": "(create only) Optional canonical URL for the source — Slack permalink, PR url, doc link. Rendered as a link icon on the knowledge detail page.",
      -        "format": "uri",
      -        "type": "string"
      -      },
      -      "title": {
      -        "description": "REQUIRED for create — one-line summary.",
      -        "maxLength": 300,
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "topics": {
      -        "description": "(create only) Short tag list (\"oauth\", \"perf\", \"v2\").",
      -        "items": {
      -          "type": "string"
      -        },
      -        "type": "array"
      -      }
      -    },
      -    "required": [
      -      "action",
      -      "project_slug",
      -      "component_id",
      -      "category",
      -      "title",
      -      "expires_on_task",
      -      "due_at",
      -      "expires_at"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "description": "knowledge action \"review\".",
      -    "properties": {
      -      "action": {
      -        "const": "review",
      -        "description": "Run the review action.",
      -        "type": "string"
      -      },
      -      "node_id": {
      -        "description": "REQUIRED for review — knowledge shareable id (e.g. KNOW-7). Tasks/components are rejected.",
      -        "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"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": false,
      +    "description": "action=\"create\": Add a knowledge node under an existing active component (component_id is\nREQUIRED) — prefer an existing component over creating one. Search before\nadding: if a near-match exists, update it with node(action=\"update\") instead of duplicating. Always\ninclude topics (without them the node won't surface in topic queries) and link\nrelated nodes — isolated nodes are nearly invisible.\n\n## The knowledge categories\n\nPick the one that matches what the fact *is*, and give the body the shape it wants. Thin one-liners\ndilute the graph — a node that restates its own title helps nobody.\n\n| Category | It is | Body shape |\n|---|---|---|\n| `decision` | A choice that was made, and could have gone another way. | ## Context / ## Alternatives considered / ## Why this won / ## Consequences |\n| `architecture` | A structural fact about how the system is built. | ## What / ## How it works / ## Why this shape |\n| `goal` | What success looks like. | ## Outcome / ## Why it matters / ## How we'll know we're done |\n| `risk` | Something that might go wrong, and hasn't yet. | ## Risk / ## Likelihood & impact / ## Mitigation / ## Trigger |\n| `gap` | A known missing piece — real, but not yet work anyone has committed to. | ## Gap / ## Why it matters / ## What needs to happen to close it |\n| `lesson` | Something learned the hard way, usually from a failure. | ## Symptom / ## Root cause / ## Fix / ## Why this matters |\n| `opportunity` | Possible future work worth considering. | ## Opportunity / ## Why now / ## What it would take |\n| `priority` | What the focus is right now, and what it is not. | ## Focus / ## Why this and not X / ## Time horizon |\n| `fyi` | Context worth remembering that calls for no action. | A paragraph or two; short is fine. |\n\nTwo that get confused: a **`gap`** is a hole someone still has to decide what to do about; once the work\nis agreed it is a **task**, not a gap. A **`risk`** has not happened; a **`lesson`** already did.\n\n**A lesson from a bug is worth little without its trigger.** Put the literal error message, the failing\nsymbol, the command that broke, into the body. The graph resurfaces knowledge by matching it against\nwhat an agent is doing, so a lesson carrying the real error string reappears the moment someone hits that\nerror again. Worded abstractly, it stays invisible exactly when it would have helped.\n\n\nLIFECYCLE IS REQUIRED. Decide all three — expires_on_task, expires_at,\ndue_at — every time; pass null to skip any (durable decision/architecture\nusually skip all three). Bound nodes retire themselves, which is what keeps\nthe graph self-maintaining — that's why these aren't optional.",
      +    "properties": {
      +      "action": {
      +        "const": "create",
      +        "type": "string"
      +      },
      +      "anchor_files": {
      +        "description": "(create only) Repo-relative file paths this note is about (e.g. 'src/auth/session.ts'). When someone later edits a file named here, this node surfaces to them. Set it on a lesson/risk/gap scoped to specific code so it resurfaces exactly when that code is touched.",
      +        "items": {
      +          "type": "string"
      +        },
      +        "type": "array"
      +      },
      +      "anchor_symbols": {
      +        "description": "(create only) Symbol names this note is about — function / class / constant / env var (e.g. 'refreshToken', 'SESSION_TTL'). Same purpose as anchor_files: a precise hook so the note resurfaces when that symbol's code is touched.",
      +        "items": {
      +          "type": "string"
      +        },
      +        "type": "array"
      +      },
      +      "body": {
      +        "description": "(create only) Markdown body with sections that fit the category: a decision's context, alternatives, and why it won; a lesson's symptom, root cause, and fix; a risk's likelihood, impact, and mitigation. Thin one-sentence bodies are discouraged. Write it in plain style: one idea per sentence, active voice, lead with the condition, one term per concept, exact technical names.",
      +        "type": "string"
      +      },
      +      "category": {
      +        "description": "REQUIRED for create — what the fact is: decision (a choice that could have gone otherwise), architecture (how the system is built), goal, risk (may go wrong, hasn't yet), lesson (already went wrong; include the literal error or symbol), gap (missing, not yet committed work), opportunity, priority, fyi.",
      +        "enum": [
      +          "decision",
      +          "architecture",
      +          "goal",
      +          "risk",
      +          "gap",
      +          "fyi",
      +          "opportunity",
      +          "priority",
      +          "lesson"
      +        ],
      +        "type": "string"
      +      },
      +      "component_id": {
      +        "description": "REQUIRED for create — parent component shareable id.",
      +        "type": "string"
      +      },
      +      "due_at": {
      +        "anyOf": [
      +          {
      +            "anyOf": [
      +              {
      +                "type": "string"
      +              },
      +              {
      +                "const": "none",
      +                "type": "string"
      +              }
      +            ]
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "REQUIRED for create (pass null to skip) — a date (2026-12-31) or an ISO-8601 timestamp. A deadline; active knowledge past its due_at surfaces as an overdue commitment. Set it on anything carrying a real deadline. Distinct from expires_at (a reminder, never auto-archived)."
      +      },
      +      "expires_at": {
      +        "anyOf": [
      +          {
      +            "anyOf": [
      +              {
      +                "type": "string"
      +              },
      +              {
      +                "const": "none",
      +                "type": "string"
      +              }
      +            ]
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "REQUIRED for create (pass null to skip) — a date (2026-12-31) or an ISO-8601 timestamp (date TTL): once the date passes the node is reported as expired, and the next health-check run with fix archives it. Use it for EPHEMERAL knowledge (fyi notes, temporary workarounds). Do NOT set on decision/architecture (those retire by supersession, not a date)."
      +      },
      +      "expires_on_task": {
      +        "anyOf": [
      +          {
      +            "anyOf": [
      +              {
      +                "description": "Shareable id: TASK-N (task), KNOW-N (knowledge), COMP-N (component), DOC-N (document), or NODE-N (any).",
      +                "type": "string"
      +              },
      +              {
      +                "const": "none",
      +                "type": "string"
      +              }
      +            ],
      +            "description": "Shareable id: TASK-N (task), KNOW-N (knowledge), COMP-N (component), DOC-N (document), or NODE-N (any)."
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "REQUIRED for create (pass null to skip) — bind a TEMPORARY risk/gap to the OPEN task (TASK-N) that will resolve it: the node auto-archives when that task completes or cancels — no manual cleanup. Durable decisions/lessons/architecture must NOT bind (they retire by supersession, not a task closing) — pass null. Binding to an already-closed task is a dead trigger and is dropped with a warning."
      +      },
      +      "project_slug": {
      +        "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "scope": {
      +        "description": "(create only) Workspace scope. Omit or 'auto' = scope to the workspace mapped to the current git branch, else trunk (shared truth). 'trunk' = force shared truth even on a branch. Or pass a workspace name/id to target it. Branch-scoped writes are invisible to collaborators off that workspace.",
      +        "type": "string"
      +      },
      +      "source": {
      +        "description": "(create only) Optional free-form provenance label — where this fact came from. Conventional formats: 'workplace:cdi-fyi', 'meeting:1on1-aaron', 'pr:stele#117', 'doc:rfc-042'. Include this whenever the knowledge originates outside the agent's own reasoning (chat thread, meeting, doc, PR). Omit when the fact is derived from the agent reading code or running tools in this session.",
      +        "maxLength": 500,
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "source_type": {
      +        "description": "(create only) Provenance / trust signal. Defaults to 'claude' from MCP (agent-authored). Pass 'human' only when transcribing a user-verified fact, or 'import' for bulk-imported entries.",
      +        "enum": [
      +          "human",
      +          "claude",
      +          "import"
      +        ],
      +        "type": "string"
      +      },
      +      "source_url": {
      +        "description": "(create only) Optional canonical URL for the source — Slack permalink, PR url, doc link. Rendered as a link icon on the knowledge detail page.",
      +        "format": "uri",
      +        "type": "string"
      +      },
      +      "title": {
      +        "description": "REQUIRED for create — one-line summary.",
      +        "maxLength": 300,
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "topics": {
      +        "description": "(create only) Short tag list (\"oauth\", \"perf\", \"v2\").",
      +        "items": {
      +          "type": "string"
      +        },
      +        "type": "array"
      +      }
      +    },
      +    "required": [
      +      "action",
      +      "project_slug",
      +      "component_id",
      +      "category",
      +      "title",
      +      "expires_on_task",
      +      "due_at",
      +      "expires_at"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "description": "action=\"review\": Verify a knowledge node: record that you deliberately confirmed its claims are STILL TRUE against current reality, stamping `last_verified_at` to now. This verification axis is orthogonal to freshness — the only signal that catches a recently-written yet factually-wrong node. Actually check it first; if it's wrong, do NOT verify — use node(action=\"update\") or a supersedes edge instead. Does NOT change content, freshness, or source_type. Knowledge only; tasks/components are rejected.",
      +    "properties": {
      +      "action": {
      +        "const": "review",
      +        "type": "string"
      +      },
      +      "node_id": {
      +        "description": "REQUIRED for review — knowledge shareable id (e.g. KNOW-7). Tasks/components are rejected.",
      +        "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"
      +  }
      +]
  5. First observed

TDQS

A4.1/5.0
Behavior4/5

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

Annotations cover the safety profile (readOnlyHint=false, destructiveHint=false, openWorldHint=true), and the description adds substantive behavior: that durable knowledge retires by supersession rather than dates, and that merging lives elsewhere. It does not restate branch-scope invisibility in the description itself, but that is covered in the schema.

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 action split is front-loaded and every clause carries information, but the description is dense and packs three distinct ideas into one paragraph, making it slightly harder to scan than a cleanly separated version.

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 an output schema and rich annotations, the description need not explain return values, and it covers the two-action branching plus the supersession rule. It is complete enough to call the tool correctly, with only minor room to note reading alternatives.

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 schema already documents every parameter thoroughly. The description only frames the lifecycle trio as a group ('pass null to skip each'), adding no format or semantic detail beyond what the schema provides, so baseline 3 is appropriate.

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

Purpose5/5

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

The description names both actions with specific verbs and resources: create files a typed fact, review marks a node re-verified. It also routes duplicate-merging to the `destructive` sibling, so an agent can distinguish this tool from neighbors without opening the schema.

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 clearly frames when each action applies (create vs review) and gives a decision rule for lifecycle fields (durable decisions/architecture skip all three). It does not, however, state when not to use this tool at all, e.g. routing reads to recall/search.

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.