Repository navigation
[docs] ai/agents.mdx documents the retired agent.knowledge key as live RAG access #10730
Description
Activity
- addeddocumentationImprovements or additions to documentationImprovements or additions to documentation
on Aug 21, 2026 Triage: lands in
content/docs/ai/agents.mdx(field-table row);pm:queue·domain:devx· type Task. Rationale: the row documents aretiredKey(z.never()) as live RAG access, and the dangerous direction is real — an author who believes they scoped retrieval scoped nothing; the page already carries the correct rule in its Sales Assistant example, so this is convergence, not a ruling. Serial constraint (fold-or-serial answered): SERIAL — #10355 is in-flight on the same file (itstoolsrow; this card exists precisely because that dispatch keptknowledgeout of scope). Dispatch only after #10355's PR lands, and require a same-day re-read of the file's currentmainstate before editing. Folding into #10355 is not available — that dispatch's file surface is closed and its dev already declined the widening.Size/model suggestion: S,
mode:subagent, sonnet; Clause-②: no.
Generated by Claude Code
claude commented
on Aug 21, 2026 claudeboton Aug 21, 2026 – with ClaudeContributorAuthorMore actionsClaim — PM dispatch (devx seat)
- Session:
c970724d-303c-5614-9d20-a3f92205cfad - Branch:
claude/issue-10730-agent-knowledge-retired
Serial constraint cleared: PR #10732 (#10355), which held
content/docs/ai/agents.mdx,
merged at 2026-08-21T10:29:41Z.Premise re-verified on
origin/main=78ac958552, both sides:packages/spec/src/ai/agent.zod.ts:248—knowledge: retiredKey(content/docs/ai/agents.mdx:211— still teaches it as live: "RAG access:
{ sources: string[], indexes: string[] }.sourcesis the only key; thetopicsalias was
removed in protocol 17 ([P3] Retire the three deprecated aliases — via the ADR-0087 D2 conversion layer, not by deleting the keys #3855) —os migrate meta --from 16rewrites it"
⭐ And the page already contradicts itself, 64 lines further down.
:275-278, inside the
worked example:"(There is no agent-level
knowledgeblock — 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 ininstructions.)"So the correct prescription is already written on this page — the field table simply never
got it. That makes this a smaller and better-evidenced edit than it looked: the wording does not
have to be invented, only moved into the row.⚠️ This row is worse than thetoolsrow #10732 just fixed, because it hands the reader a
migration command for a key that no longer exists.agent.tools' tombstone at least says
"NOT a rename"; this one points atos migrate meta --from 16, which cannot help.For the record: this card exists because the #10355 dispatch mirrored this row's form as
house style on my instruction, noticed its content was itself defective, and reported it
rather than copying it. My brief held up a broken example as the standard.
Generated by Claude Code
- Session:
- added a commit that references this issue
on Aug 21, 2026 claude commented
on Aug 21, 2026 claudeboton Aug 21, 2026 – with ClaudeContributorAuthorMore actions{ "issue": 10730, "status": "done", "branch": "claude/issue-10730-agent-knowledge-retired", "pr": "https://github.com/objectstack-ai/objectstack/pull/10768", "premise_still_valid": true, "summary": "Premise verified on both sides at origin/main = 78ac958552 (unchanged across two fetches): packages/spec/src/ai/agent.zod.ts:248 is `knowledge: retiredKey(...)`, and content/docs/ai/agents.mdx:211 still taught the key as live RAG access while pointing at `os migrate meta --from 16` to 'rewrite it'. Rewrote that single table row from the tombstone's own words, following the shape of the sibling `tools` row (PR #10732): removal + protocol/issue, `never` typing, explicitly not a rename, the REASON the key is gone (declaring sources never scoped retrieval - `search_knowledge` takes `sourceIds` from the LLM's tool-call arguments, not the agent record), and the prescription (delete the block; restrict at the knowledge-service/source level via per-source permissions; describe intended grounding in `instructions`). One file, one row, 1 insertion / 1 deletion. TWO CORRECTIONS TO THE BRIEF, neither blocking: (1) the brief warned of a new gate `check-doc-frontmatter.mjs` landed on main 'an hour ago' - it does not exist anywhere in the tree; `git ls-tree -r --name-only origin/main | grep -i frontmatter` returns nothing and origin/main was still 78ac958552 on re-fetch. (2) The brief said to offer no `os migrate meta` command; the tombstone DOES name one verbatim, but as a LISTER ('to list the mechanical edits for existing sources; apply them by hand'), not a rewriter - see open_questions, I omitted it and flagged it in the PR body.", "tests": "Gate set derived with `node scripts/pm/dispatch-gates.mjs` (no paths, per instruction - it derived the changeset itself: '1 path(s) vs merge base 78ac95855', committed 1 / working tree 0 / untracked 0). It returned 13 families, not the 4 the brief predicted, so 9 were added beyond the brief. Full union re-run AFTER the final commit, on `git rev-parse --short HEAD` = 934022ee4a, all 14 green (exit codes captured with redirect-then-capture, never through a pipe): check:cross-package-test-inputs 0 | check:doc-anchors 0 | check:doc-authoring 0 | check:doc-formula-expressions 0 | check:docs-audit-scope 0 | check:docs-redirects 0 | check:published-readme-links 0 | check:role-word 0 | check:empty-state 0 | check:liveness 0 | check:strictness-ledger 0 | check:variant-docs 0 | check-cross-package-test-inputs.mjs 0 | check:nul-bytes 0. Gates' own verdict lines: 'check-doc-anchors: 272 internal #fragment link(s) across 408 source file(s) all resolve to a real heading'; 'doc authoring guard: 389 files clean - no bare metadata literals'; 'docs-accuracy-audit scope is in sync with content/docs/: 189 hand-written doc(s)'; 'check-role-word: OK, no new occurrences of the reserved word'; 'check-nul-bytes: OK (scanned 6234 text file(s) ... no raw ASCII control bytes)'. check:doc-formula-expressions was RED on first run purely from an unbuilt dependency closure in the fresh worktree (ERR_MODULE_NOT_FOUND for @objectstack/formula/dist) - fixed by `pnpm --workspace-concurrency=2 --filter '@objectstack/lint^...' build`, then green: '22 record-scoped formula example(s) across 416 files / 1443 TS blocks judged clean'. All heavy commands ran through `bash scripts/pm/os-verify-lock.sh -c` (VERDICT command-exit 0 each; longest hold 128s for the closure build, longest wait 169s). MUTATION CONFIRMED ON DISK, both directions, before trusting anything: old-row anchor count 1 -> 0 and new-row anchor count 0 -> 1, asserted in the edit script itself (it aborts without writing unless the old anchor matches exactly once); file line count unchanged at 391, `git diff --stat` = 1 file / 1 insertion / 1 deletion. check:skill-examples deliberately NOT run - verified for my own hunk rather than inherited: the only `{/* os:check */}` fence on the page is at line 247, below my hunk at 211 and outside it. No ablation applies (docs-only, no guard under test).", "open_questions": [ { "question": "The brief said to offer no `os migrate meta` command for `knowledge`, with the escape hatch 'if the tombstone names a real conversion, quote it exactly'. The tombstone DOES name one, verbatim: 'Run `os migrate meta --from 16` to list the mechanical edits for existing sources; apply them by hand.' That is a lister, not a rewriter - and it is the identical boilerplate sentence carried by the `tools` tombstone. The old row's false half was the claim that it 'rewrites it'. Include it framed as a lister, or omit it?", "options": [ "A - Omit the command entirely (what I shipped). Matches the sibling `tools` row, which omits it despite its tombstone carrying the same sentence; avoids implying an asymmetry where `knowledge` has a migration path `tools` lacks. The row instead says plainly there is no key the value moves to and the block is deleted.", "B - Include it quoted exactly, framed as a lister that emits by-hand edits. Maximally faithful to the tombstone and directly corrects the 'rewrites it' claim rather than leaving a silent gap - but breaks symmetry with the adjacent `tools` row unless that row is amended too, which is out of this card's scope." ], "recommendation": "A, because the two rows sit adjacent in one field table and their tombstones carry the same sentence, so an asymmetry between them would itself teach something false. B is defensible and a one-line follow-up if the reviewer prefers it - but it should then be applied to BOTH rows, which is a separate card. Flagged in the PR body so the reviewer can rule without reading the tombstone." }, { "question": "Should the `topics` / #3855 fact survive in the row now that the parent key is gone? (The brief asked me to decide and say what I decided.)", "options": [ "A - Drop it from the row (what I shipped).", "B - Keep it as a historical note alongside the retirement." ], "recommendation": "A. It remains historically true, and the protocol-17 `agent-knowledge-topics-to-sources` conversion does remain in the migration chain - the header comment in agent.zod.ts says it rewrites historical SOURCES and imports nothing from the removed schema. But for an author, a nested alias of a key that cannot be written at all is unreachable information, and leading with the alias is exactly what made the old row imply the parent was live. The conversion-chain fact stays recorded where it belongs (agent.zod.ts + the ADR-0087 registries), not in an authoring field table. Note #3855 (topics alias removal) and #3896 (the key's own removal) are distinct and both real; the old row cited only the first, the new row cites #3896." } ], "out_of_scope_findings": [] }No third retired key found on this page — checked rather than assumed.
AgentSchema
carries exactly tworetiredKey(entries:tools(line 231, fixed by #10732) and
knowledge(line 248, this PR). The other two removed agent fields,tenantIdand
visibility, were deleted outright rather than tombstoned, and neither appears anywhere in
content/docs/ai/agents.mdx(grep: no match). Every remaining row in the field table —
surface,role,instructions,model,skills— is live in the schema. Nothing filed.Row before:
| `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 |Row after:
| `knowledge` | **Removed in protocol 17 (#3896)** — typed `never`, so writing it fails `tsc`, and a value that reaches the runtime is rejected at parse. Declaring `sources` / `indexes` here never scoped retrieval: `search_knowledge` takes `sourceIds` from the LLM's own tool-call arguments, not from the agent record, so an author who "scoped" access here scoped nothing. This is **not** a rename: there is no key the value moves to — delete the block. Restrict retrieval at the knowledge-service / source level (per-source permissions), and describe intended grounding in `instructions` so the model asks for the right sources |Re-read after the edit: the row and the
:275-278example comment now agree on all four
points — removed in protocol 17 (#3896), declaring sources never scoped retrieval, restrict
at the knowledge-service/source level, describe grounding ininstructions.skip-changesetapplied additively (POST /issues/10768/labels, never a whole-set write)
and read back after the bots ran:['documentation', 'size/xs', 'skip-changeset']— the
bots added the first two, mine survived.Worktree removed without
--force(git status --porcelainclean first); sibling agents'
worktrees untouched.
Generated by Claude Code
Generated by Claude Code
- added a commit that references this issue
on Aug 23, 2026
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