Skip to content

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

Description

@lukemaj

Part of toolboxmd/model-router#115 (the spec; read it first). Stream A: fork server and contracts.

Scope

  • Prism MCP toolkit next to the threads toolkit: prism_submit, prism_status, prism_questions, prism_answer. They call the installed router CLI (~/.codex/plugins/cache/toolboxmd/model-router/<newest>/bin/model-router, state dir ~/.local/share/durable-runner), pass the calling thread as --planner-t3-thread and supply the server URL and a token themselves. Tool descriptions say what each is for and when to use it (prism_submit = full job with dispatcher, fallback, recovery, one PR; spawn_thread(role) = small direct work).
  • spawn_thread accepts role (planner, dispatcher, reviewer, worker, correction, recovery) and applies that role's kit and preferred model unless a model is named; thread-tool scope per role as in Prism role for the Promachos picks his conversation's model #115.
  • Role kits and per-role ordered model preferences live in Chromeria settings, scoped per project and environment like Providers; define the schema in packages/contracts first and push that commit early (stream C builds the settings page on it).
  • An HTTP endpoint returning the provider snapshot (enabled models, options, usage windows with resetsAt) plus role preferences, for the router; turn on interval refresh for OpenCode usage.

Proof

Server tests per tool, role and scope; typecheck, lint, fmt; fork CI (GitHub-hosted); live check on an isolated instance.

Activity

  1. lukemaj commented on Sep 25, 2026

    @lukemaj
    ContributorAuthor

    Router side (stream B, toolboxmd/model-router#116) is building its snapshot reader against this provisional contract. Whatever stream A ships wins; the router keeps the contract in one parser, so a different path or field name is a small edit. Please note any difference here.

    • GET /api/prism/snapshot (optional ?projectId=), same bearer token as /api/orchestration/*.
    • Body: {"checkedAt": ISO, "providers": [ServerProvider], "rolePreferences"?: {role: [{"instanceId", "model", "options"?: {...}}]}}.
    • Fields the router reads from each ServerProvider: instanceId, enabled, availability (absent = available), models[].slug (enabled models only), usageLimits.windows[] (usedPercent, resetsAt), usageLimits.checkedAt.
    • Router rules: a window at 100 % with a future resetsAt blocks every route on that instance's meter until then; 100 % with no resetsAt blocks until the next read; 80 % or more is degraded. OpenCode's windows apply to Go models only (Zen free keeps its own error mark).
    • A 404 or unreachable endpoint means the snapshot is unknown: the router does not filter routes and relies on policy defaults plus error marks, so it keeps working on servers that don't have the endpoint.
  2. lukemaj commented on Sep 25, 2026

    @lukemaj
    ContributorAuthor

    Contracts pushed early for stream C: commit 2c7afaa on feat/19-prism-toolkit.

    • packages/contracts/src/prism.ts: PRISM_ROLES, PrismRole, PrismThreadToolScope (planner | children | project-read | none), PrismModelPreference ({instanceId, model, effort?}), PrismRoleKits (per role: instructions, runtimeMode?, skills, threadTools, ordered models), PrismRoleKitsPatch (per role, per field; arrays replace whole), DEFAULT_PRISM_ROLE_KITS.
    • settings.ts: server setting prismRoles, in PROJECT_SCOPED_SERVER_SETTING_KEYS (project override replaces the whole kit set, like other scoped keys), ServerSettingsPatch.prismRoles.
    • prismSnapshot.ts: PrismProviderSnapshot for GET /api/prism/snapshot (providers with models, options via capabilities, usage windows with resetsAt, plus resolved role kits).
  3. lukemaj commented on Sep 25, 2026

    @lukemaj
    ContributorAuthor

    Contract update pushed: 9d22ee3 on feat/19-prism-toolkit (supersedes the models field of 2c7afaa).

    • PRISM_LANES / PrismLane = easy | medium | hard, DEFAULT_PRISM_LANE = medium.
    • Each role kit: lanes: { easy, medium, hard }, each an ordered PrismModelPreference[] ({instanceId, model, effort?}): first = primary, rest = fallbacks; one model at another effort is its own entry. models is gone. Recovery keeps its own lanes.
    • PrismRoleKitsPatch: { <role>: { lanes: { <lane>: [...] } } }, a lane's list replaces whole.
    • PrismProviderSnapshot.roles carries the same structure. No capability tags.
  4. lukemaj commented on Sep 25, 2026

    @lukemaj
    ContributorAuthor

    Correction to the note on 9d22ee3: knip rejects the unused PRISM_LANES export, so it is module-local from c18070d on; list lanes with PrismLane.literals. Everything else in the contract is unchanged.

  5. lukemaj commented on Sep 25, 2026

    @lukemaj
    ContributorAuthor

    Stream B update: toolboxmd/model-router#119 reads the contract exactly as feat/19-prism-toolkit has it: GET /api/prism/snapshot?projectId=, {generatedAt, projectId, providers[{instanceId, driver, enabled, models[].slug, usageLimits.windows}], roles.<role>.lanes.{easy,medium,hard}[{instanceId, model, effort?}]}. My earlier rolePreferences proposal is withdrawn. The router maps worker easy/medium/hard onto its small/default/hard lanes, and dispatcher, correction and recovery onto the job's lane. It treats enabled: false or a model missing from models as ineligible. Two things are still unverified live: whether models lists only the models enabled in Providers, and the exact OpenCode slugs (opencode/muse-spark-1.3-contributor-free, opencode-go/...).

  6. added 4 commits that reference this issue on Sep 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions