Found while implementing #10355 (the sibling agent.tools row on the same table). Out of that card's scope — it names tools only — so filed rather than fixed there, following that card's own rider to sanity-check the remaining field-table rows against AgentSchema and report drift rather than widen.
The defect
content/docs/ai/agents.mdx — the "The shape of an agent" field table — carries this row:
| `knowledge` | RAG access: `{ sources: string[], indexes: string[] }`. `sources` is the only key; the `topics` alias was removed in protocol 17 (#3855) — `os migrate meta --from 16` rewrites it |
It documents knowledge as a live authoring field and notes only that a nested alias was removed. But the entire key is retired. packages/spec/src/ai/agent.zod.ts:
knowledge: retiredKey('`agent.knowledge` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — '+'declaring knowledge sources/indexes on an agent never scoped retrieval: the '+"`search_knowledge` tool takes `sourceIds` from the LLM's tool-call arguments, not from "+'the agent record. Delete the block. ...',),retiredKey is z.never(): the key types as never (so it fails tsc at the authoring site) and any value that reaches the runtime is rejected at parse with the prescription. The row teaches a key that cannot be written.
The page already contradicts itself
The Sales Assistant example further down the same file states the correct rule in a code comment:
// (There is no agent-level `knowledge` block — it was removed in protocol
// 17 (#3896 close-out): declaring sources never scoped retrieval. Restrict
// access at the knowledge-service/source level; describe intended
// grounding in `instructions`.)
Why it matters beyond a stale row
Same shape as the tools case: the key read as a security control and was not one. Declaring sources / indexes on an agent never scoped retrieval — search_knowledge takes sourceIds from the LLM's own tool-call arguments, not from the agent record. An author who believed they had scoped retrieval here scoped nothing, which is the dangerous direction.
Suggested repair
Replace the row with the retirement and its prescription, taken from the tombstone's own words: delete the block; restrict retrieval at the knowledge-service / source level (per-source permissions); describe intended grounding in instructions. The topics sub-alias is moot once the parent key is gone, so the os migrate meta clause currently attached to it should not survive as-is.
⚠️ Note for whoever picks this up: this row is currently cited as the page's house-style precedent for documenting a retirement. It is the form that is worth copying, not its content.
Generated by Claude Code
Found while implementing #10355 (the sibling
agent.toolsrow on the same table). Out of that card's scope — it namestoolsonly — so filed rather than fixed there, following that card's own rider to sanity-check the remaining field-table rows againstAgentSchemaand report drift rather than widen.The defect
content/docs/ai/agents.mdx— the "The shape of an agent" field table — carries this row:It documents
knowledgeas a live authoring field and notes only that a nested alias was removed. But the entire key is retired.packages/spec/src/ai/agent.zod.ts:retiredKeyisz.never(): the key types asnever(so it failstscat the authoring site) and any value that reaches the runtime is rejected at parse with the prescription. The row teaches a key that cannot be written.The page already contradicts itself
The Sales Assistant example further down the same file states the correct rule in a code comment:
Why it matters beyond a stale row
Same shape as the
toolscase: the key read as a security control and was not one. Declaringsources/indexeson an agent never scoped retrieval —search_knowledgetakessourceIdsfrom the LLM's own tool-call arguments, not from the agent record. An author who believed they had scoped retrieval here scoped nothing, which is the dangerous direction.Suggested repair
Replace the row with the retirement and its prescription, taken from the tombstone's own words: delete the block; restrict retrieval at the knowledge-service / source level (per-source permissions); describe intended grounding in
instructions. Thetopicssub-alias is moot once the parent key is gone, so theos migrate metaclause currently attached to it should not survive as-is.Generated by Claude Code