Skip to content

feat(server): Prism MCP toolkit, spawn_thread(role), role kits and provider snapshot - #22

Merged
lukemaj merged 5 commits into
mainfrom
feat/19-prism-toolkit
Sep 25, 2026
Merged

lukemaj merged 5 commits into
mainfrom
feat/19-prism-toolkit

Conversation

@lukemaj

@lukemaj lukemaj commented Sep 25, 2026 •

Copy link
Copy Markdown

Closes #19. Stream A of toolboxmd/model-router#115.

Problem

Planners reach Prism (Model Router) through a CLI and have to find a T3 token themselves, spawn_thread cannot start roles, role preferences have no home, and the router has no way to read Chromeria's providers, models and limits.

Change

  • Contracts (packages/contracts/src/prism.ts, prismSnapshot.ts; pushed early as 2c7afaa, lanes as 9d22ee3, for streams B and C): six roles with kits (instructions, runtime mode, skills, thread-tool scope) and, per lane (easy, medium, hard), an ordered list of {instanceId, model, effort?}: first entry primary, the rest fallbacks, one model at another effort is its own entry. Stored as the project-scoped server setting prismRoles, with a per-role, per-lane patch; the snapshot response schema carries the same structure. No capability tags.
  • Prism MCP toolkit (toolkits/prism/): prism_submit, prism_status, prism_questions, prism_answer run the newest installed model-router CLI (PRISM_ROUTER_BIN overrides) with --planner-t3-thread = the calling thread, the server's own URL and a fresh token scoped to orchestration:read + orchestration:operate (30-day TTL, never admin). lane is easy/medium/hard, mapped to the installed router's small/default/hard until the router accepts the new names. Planner threads only. Descriptions say when to use prism_submit versus spawn_thread(role).
  • spawn_thread(role, lane?) (lane defaults to medium): applies the role's kit: instructions and skills lead the first message, runtime mode, and the first entry of that lane's list that is enabled in Providers, offered by the instance and not at a 100 % usage window before its resetsAt, unless a model or instance is named. A role with preferences but no eligible model refuses with the reasons (no silent substitution); a role without preferences uses this thread's model. The role is encoded in the child id (sub.<parent>.<role>-<rand>), so it survives restarts.
  • Thread-tool scope per role: planner (top-level thread) all tools with project scope plus Prism tools; dispatcher read/list/message its own children; reviewer read and list with project scope; worker, correction, recovery none. Children without a role prefix (direct spawns, today's router threads) keep their previous tools and get no Prism tools.
  • GET /api/prism/snapshot[?projectId=] (bearer with orchestration:read): each provider instance with enabled flag, status, models (capabilities carry the options) and usage windows with resetsAt, plus the role kits resolved for the project.
  • OpenCode usage now refreshes on the provider health interval (refreshOnInterval: true).
  • Upstream edits allowlisted and listed in docs/fork.md: contracts/src/index.ts, contracts/src/settings.ts, McpHttpServer.ts, threads tools.ts/handlers.ts, OpenCodeDriver.ts.

Proof

  • Tests: roles.test.ts (role from id, tool scope per role, eligibility, usage blocking, first message), prism/handlers.test.ts (submit argv, router output and errors, state dir, newest-version discovery), snapshotRoute.test.ts, contracts/prism.test.ts; threads, prism, snapshot and McpHttpServer suites 58/58; shared project settings 49/49; web settings 454/454; driver suites 95/95 in the documented host-neutral env (3 CodexDriver tests fail only with Homebrew on PATH, as docs/fork.md describes).
  • Typecheck (contracts, shared, server, web, mobile), vp lint, vp fmt --check, scripts/fork-check.sh: pass.
  • Lane live check (second isolated server, port 38918): reviewer hard = [opencode/muse high (instance disabled), claude-haiku-4-5 high] started on claude-haiku-4-5 effort high (fallback); reviewer without lane started on the medium primary claude-sonnet-5 effort low; prism_submit lane easy reached the router as --lane small and persisted implementation_small; recovery reported its own empty lanes in the snapshot.
  • Live check on an isolated server from this worktree (T3CODE_HOME=/tmp/prism-live/home, port 38917, router state in /tmp, router wrapped to force --no-start): unauthenticated snapshot 401; with token 200 with real Codex and Claude windows and resetsAt; settings edits appear in the snapshot. A Claude Haiku 4.5 planner thread called every tool: spawn_thread(role: reviewer) created sub.live-planner.reviewer-… on the reviewer's preferred model (claude-haiku-4-5, effort low) with the kit's instructions and skills first; that reviewer's list_threads(scope: project) worked and its spawn_thread was refused with This role may only read threads.; spawn_thread(role: worker) refused with No eligible model for this role: opencode/opencode/muse (instance disabled).; prism_submit persisted a job with planner_t3_thread, planner_harness: t3, lane small and the server URL, the router received a token scoped to orchestration:read/orchestration:operate; prism_status returned pending; prism_questions returned none.

Not covered

  • Per-model hiding in Providers is client-local upstream (providerModelPreferences), so the server cannot see it; eligibility uses enabled instances and offered models.
  • Interval refresh runs only while a client creates provider-status demand (upstream BackgroundPolicy).
  • The router should name its threads dispatcher-…/worker-… to get role scopes (stream B).

Model and harness: Claude Opus 5.5 in Claude Code.

🤖 Generated with Claude Code

lukemaj and others added 2 commits September 25, 2026 19:50
Role kits (instructions, runtime mode, skills, thread-tool scope) and
ordered model preferences for the six Prism roles, stored as the
project-scoped server setting prismRoles, with a per-role patch. Adds the
GET /api/prism/snapshot response schema for the router.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…shot endpoint (#19)

Adds prism_submit, prism_status, prism_questions and prism_answer, which
run the installed Model Router CLI with the calling thread as the T3
planner and a server URL plus an orchestration-scoped token supplied by
the server. spawn_thread takes a Prism role, applies its kit and first
eligible preferred model, and each role's thread-tool scope is enforced.
GET /api/prism/snapshot returns providers, models, usage windows with
resetsAt and the role kits resolved for a project. OpenCode usage now
refreshes on the provider health interval.

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:XL labels Sep 25, 2026
@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 13.5 KiB 13.5 KiB +12 B (+0.1%) 15.1 KiB ✅
Codex Thread snapshot wire 7.1 KiB 7.1 KiB −6 B (−0.1%) 7.3 KiB ✅
Codex Live turn WebSocket wire 6.4 KiB 6.5 KiB +18 B (+0.3%) 7.8 KiB ✅
Codex Live turn WebSocket decoded 56.2 KiB 56.3 KiB +44 B (+0.1%) 66.4 KiB ✅
Codex Live turn messages 9 10 +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 +4 B (+0.1%) 7.3 KiB ✅
Claude Live turn WebSocket wire 6.4 KiB 6.4 KiB −27 B (−0.4%) 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: fc62c05 · PR result: c18070d · 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.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
lukemaj and others added 2 commits September 25, 2026 20:17
Each role keeps an ordered list of {instanceId, model, effort} per lane
(easy, medium, hard): the first entry is the primary choice, the rest are
fallbacks, and one model at another effort is its own entry. Adds
PrismLane (default medium) and per-lane patching. The snapshot carries
the same structure through PrismRoleKits.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…it (#19)

spawn_thread takes an optional lane (default medium) and walks that
role's lane list, primary first then fallbacks. prism_submit takes
easy, medium or hard and maps them onto the installed router's
small, default and hard lanes. PRISM_LANES stays module-local for knip;
PrismLane.literals lists the lanes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@lukemaj
lukemaj merged commit 6f9364f into main Sep 25, 2026
19 checks passed
@lukemaj
lukemaj deleted the feat/19-prism-toolkit branch September 25, 2026 18:29
lukemaj added a commit that referenced this pull request Sep 27, 2026
…ovider snapshot (#22)

* feat(contracts): Prism role kits and provider snapshot schema (#19)

Role kits (instructions, runtime mode, skills, thread-tool scope) and
ordered model preferences for the six Prism roles, stored as the
project-scoped server setting prismRoles, with a per-role patch. Adds the
GET /api/prism/snapshot response schema for the router.

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

* feat(server): Prism MCP toolkit, spawn_thread(role) and provider snapshot endpoint (#19)

Adds prism_submit, prism_status, prism_questions and prism_answer, which
run the installed Model Router CLI with the calling thread as the T3
planner and a server URL plus an orchestration-scoped token supplied by
the server. spawn_thread takes a Prism role, applies its kit and first
eligible preferred model, and each role's thread-tool scope is enforced.
GET /api/prism/snapshot returns providers, models, usage windows with
resetsAt and the role kits resolved for a project. OpenCode usage now
refreshes on the provider health interval.

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

* chore: drop unused Prism exports flagged by knip (#19)

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

* feat(contracts): Prism model lists per role and lane (#19)

Each role keeps an ordered list of {instanceId, model, effort} per lane
(easy, medium, hard): the first entry is the primary choice, the rest are
fallbacks, and one model at another effort is its own entry. Adds
PrismLane (default medium) and per-lane patching. The snapshot carries
the same structure through PrismRoleKits.

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

* feat(server): pick role models by lane in spawn_thread and prism_submit (#19)

spawn_thread takes an optional lane (default medium) and walks that
role's lane list, primary first then fallbacks. prism_submit takes
easy, medium or hard and maps them onto the installed router's
small, default and hard lanes. PRISM_LANES stays module-local for knip;
PrismLane.literals lists the lanes.

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
lukemaj added a commit that referenced this pull request Sep 27, 2026
…ovider snapshot (#22)

* feat(contracts): Prism role kits and provider snapshot schema (#19)

Role kits (instructions, runtime mode, skills, thread-tool scope) and
ordered model preferences for the six Prism roles, stored as the
project-scoped server setting prismRoles, with a per-role patch. Adds the
GET /api/prism/snapshot response schema for the router.

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

* feat(server): Prism MCP toolkit, spawn_thread(role) and provider snapshot endpoint (#19)

Adds prism_submit, prism_status, prism_questions and prism_answer, which
run the installed Model Router CLI with the calling thread as the T3
planner and a server URL plus an orchestration-scoped token supplied by
the server. spawn_thread takes a Prism role, applies its kit and first
eligible preferred model, and each role's thread-tool scope is enforced.
GET /api/prism/snapshot returns providers, models, usage windows with
resetsAt and the role kits resolved for a project. OpenCode usage now
refreshes on the provider health interval.

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

* chore: drop unused Prism exports flagged by knip (#19)

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

* feat(contracts): Prism model lists per role and lane (#19)

Each role keeps an ordered list of {instanceId, model, effort} per lane
(easy, medium, hard): the first entry is the primary choice, the rest are
fallbacks, and one model at another effort is its own entry. Adds
PrismLane (default medium) and per-lane patching. The snapshot carries
the same structure through PrismRoleKits.

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

* feat(server): pick role models by lane in spawn_thread and prism_submit (#19)

spawn_thread takes an optional lane (default medium) and walks that
role's lane list, primary first then fallbacks. prism_submit takes
easy, medium or hard and maps them onto the installed router's
small, default and hard lanes. PRISM_LANES stays module-local for knip;
PrismLane.literals lists the lanes.

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
lukemaj added a commit that referenced this pull request Sep 27, 2026
…ovider snapshot (#22)

* feat(contracts): Prism role kits and provider snapshot schema (#19)

Role kits (instructions, runtime mode, skills, thread-tool scope) and
ordered model preferences for the six Prism roles, stored as the
project-scoped server setting prismRoles, with a per-role patch. Adds the
GET /api/prism/snapshot response schema for the router.

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

* feat(server): Prism MCP toolkit, spawn_thread(role) and provider snapshot endpoint (#19)

Adds prism_submit, prism_status, prism_questions and prism_answer, which
run the installed Model Router CLI with the calling thread as the T3
planner and a server URL plus an orchestration-scoped token supplied by
the server. spawn_thread takes a Prism role, applies its kit and first
eligible preferred model, and each role's thread-tool scope is enforced.
GET /api/prism/snapshot returns providers, models, usage windows with
resetsAt and the role kits resolved for a project. OpenCode usage now
refreshes on the provider health interval.

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

* chore: drop unused Prism exports flagged by knip (#19)

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

* feat(contracts): Prism model lists per role and lane (#19)

Each role keeps an ordered list of {instanceId, model, effort} per lane
(easy, medium, hard): the first entry is the primary choice, the rest are
fallbacks, and one model at another effort is its own entry. Adds
PrismLane (default medium) and per-lane patching. The snapshot carries
the same structure through PrismRoleKits.

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

* feat(server): pick role models by lane in spawn_thread and prism_submit (#19)

spawn_thread takes an optional lane (default medium) and walks that
role's lane list, primary first then fallbacks. prism_submit takes
easy, medium or hard and maps them onto the installed router's
small, default and hard lanes. PRISM_LANES stays module-local for knip;
PrismLane.literals lists the lanes.

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL 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.

Prism in Chromeria: MCP toolkit, spawn_thread(role), role settings schema, provider snapshot endpoint

1 participant