verbspec: single-source the Anthropic report tool from a VerbSpec (Thread 2 Step 1) - #18
Merged
Conversation
…read 2 Step 1) Author the `report` verb ONCE as a verbspec VerbSpec (typed Zod input: score integer 0..10, findings string[]) and project it to the Anthropic tool surface via toAnthropicTool — instead of hand-writing REPORT_TOOL.input_schema. Same typed contract a CLI/MCP/OpenAPI projection reads, so the structured-output schema can't drift from them. The projected input_schema deep-equals the previous hand-written one; z.toJSONSchema's `$schema` draft pointer is stripped so the wire payload is byte-equivalent. buildRequest / parseResponse are untouched — the LLM path is identical to v0.3.x (tool_choice still forces `report`; parseResponse still reads tool_use.input). test.mjs now also pins the exact projected schema, guarding against a verbspec/zod bump silently drifting the contract. Deps: verbspec (npm:@jsr/...) + its zod peer become regular runtime deps — anthropic.mjs is imported by audit.mjs + test.mjs, so the core CI install (npm ci --omit=optional) pulls them; only the heavy cas/anchored-chain CAS backends stay optional. The site's prose-only gate (prose.mjs) is unaffected — it never imports anthropic.mjs. Verified locally: full ci.yml sequence green (core install = prose+verbspec, no CAS; test/audit/cache/extract; optional CAS install + socket store). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This was referenced Jun 23, 2026
bdelanghe
added a commit
that referenced
this pull request
Jun 23, 2026
Bump 0.3.1 → 0.4.0 for the verbspec surfaces merged since v0.3.1: audit + extract authored once as VerbSpecs → CLI + MCP (string-audit-mcp bin), Anthropic report tool single-sourced from a VerbSpec (#18, #19); cas/anchored-chain made optional (#13, #15, #17). The release workflow auto-tags v0.4.0 on merge.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Thread 2, Step 1 of the verbspec integration (the highest-value, smallest surface).
What
The
reporttool — the Anthropic structured-output contract{score, findings}— was ahand-written
REPORT_TOOL.input_schemainanthropic.mjs. This authors it once as averbspec
VerbSpecand projects it to the Anthropic tool surface viatoAnthropicTool:It's the same typed contract a CLI / MCP / OpenAPI projection of the verb reads, so the
structured-output schema can't drift from them — the point of verbspec.
Behavior unchanged
input_schemadeep-equals the previous hand-written one (integer0..10,string[],required:[score,findings],additionalProperties:false,identical descriptions).
z.toJSONSchema's$schemadraft pointer is stripped, sothe wire payload is byte-equivalent.
buildRequest/parseResponseare untouched — the LLM path is identical to v0.3.x(
tool_choicestill forcesreport;parseResponsestill readstool_use.input).test.mjsnow also pins the exact projected schema (deepEqual), so a verbspec/zodbump can't silently drift the contract.
Dependencies
verbspec(npm:@jsr/bounded-systems__verbspec) + itszodpeer become regular runtimedeps —
anthropic.mjsis imported byaudit.mjsandtest.mjs, so the core CI install(
npm ci --omit=optional) pulls them; only the heavycas/anchored-chainCAS backendsstay optional. The consumer site's prose-only gate (
prose.mjs) is unaffected — itnever imports
anthropic.mjs. (ci.ymlcomment/step-name updated to reflect that the corenow installs verbspec; the "JSR-free core" framing is retired — only the CAS backends are
optional.)
Test — full
ci.ymlsequence locally (Node 24)Plus a direct
deepEqualof the projectedREPORT_TOOLagainst the original schema.Follow-up (Step 2, separate PR): author
audit+extractas VerbSpecs → project to CLIPR run sheet
RELEASE-v0.3.0.mdleft out.🤖 Generated with Claude Code