Skip to content

docs(ai): mark the retired agent.tools key as removed in agents.mdx - #10732

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-10355-agent-tools-retired
Aug 21, 2026
Merged

docs(ai): mark the retired agent.tools key as removed in agents.mdx#10732
os-zhuang merged 1 commit into
mainfrom
claude/issue-10355-agent-tools-retired

Conversation

@claude

@claudeclaudeBot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Closes#10355

content/docs/ai/agents.mdx taught agent.tools as a live authoring field in two places, while packages/spec/src/ai/agent.zod.ts carries it as a retiredKey() tombstone — z.never(), so the key types as never (it fails tsc at the authoring site) and any value that reaches the runtime is rejected at parse with the prescription. The page already stated the correct ADR-0064 rule in its own prose at line 118 ("an agent's tool set is the union of its surface-compatible skills' tools — there is no global fall-through"), so it contradicted itself: correct rule in the prose, retired key in the table.

Site 1 — the "The shape of an agent" field-table row

Before

| `tools` | Direct tool **references** `{ type, name, description }` — `type` is `action` \| `flow` \| `query` \| `vector_search`; `name` points at an existing Action/Flow/query |

After

| `tools` | **Removed in protocol 17 (#3894)** — typed `never`, so writing it fails `tsc`, and a value that reaches the runtime is rejected at parse. This is **not** a rename: there is no key the value moves to. Declare each tool on a **skill** instead — a platform tool by its registered name, or `action_<name>` for one of your own AI-exposed Actions — and attach that skill through `skills` (ADR-0064) |

Site 2 — the callout beneath that table

Before

<Callout type="info">
Agent tools are **references** to existing Actions, Flows, or queries — you do
not define ad-hoc tool names with inline parameter schemas here. See
[Actions as Tools](/docs/ai/actions-as-tools) for how an Action becomes
LLM-callable.
</Callout>

After

<Callout type="warn">
**An agent has no tool slot of its own.** Its tool set is exactly the union of
its surface-compatible skills' tools, with no fall-through to the global
registry ([ADR-0064](https://github.com/objectstack-ai/objectstack/blob/main/docs/adr/0064-tool-scoping-to-agent.md)).
The removed `tools` key was the one seam that broke that invariant: the runtime
resolved `agent.tools[].name` against the **full** registry with no surface
check, so an `ask`-surface agent could name an authoring tool and reach it. So
there is nowhere on the agent to move a reference **to** — re-declare each one
in a skill's `tools` by hand, then attach the skill. See
[Actions as Tools](/docs/ai/actions-as-tools) for how an Action becomes
LLM-callable.
</Callout>

The callout kept its type="info" shape but became type="warn" — it now carries a retirement, and warn is the dominant spelling in this corpus (222 uses vs. 5 of warning). The old callout's true half ("you do not define ad-hoc tool names with inline parameter schemas here") is preserved and strengthened: an agent has no tool slot at all.

Deliberately no migration command

The sibling knowledge row on the same table closes with "os migrate meta --from 16 rewrites it", because that removal was a rename. This one is not, and the tombstone says so in its own words:

This is NOT a rename — there is no key the value moves to: the migration DELETES the key and emits a notice naming each tool that was listed, and you re-declare each one in a skill by hand.

So the replacement text offers no codemod and implies no mechanical rewrite. It states the by-hand prescription and why the old shape is gone — the removal closed a real capability leak (agent.tools[].name resolved against the full registry with no surface check), so a neutral "this moved" would have been the wrong register.

Scope — agent sense only

Only the agent-level key is retired. Every tools in the skill sense is correct and is untouched: the defineSkill example's tools: ['get_record', ...], and the | **Wiring** | \tools`, `surface`, `triggerConditions` |` row in the skill-halves table. The diff is 2 hunks in 1 file.

Verification — 14 gate families green at 888aebf682

Gate set derived with node scripts/pm/dispatch-gates.mjs (no paths — it takes its own change set from the merge base), which matched 13 families for content/docs/**, plus check:nul-bytes for the edit itself. Run at the final commit with a clean tree; each exit code captured before any pipe. Their own verdict lines:

  • check:doc-anchors"272 internal #fragment link(s) across 408 source file(s) all resolve to a real heading"
  • check:role-word"OK, no new occurrences of the reserved word" (this file's baseline is 5; it was 5 before and 5 after)
  • check:doc-authoring"389 files clean — no bare metadata literals"
  • check:docs-audit-scope"scope is in sync with content/docs/: 189 hand-written doc(s)"
  • check:docs-redirects — self-test 48 assertions, green
  • check:doc-formula-expressions"22 record-scoped formula example(s) across 416 files / 1443 TS blocks judged clean"
  • check:published-readme-links"152 outbound link(s) ... 12 docs-site page(s) resolved (0 via redirect), 1 anchor(s) verified"
  • check:nul-bytes, check:cross-package-test-inputs (both spellings), check:empty-state, check:liveness, check:strictness-ledger, check:variant-docs — all green

check:skill-examples does not apply: this edit touches no fenced code block. The nearest {/* os:check */} fence (the Sales Assistant example) is below both hunks and unmodified.

No changeset

Docs-only — this publishes nothing, so no .changeset/*.md. The skip-changeset label is applied.

Out-of-scope findings — filed, not touched here

Both came out of the card's own rider to sanity-check the remaining field-table rows against AgentSchema. Neither is assigned and neither carries pm:queue.

One judgement call to flag: the knowledge row sits directly under the row this PR rewrites and is stale in exactly the same way, so it met the bar for a bounded in-place repair. It was filed instead, because the card and its triage both said to report drift on the remaining rows rather than widen, and because that retirement carries its own distinct prescription (#3896) that deserves its own triage.


Generated by Claude Code

The field table and the callout under it still taught `agent.tools` as a live
authoring field, while `packages/spec/src/ai/agent.zod.ts` carries it as a
`retiredKey()` tombstone — typed `never`, rejected at parse. The page already
stated the correct ADR-0064 rule in its own prose, so it contradicted itself.
Replace the row with the retirement and its prescription, and rewrite the
callout to state the ADR-0064 invariant and why the key is gone: the runtime
resolved the reference against the full registry with no surface check.
Not a rename — no migration command is offered, because there is no key the
value moves to.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DdCnBGcHeufjrq7drTD3wt
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 21, 2026
@github-actionsgithub-actionsBot added the documentation Improvements or additions to documentation label Aug 21, 2026
@claude

claudeBot commented Aug 21, 2026

Copy link
Copy Markdown
ContributorAuthor

PM review — verified against the diff and the spec source, not the report. Approving.

⏳ Arming deferred: GraphQL is exhausted (0/5000, resets ~10:13Z) and the draft flip needs it. Core REST is fine, which is why this lands now. ⛔ Not reaching for merge_pull_request.

⚠️ First: the precedent in my brief was itself the defect

I told you to mirror :211's knowledge row as "this page's own house style" for documenting a retirement. I verified your #10730 against the source rather than taking it, and you are right:

So the row I held up as the model is an instance of the exact defect your card is about, one row above your own edit, and it is worse than the tools row because it hands the reader a migration command for a dead key.

Mirroring its form and not its content was the right call, and saying so explicitly is what let me catch my own brief. Fifth brief defect from this seat tonight and the sharpest — I pointed you at a broken example as the standard to meet.

The edit itself

Both sites rewritten from the tombstone's own words, and the thing I most wanted is present: no migration command is offered. The tombstone says "This is NOT a rename — there is no key the value moves to", and inventing an os migrate equivalent by analogy with the topics row would have been the natural mistake — especially with that row sitting directly above as my "precedent".

The callout now carries the ADR-0064 invariant and the reason the key is goneagent.tools[].name resolved against the full registry with no surface check, so an ask-surface agent could reach an authoring tool. That makes it a prescription rather than a neutral "this moved", which matters because the removal closed a real capability leak.

The skill-sense tools is untouched and you proved it: the defineSkill example's tools: ['get_record', …] at :156 and the | **Wiring** | \tools`, `surface`, `triggerConditions` |row at:190` are both correct and not in the diff. Getting that distinction wrong in either direction was the way this card fails, and the diff is 2 hunks in 1 file.

And the site you evaluated and left alone: :214's "behaviour comes from persona, instructions, skills, and tools" asserts no key and is true as written — an agent does reach tools, via its skills. Leaving a true sentence alone while editing its neighbours is the harder half of a prose fix.

infowarn decided by measuring the corpus (222 warn vs 5 warning) rather than by taste. check:role-word's baseline for this file is 5, measured 5 before and 5 after — the shrink-only ratchet neither tripped nor owed an update, which is worth stating since that ratchet has blocked docs work before (#10533).

Mutation proven on disk before anything else, with per-anchor occurrence counts both ways and an abort-without-writing guard. check:doc-formula-expressions red on first run for ERR_MODULE_NOT_FOUND — correctly classified as the unbuilt-dependency trap, and it usefully exposed a skipped pnpm install. check:skill-examples correctly not run, with the reason: the edit touches no fenced block and the nearest {/* os:check */} fence is below both hunks and unmodified.

On the finding label — your call stands

You withheld finding deliberately, because both #10730 and #10731 are concrete defects (a reader following either hits a hard tsc/parse error) and your standing instructions reserve finding for observation-class items, so concrete defects reach triage ungraded. That is a coherent distinction, you honoured the binding constraints exactly (unassigned, no pm:queue), and you flagged the deviation instead of making it silently. Accepted — I am not relabelling.

I have added the routing labels, which is the non-negotiable half: #10730domain:devx, #10731domain:spec (it lands in packages/spec/src/ai/agent.zod.ts, not this seat's tree — the spec seat can re-route if I have that wrong). Without a domain:* an issue is invisible to every board regardless of how it is graded.

On the in-place-fix exemption you declined

You are right that #10730 met the conditions, and right not to take it: both the card body and triage said to sanity-check the remaining rows and report drift rather than widen, and that retirement carries its own prescription (#3896) deserving its own triage. Widening after the fact would also have broken the property that makes this PR reviewable against its card.

I am not taking up the one-hunk follow-up here. #10730 is a good next dispatch, but it edits content/docs/ai/agents.mdx — this file — so it waits until this PR merges rather than racing it.


Generated by Claude Code

@os-zhuang
os-zhuang marked this pull request as ready for review August 21, 2026 10:19
@os-zhuang
os-zhuang added this pull request to the merge queueAug 21, 2026
Merged via the queue into main with commit 5d51e19Aug 21, 2026
33 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-10355-agent-tools-retired branch August 21, 2026 10:29
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[docs] ai/agents.mdx still documents agent.tools as a live field — it was tombstoned in protocol 17

1 participant

@os-zhuang