Repository navigation
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agents read each tool's encoded-side JSON schema. A description set with .annotate on a trimmed string lands on the decoded side and never reaches them. Annotate the optional wrapper, as this code already does elsewhere, or use Schema.annotateEncoded where the field is required. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both fields add their description with `.annotate` after a `Schema.makeFilter` check, which loses it from the encoded and the decoded projection alike, so agents got bare strings and the walk in tools.test.ts could not see the gap. Move both to `Schema.annotateEncoded`, pin them by name, and say in the walk's comment what it cannot catch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The guard walk now follows every anyOf member and array items, which exposes timeOfDay, signature.header and filters[].path on schedule_task and update_scheduled_task. They move to Schema.annotateEncoded like the other trimmed-string fields. Three more pins cover array items and union members. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — This is a focused MCP schema metadata fix that makes existing parameter descriptions visible to agents without changing validation, tool execution, defaults, or production infrastructure. The added coverage checks all registered toolkits, including nested and union-based parameters. You can add or adjust custom eligibility rules. Learn more. |
|
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
Schema description annotations packages/contracts/src/orchestratorMcp.ts, packages/contracts/src/device.ts, packages/contracts/src/scheduledTask.ts, packages/contracts/src/threadMetadataMcp.ts, packages/contracts/src/worktreeMcp.ts, apps/server/src/mcp/toolkits/pullRequests/tools.ts |
Descriptions move to encoded-schema or optional-schema annotations across contract fields and pull-request tool parameters. Types, optionality, and stated validation constraints remain unchanged. |
Served schema description checks apps/server/src/mcp/toolkits/tools.test.ts |
Tests compare decoded parameter descriptions with served JSON schemas and check descriptions on selected fields and nested paths. |
Priority:
Estimated code review effort: 2 (Simple) | ~10 minutes
Change: Bug fix
Possibly related PRs
- pingdotgg/t3code#23996: Changes the description for
PullRequestTargetInput.url, which is also covered by the annotation changes here.
Suggested reviewers: juliusmarminge
Merge Risk: 
Minimal · up to e88f9
-
No actionable merge-blocking risk was identified.
Pre-merge checks: 
4
-
Full details: Description check
-
Explanation
The description covers the required Problem, Change, Scope and approval, and Verification sections. It explains the schema annotation issue, implementation, affected files and tools, testing results, limitations, and lack of prior issue or approval due to the focused bug fix.
-
Finishing Touches
-
🧪 Generate unit tests (beta)
-
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Comment @coderabbitai help to get the list of available commands.
…hestra Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hestra Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hestra Resolve PullRequestTargetInput in pullRequests/tools.ts: keep this branch's outer Schema.optional(...).annotate shape so the descriptions reach the tool schema, and take main's host-neutral url and host description text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Problem
Every agent that uses T3's MCP tools gets 67 parameters with no description, even though each one has a description in the source. Examples:
delegate_task.task, thepromptof eachcreate_threadsentry, sevenclientRequestIdfields,schedule_task'stimeOfDay, andurl,repositoryandhoston the pull request tools. The model sees only{"type": "string"}and guesses what to pass.The cause is one rule in Effect Schema.
TrimmedNonEmptyStringand the ids built on it are transformations, and.annotate()writes to the decoded side.Tool.getJsonSchema, whichMcpHttpServerserves as each tool'sinputSchema, renders the encoded side, so the description is dropped. Fields whose base type is not a transformation (PositiveInt,Schema.Boolean, literals) keep theirs..annotateafter aSchema.makeFiltercheck loses the description on both sides, which dropst3_thread_update'sclientRequestIdandpullRequest.url.It affects 23 tools in the orchestrator, pull request, worktree and device toolkits. The preview toolkit already works around it, and #22889 added another case (
orchestrator_capabilities.search).Change
Each description moves to where the encoded schema sees it. Text, types, decoding and validation are unchanged.
Schema.optional(...)wrapper instead of the inner schema, asorchestratorMcp.tsalready does forplaceholderand fix(server): t3_thread_read clamps oversized page sizes instead of failing #22901 did for thet3_thread_readlimits. 17 sites.OrchestratorMcpPrompt,OrchestratorMcpTitle,OrchestratorMcpClientRequestIdandThreadMetadataTitleconstants, the two filteredt3_thread_updatefields and three scheduled task fields (timeOfDay,signature.header, webhook filterpath):Schema.annotateEncoded, Effect's encoded-side counterpart ofannotate. 15 sites.A new test,
apps/server/src/mcp/toolkits/tools.test.ts, walks every registered toolkit. It fails when a description written on the decoded side is missing from the schema agents get, following nested objects, every union member and array items. It also pins twelve fields by name, including the twot3_thread_updatefields the walk cannot see.Size: +137/−131 production lines over 32 sites in six files; the test adds 111.
Scope and approval
No issue or open PR covers this, and it changes no behavior. At 2026-10-22T02:37Z, 38 open PRs touch these files: #11635, #14617, #15111, #15622, #15904, #15975, #16654, #16684, #16719, #16731, #16751, #17129, #18371, #19143, #19758, #20056, #20937, #21105, #21222, #21514, #21636, #21710, #21714, #21791, #21792, #22093, #22281, #22355, #22394, #22464, #23055, #23088, #23111, #23131, #23252, #23256, #23277 and #23278. Six edit lines this PR also edits, so whichever lands second needs a small rebase: #22464 rewrites the
url,repositoryandhostdescriptions inPullRequestTargetInput, #15975 and #16654 exportOrchestratorMcpClientRequestId, and #23252 rewrites the webhook filterpathdescription. None of the 38 changes how descriptions are emitted. #16751 addst3_thread_handofffields in the old form; if it lands after this, the new test lists them.Verification
The new test against main's source, then on the branch:
Real app, Linux, production builds of
mainand the branch with fresh state, using the real Pi agent (@earendil-works/pi-coding-agent1.3.0) on anopenai-completionsmodel pointed at a local stub that logs each request'stools. I sent "hello" in a new thread and compared the first request from each build. The same 67 parameters gain descriptions, none lose one, and with descriptions removed every tool's parameter schema is identical.Other checks on the branch:
vp test runfor the new test, the orchestrator, preview and pull request toolkit tests,core.test.ts, the scheduled task tests andMcpHttpServer.test.ts: 140 passed.packages/contractsvp test run: 139 passed.typecheckforpackages/contractsandapps/server, plusvp lintandvp fmt --checkon the changed files: pass.Nothing on screen changes. No UI reads these schemas; only
McpHttpServerserves them.Not checked:
inputSchema.maxLengthon these strings is also missing from the served schema for the same reason. That is a separate change.Prior PRs
None for this bug. #22652 by @grey-tsosie, folded into #22901, described the
t3_thread_readlimits and used the optional-wrapper form this PR follows.Production fix, tests, PR description and images written with Claude Opus 5.5 in T3 Code Nightly.
🤖 Generated with Claude Opus 5.5 in T3 Code Nightly