From bed4e87678c643bb2f601330e4d093b14654a452 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 21 Aug 2026 07:27:11 +0000 Subject: [PATCH 1/2] docs(spec): align the skill.tools docblock with ADR-0109's authoring model MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `SkillSchema.tools` docblock told authors that tools "should also be registered as first-class metadata (type: 'tool') unless they are dynamically materialised at runtime" — the shape ADR-0109 explicitly rejected, with the exemption inverted: it treated the materialised path as the exception when ADR-0109 makes it, together with the platform registry, the rule. The sibling docblock over `stack.zod.ts`'s `tools` already stated the correct model, so the package shipped two contradictory answers to the same question. The text now mirrors the resolution universe `validate-ai-tool-references` implements: a `tool` record is never required, the default third-party path declares none, and a name resolves against `stack.tools[]` names, the `PLATFORM_PROVIDED_TOOL_NAMES` registry, or the materialised `action_` family. It also records that `stack.tools` is the optional Phase-2 refinement layer with no runtime reader until that phase lands. Prose only — no schema shape, no `.describe()` text, no code path. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01B4h3medzvhB9rpfoja9jcw --- .changeset/skill-tools-docblock-adr-0109.md | 11 +++++++++++ packages/spec/src/ai/skill.zod.ts | 14 ++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 .changeset/skill-tools-docblock-adr-0109.md diff --git a/.changeset/skill-tools-docblock-adr-0109.md b/.changeset/skill-tools-docblock-adr-0109.md new file mode 100644 index 0000000000..8e833c23f1 --- /dev/null +++ b/.changeset/skill-tools-docblock-adr-0109.md @@ -0,0 +1,11 @@ +--- +"@objectstack/spec": patch +--- + +**Docs:** the `skill.tools[]` docblock now states ADR-0109's authoring model instead of its rejected alternative (#10356). + +`SkillSchema.tools`' docblock told authors that "Tools should also be registered as first-class metadata (type: 'tool') unless they are dynamically materialised at runtime" — the shape ADR-0109 explicitly **rejected** ("a required tool record per exposed action": a second authoring step, a second namespace to keep consistent, and a second surface for AI authors to hallucinate into, for zero added capability). It also inverted the exemption, treating the materialised path as the exception when ADR-0109 makes it — together with the platform registry — the rule. The sibling docblock over `stack.zod.ts`'s `tools` already said the opposite, so the package shipped two contradictory answers to the same question. + +The text now mirrors the resolution universe `@objectstack/lint`'s `validate-ai-tool-references` actually implements: a `tool` record is never required and the default third-party path declares none; a `skill.tools[]` name resolves against the stack's own `stack.tools[]` names, `PLATFORM_PROVIDED_TOOL_NAMES`, and the `action_` family the runtime materialises from AI-exposed declarative actions (`ai.exposed` + `ai.description` on a headless action type, per ADR-0011). It also records that `stack.tools` is the optional Phase-2 AI-presentation refinement layer with no runtime reader until that phase lands — so a record authored today is inert, which the old sentence recommended authoring without saying. + +Prose only: no schema shape, no `.describe()` text, no runtime behaviour and no authorable surface changes. It reaches the published package through the generated `.d.ts`, which is why it is graded rather than skipped — this is the docblock an AI author reads while writing `skill.tools[]`, the exact surface ADR-0109 was written to keep clean. diff --git a/packages/spec/src/ai/skill.zod.ts b/packages/spec/src/ai/skill.zod.ts index 3b0e56b770..796d85450d 100644 --- a/packages/spec/src/ai/skill.zod.ts +++ b/packages/spec/src/ai/skill.zod.ts @@ -345,8 +345,18 @@ export const SkillSchema = lazySchema(() => strictObject({ * of dynamically registered tools (e.g. the `action_` tools * materialised from each object's declarative Action list). * - * Tools should also be registered as first-class metadata - * (type: 'tool') unless they are dynamically materialised at runtime. + * A `tool` record is NEVER required, and the default third-party path + * declares none (ADR-0109). A name here resolves against, in order: the + * stack's own `stack.tools[]` names; `PLATFORM_PROVIDED_TOOL_NAMES`, the + * curated registry of tools the cloud AI runtime registers at boot; and the + * `action_` family the runtime materialises from the app's own + * AI-exposed declarative actions (`ai.exposed` + `ai.description` on a + * headless action type — ADR-0011). The first of those is the OPTIONAL + * AI-presentation refinement layer (Phase 2: LLM-facing description, + * parameter narrowing, flow exposure) and has no runtime reader until that + * lands, so a `stack.tools` record authored today is inert. In the default + * path the executable, its authz and its audit stay on the action/flow the + * app already ships. * * **CLOUD-RUNTIME-ONLY** (#3905). Tool binding is consumed by the in-product * agent runtime, which composes an agent's tool set from its From 9259145cb80c68eeefdf5ff3ad19d90406cbc581 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 21 Aug 2026 07:53:00 +0000 Subject: [PATCH 2/2] docs(changeset): correct how the skill.tools docblock reaches consumers Measured after a real DTS build: property-level comments inside the `z.object({ ... })` literal do NOT survive into `dist/*.d.ts` (the emitted declaration is a bare `tools: z.ZodArray;`). The text ships instead through `@objectstack/spec`'s `files` list, which publishes `src/**/*.zod.ts`, so the docblock travels in the npm tarball as source. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01B4h3medzvhB9rpfoja9jcw --- .changeset/skill-tools-docblock-adr-0109.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/skill-tools-docblock-adr-0109.md b/.changeset/skill-tools-docblock-adr-0109.md index 8e833c23f1..c733525762 100644 --- a/.changeset/skill-tools-docblock-adr-0109.md +++ b/.changeset/skill-tools-docblock-adr-0109.md @@ -8,4 +8,4 @@ The text now mirrors the resolution universe `@objectstack/lint`'s `validate-ai-tool-references` actually implements: a `tool` record is never required and the default third-party path declares none; a `skill.tools[]` name resolves against the stack's own `stack.tools[]` names, `PLATFORM_PROVIDED_TOOL_NAMES`, and the `action_` family the runtime materialises from AI-exposed declarative actions (`ai.exposed` + `ai.description` on a headless action type, per ADR-0011). It also records that `stack.tools` is the optional Phase-2 AI-presentation refinement layer with no runtime reader until that phase lands — so a record authored today is inert, which the old sentence recommended authoring without saying. -Prose only: no schema shape, no `.describe()` text, no runtime behaviour and no authorable surface changes. It reaches the published package through the generated `.d.ts`, which is why it is graded rather than skipped — this is the docblock an AI author reads while writing `skill.tools[]`, the exact surface ADR-0109 was written to keep clean. +Prose only: no schema shape, no `.describe()` text, no runtime behaviour and no authorable-surface change (`check:authorable-surface` and the whole `check:generated` set are unmoved by this diff). It is graded rather than skipped because the text ships to consumers: `@objectstack/spec`'s `files` list publishes `src/**/*.zod.ts`, so this docblock travels in the npm tarball as source. It does **not** reach `dist/*.d.ts` — property-level comments inside the `z.object({ … })` literal are dropped from the emitted declarations, which is measurable in the built chunk (`tools: z.ZodArray;`, no comment). Published source is the surface that matters here anyway: this is the docblock an AI author reads while writing `skill.tools[]`, the exact surface ADR-0109 was written to keep clean.