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"
+ }
+]