diff --git a/.changeset/16927-agent-tools-retirement-citation.md b/.changeset/16927-agent-tools-retirement-citation.md new file mode 100644 index 0000000000..820b091504 --- /dev/null +++ b/.changeset/16927-agent-tools-retirement-citation.md @@ -0,0 +1,24 @@ +--- +'@objectstack/spec': patch +--- + +The `agent.tools` rejection now says why ADR-0064 binds, so its `Proposed` status does not read as "not yet in force" + +An author who writes the retired `agent.tools` key gets the tombstone's +prescription, which rests the rule on **ADR-0064** (*"an agent's tool set is the +union of its surface-compatible skills' tools"*). Following that citation lands +on a record whose own header reads `**Status**: Proposed (2026-06-22)` and +carries a `πŸ”Ά Cloud-owned β€” superseded in part by cloud ADR-0025` callout. From +the record itself an author cannot tell that the rule still binds them β€” the +weaker reading is the one the metadata invites. + +ADR-0064 stays the cited authority, because it is the record that states the +invariant the key violated; **ADR-0109** (`Accepted β€” implemented (Phase 1)`) +names `agent.tools` nowhere and only *builds on* that invariant, so retargeting +the citation would send the author to a record that does not contain the rule +they broke. The message instead gains one clarifying clause: the `Proposed` / +cloud-owned status scopes the **runtime** half (tool resolution, which lives in +cloud `service-ai`), while the **authoring** half is in force in this repo and +ADR-0109 is the in-repo record carrying it. + +Prose only β€” the rejection, the retirement and the accept set are unchanged. diff --git a/content/docs/references/ai/agent.mdx b/content/docs/references/ai/agent.mdx index 880bc15536..159db8c9f8 100644 --- a/content/docs/references/ai/agent.mdx +++ b/content/docs/references/ai/agent.mdx @@ -51,7 +51,7 @@ const result = AIModelConfigSchema.parse(data); | **lifecycle** | `{ id: string; description?: string; contextSchema?: Record; initial: string; … }` | optional | [EXPERIMENTAL β€” not enforced] State machine defining the agent conversation flow and constraints. Parsed but no runtime consumer yet. | | **surface** | `Enum<'ask' \| 'build'>` | optional (default: `"ask"`) | Product surface this agent binds ('ask' \| 'build') β€” ADR-0063 Β§1 | | **skills** | `string[]` | optional | Skill names to attach (Agentβ†’Skillβ†’Tool architecture) | -| **tools** | `never` | optional | [REMOVED] `agent.tools` was removed in @objectstack/spec 17 β€” use `skills`. An agent reaches exactly the tools its surface-compatible skills declare (ADR-0064), so move each reference into a skill: a platform tool by its registered name, or `action_` for one of your own AI-exposed Actions. 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. Run `os migrate meta --from 16` to list the mechanical edits for existing sources; apply them by hand. | +| **tools** | `never` | optional | [REMOVED] `agent.tools` was removed in @objectstack/spec 17 β€” use `skills`. An agent reaches exactly the tools its surface-compatible skills declare (ADR-0064), so move each reference into a skill: a platform tool by its registered name, or `action_` for one of your own AI-exposed Actions. 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. ADR-0064 itself still reads `Proposed` and is cloud-owned β€” that scopes its RUNTIME half (tool resolution, which lives in cloud `service-ai`), not this rejection: the authoring invariant binds you here, and ADR-0109 (Accepted β€” implemented) is the in-repo record that carries it. Run `os migrate meta --from 16` to list the mechanical edits for existing sources; apply them by hand. | | **knowledge** | `never` | optional | [REMOVED] `agent.knowledge` was removed in @objectstack/spec 17.0.0 (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. 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. Run `os migrate meta --from 16` to list the mechanical edits for existing sources; apply them by hand. | | **active** | `boolean` | optional (default: `true`) | | | **access** | `string[]` | optional | Who can chat with this agent | diff --git a/packages/spec/src/ai/agent.zod.ts b/packages/spec/src/ai/agent.zod.ts index 690dc4e58e..db3e7e4e16 100644 --- a/packages/spec/src/ai/agent.zod.ts +++ b/packages/spec/src/ai/agent.zod.ts @@ -239,6 +239,10 @@ export const AgentSchema = lazySchema(() => strictObject({ '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. ' + + 'ADR-0064 itself still reads `Proposed` and is cloud-owned β€” that scopes its ' + + 'RUNTIME half (tool resolution, which lives in cloud `service-ai`), not this ' + + 'rejection: the authoring invariant binds you here, and ADR-0109 ' + + '(Accepted β€” implemented) is the in-repo record that carries it. ' + 'Run `os migrate meta --from 16` to list the mechanical edits for existing sources; apply them by hand.', ),