Skip to content

feat(server): route delegated work through spawn_thread roles - #104

Merged
lukemaj merged 2 commits into
mainfrom
feat/96-routing-instructions
Oct 1, 2026
Merged

lukemaj merged 2 commits into
mainfrom
feat/96-routing-instructions

Conversation

@lukemaj

@lukemaj lukemaj commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

What: Every coordinating thread's launch prompt and the spawn_thread / interrupt_thread descriptions now carry the routing rules: delegate with roles, start a dispatcher for one-PR jobs, recover a failed child by interrupting it and, once settled, starting retry, then escalation.
Why: With the runner retiring, whoever coordinates decides lane, recovery order and review; the planner is never spawned, so only the tool-instruction block reaches it.
So what: The planner reviews and merges this PR, stages the build, then runs the two live tasks in #96 (planner dispatches itself; planner starts a dispatcher).

Refs #96

New instruction text (apps/server/src/mcp/toolInstructions.ts, 1,606 characters)

Reach for the t3-code tools when work should stay visible in this T3 Code thread: delegating to other agents, testing web or native UI, and linking Issues. Delegate with them, never by starting codex exec, claude -p, opencode run or grok in the shell: the user cannot see those runs. Delegate with spawn_thread and a role (worker with a lane by difficulty, reviewer); Prism picks the model. For a job that ends in one PR, start spawn_thread(role: dispatcher) with the brief, unless the user or a comparison job says to coordinate it yourself. When a child fails, hits a limit or goes stale, interrupt_thread it and, once it reports settled, spawn retry, then escalation, then ask whoever started you. Only if no dispatcher can start, fall back to prism_submit: Prism picks models, recovers failures and wakes you only for judgment (prism_questions, then prism_answer). When a Prism job blocks, loops or misbehaves, have a spawn_thread child with role reviewer confirm the defect from prism_status and ~/.local/share/durable-runner/outputs//, then open or update the toolboxmd/model-router Issue with that confirmation, then start a spawn_thread child with role worker on the fix in its own worktree, with a normal PR and review. Meanwhile keep the job going or recover it. Comment an unconfirmed suspicion on an existing Issue or drop it; never file it as a new Issue. For small direct work, or when a specific model and effort is wanted, call spawn_thread, then read_thread and message_thread. For web UI: preview_open, preview_snapshot, then act. For simulators: device_list, then device_open.

The three routing sentences come right after the shell rule. The prism_submit sentence now applies only when no dispatcher can start; #97 removes it and the defect paragraph after the live tasks.

Tool descriptions (apps/server/src/mcp/toolkits/threads/tools.ts)

  • spawn_thread: > Use when another agent should do work: a bounded task, a review, or a whole job that ends in one PR (role: dispatcher). Use it instead of codex exec, claude -p, opencode run or grok in the shell: the user cannot see those runs. role applies that Prism role's kit and first eligible model, skipping providers at a usage limit: worker with a lane by difficulty, reviewer, and retry then escalation to replace a failed child. Or name instance, model and effort. Each finished turn of the child reports its final reply here unless reportBack is false. Follow up with read_thread and message_thread.
  • interrupt_thread: "Use it before replacing a stalled, failed or usage-limit-hit child with role retry, then escalation, so two threads never write to the same branch."

These match the current code: pickRoleModel skips providers that isProviderBlocked marks as limit-hit, and reportBack defaults to true.

Default Prism role instructions

None ship. DEFAULT_PRISM_ROLE_KITS is Schema.decodeSync(PrismRoleKits)({}), and every kit's instructions defaults to "" and skills to [] (packages/contracts/src/prism.ts). Settings has no other default. A new test in packages/contracts/src/prism.test.ts pins this for all six roles.

Proof (head 6d52607, Node 24.13.1)

  • vp test run apps/server/src/mcp/toolInstructions.test.ts apps/server/src/mcp/alwaysLoad.test.ts packages/contracts/src/prism.test.ts apps/server/src/mcp/toolkits/threads: 10 files, 71 tests passed (includes the Codex 3,000-character runtime cap test).
  • tsc --noEmit in apps/server and packages/contracts: exit 0, no errors.
  • vp lint and vp fmt --check on the 5 changed files: clean.
  • bash scripts/fork-check.sh --upstream upstream: fork-features: OK (19 features). fork-check: OK.
  • Review fix from Codex gpt-6-luna on d2bea2e: the replacement starts only after the interrupt reports settled (interrupted or no_active_run), never on interrupt_requested; spawn_thread notes reportBack: false.
  • handlers.ts is untouched (PR feat(server): direct child threads resume on their own after a usage limit #72 rebase owns it).

Elon record

🤖 Generated with Claude Code

The tool-instruction block now tells every coordinating thread to delegate
with spawn_thread roles, start a dispatcher for one-PR jobs, and recover a
failed child with interrupt_thread, retry, then escalation. prism_submit stays
only as the fallback until #97 removes it. spawn_thread and interrupt_thread
descriptions carry the mechanics; a test pins that Prism role kits ship no
default instructions.

Refs #96

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:S labels Oct 1, 2026
@lukemaj

lukemaj commented Oct 1, 2026

Copy link
Copy Markdown
Contributor Author

Independent review of d2bea2e: request changes

  1. apps/server/src/mcp/toolInstructions.ts:12 tells every coordinator to interrupt a child, then spawn retry, without handling interrupt_requested. If a stalled child is still running after the 30-second wait, interrupt_thread returns that status and the tool description says to read the thread before replacing it; following the shared launch instruction as written can start a second writer on the same branch.
  2. apps/server/src/mcp/toolkits/threads/tools.ts:136 says every finished child turn reports its final reply here, but spawn_thread({ reportBack: false }) disables that behavior (handlers.ts:656). A caller that opts out is told to expect reports that will never arrive; qualify the promise as default/conditional.

Review on #104: interrupt_requested can leave the child running, so the
replacement waits for a settled report; spawn_thread notes reportBack: false.

Refs #96

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ℹ️ The exact PR base did not have a successful artifact. Baseline uses the latest successful main measurement shown below.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 13.5 KiB 13.5 KiB −16 B (−0.1%) 15.1 KiB ✅
Codex Thread snapshot wire 7.1 KiB 7.1 KiB +11 B (+0.2%) 7.3 KiB ✅
Codex Live turn WebSocket wire 6.4 KiB 6.4 KiB −27 B (−0.4%) 7.8 KiB ✅
Codex Live turn WebSocket decoded 56.2 KiB 56.2 KiB −44 B (−0.1%) 66.4 KiB ✅
Codex Live turn messages 9 8 −1 (−11.1%) 21 ✅
Claude Total thread wire 13.5 KiB 13.5 KiB +23 B (+0.2%) 15.1 KiB ✅
Claude Thread snapshot wire 7.1 KiB 7.1 KiB +9 B (+0.1%) 7.3 KiB ✅
Claude Live turn WebSocket wire 6.4 KiB 6.4 KiB +14 B (+0.2%) 7.8 KiB ✅
Claude Live turn WebSocket decoded 57.0 KiB 57.0 KiB 0 B (0.0%) 66.4 KiB ✅
Claude Live turn messages 9 9 0 (0.0%) 21 ✅

Baseline: 9f1f2c4 · PR result: 6d52607 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 113.9 KiB
  • Claude decoded thread snapshot: 114.6 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@lukemaj

lukemaj commented Oct 1, 2026

Copy link
Copy Markdown
Contributor Author

Independent review of 6d52607: approve

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant