From f44719e5db1b5f69e8fb1dc0a7406374a5c40249 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 18 Oct 2026 22:13:36 +0700 Subject: [PATCH] claw: model_route.t27 -- Opus 5.5 orchestrates, Sonnet 5.5 runs sub-tasks (Closes #10492) Owner directive 2026-10-18. The law is specs/claw/model_route.t27 (6/6 tests, 0 vacuous, invariant proved; the orchestration-to-Sonnet mutant fails 3). Claude Code follows it through CLAUDE_CODE_SUBAGENT_MODEL in .claude/settings.json, model: in every .claude/agents/*.md (Queen on opus, the rest on sonnet) and the model-routing skill. Co-Authored-By: Claude Opus 5.5 --- .claude/agents/agent-c-compiler.md | 1 + .claude/agents/agent-e-experience.md | 1 + .claude/agents/agent-l-lsp.md | 1 + .claude/agents/agent-v-verify.md | 1 + .claude/agents/creator.md | 1 + .claude/agents/experience.md | 1 + .claude/agents/learner.md | 1 + .claude/agents/review-warden.md | 1 + .claude/agents/t27c-steward.md | 1 + .claude/agents/trinity.md | 1 + .claude/agents/verifier.md | 1 + .claude/settings.json | 3 + .claude/skills/model-routing/SKILL.md | 57 ++++++++++ .trinity/seals/claw_ClawModelRoute.json | 28 +++++ CLAUDE.md | 8 ++ docs/claw/README.md | 1 + specs/claw/model_route.t27 | 142 ++++++++++++++++++++++++ 17 files changed, 250 insertions(+) create mode 100644 .claude/skills/model-routing/SKILL.md create mode 100644 .trinity/seals/claw_ClawModelRoute.json create mode 100644 specs/claw/model_route.t27 diff --git a/.claude/agents/agent-c-compiler.md b/.claude/agents/agent-c-compiler.md index 29637ebdec..233ce6c84a 100644 --- a/.claude/agents/agent-c-compiler.md +++ b/.claude/agents/agent-c-compiler.md @@ -1,5 +1,6 @@ --- id: agent-c-compiler +model: sonnet name: Agent C - Compiler description: Compiles t27 specifications into executable code, manages three-roads generation and binary output triggers: diff --git a/.claude/agents/agent-e-experience.md b/.claude/agents/agent-e-experience.md index a67401af29..daf6517e62 100644 --- a/.claude/agents/agent-e-experience.md +++ b/.claude/agents/agent-e-experience.md @@ -1,5 +1,6 @@ --- id: agent-e-experience +model: sonnet name: Agent E - Experience description: Captures learnings from PHI LOOP cycles, maintains semantic memory, updates agent behaviors triggers: diff --git a/.claude/agents/agent-l-lsp.md b/.claude/agents/agent-l-lsp.md index 9a2dd1e500..5cb483817f 100644 --- a/.claude/agents/agent-l-lsp.md +++ b/.claude/agents/agent-l-lsp.md @@ -1,5 +1,6 @@ --- id: agent-l-lsp +model: sonnet name: Agent L - LSP Validator description: Validates language server protocol integration, type definitions, and IDE tooling for t27 specs and generated code triggers: diff --git a/.claude/agents/agent-v-verify.md b/.claude/agents/agent-v-verify.md index c1cffed9fc..1c85cd77aa 100644 --- a/.claude/agents/agent-v-verify.md +++ b/.claude/agents/agent-v-verify.md @@ -1,5 +1,6 @@ --- id: agent-v-verify +model: sonnet name: Agent V - Verification description: Validates generated code against specifications, runs conformance tests, ensures L1-L7 compliance triggers: diff --git a/.claude/agents/creator.md b/.claude/agents/creator.md index 5a478fbf28..f411e5c762 100644 --- a/.claude/agents/creator.md +++ b/.claude/agents/creator.md @@ -1,4 +1,5 @@ --- +model: sonnet description: Creator Agent - Generates code from specs, implements features color: "#3b82f6" --- diff --git a/.claude/agents/experience.md b/.claude/agents/experience.md index ca0c5ba646..bda6ef374e 100644 --- a/.claude/agents/experience.md +++ b/.claude/agents/experience.md @@ -1,4 +1,5 @@ --- +model: sonnet description: Experience Agent - Manages learning history, provides context, retrieves patterns color: "#f59e0b" --- diff --git a/.claude/agents/learner.md b/.claude/agents/learner.md index 8629876fd8..ac9e354ac5 100644 --- a/.claude/agents/learner.md +++ b/.claude/agents/learner.md @@ -1,4 +1,5 @@ --- +model: sonnet description: Learner Agent - Researches patterns, discovers insights, builds knowledge base color: "#8b5cf6" --- diff --git a/.claude/agents/review-warden.md b/.claude/agents/review-warden.md index bd9fb46781..0572addc93 100644 --- a/.claude/agents/review-warden.md +++ b/.claude/agents/review-warden.md @@ -1,4 +1,5 @@ --- +model: sonnet description: Review Warden - keeps pull-request review moving; measures the reviewer bee and the epics' CI, hands every fix to the Queen as a task she can run, and reports on the plan's issue color: "#f59e0b" --- diff --git a/.claude/agents/t27c-steward.md b/.claude/agents/t27c-steward.md index 74948c80c0..5262945cd3 100644 --- a/.claude/agents/t27c-steward.md +++ b/.claude/agents/t27c-steward.md @@ -1,5 +1,6 @@ --- name: t27c-steward +model: sonnet description: t27c Steward - keeps the silent-misread stack (epic #6092) moving to zero and holding there; reads the Railway t27c lab, hands spec-source fixes to the Queen as tasks she can run, drives compiler fixes through one lane at a time, reports on the epic color: "#22c55e" --- diff --git a/.claude/agents/trinity.md b/.claude/agents/trinity.md index f675801523..d6a4c99456 100644 --- a/.claude/agents/trinity.md +++ b/.claude/agents/trinity.md @@ -1,4 +1,5 @@ --- +model: opus description: Trinity Agent (Queen) - Orchestrates multi-agent coordination, executes AEL v2.0 color: "#ef4444" orchestrator: true diff --git a/.claude/agents/verifier.md b/.claude/agents/verifier.md index 6dc497d5e3..4c12f2eb52 100644 --- a/.claude/agents/verifier.md +++ b/.claude/agents/verifier.md @@ -1,4 +1,5 @@ --- +model: sonnet description: Verifier Agent - Validates correctness, runs conformance tests, ensures law compliance color: "#10b981" --- diff --git a/.claude/settings.json b/.claude/settings.json index bf23887c78..f83ad1ed64 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -1,4 +1,7 @@ { + "env": { + "CLAUDE_CODE_SUBAGENT_MODEL": "claude-sonnet-5-5" + }, "hooks": { "Stop": [ { diff --git a/.claude/skills/model-routing/SKILL.md b/.claude/skills/model-routing/SKILL.md new file mode 100644 index 0000000000..d05f475df1 --- /dev/null +++ b/.claude/skills/model-routing/SKILL.md @@ -0,0 +1,57 @@ +--- +id: model-routing +name: model-routing +description: Which Claude model does which job -- the orchestrator runs on Opus 5.5, every sub-task it delegates runs on Sonnet 5.5, and a sub-task escalates to Opus only after two failed attempts or on the owner's word. Load before spawning any subagent, writing a workflow, or picking a model in TRI CLAW or the Queen. +argument-hint: "[role: orchestrate|plan|review-final|implement|port|search|test|docs|fix]" +--- + +# /model-routing -- Opus orchestrates, Sonnet does the sub-tasks + + +> **Only t27: everything is written in `.t27`.** (Owner hard rule 2026-10-05; budget #7371; restated in every skill per #7588.) +> - New logic starts as a `.t27` spec with `test` / `invariant` blocks. It reaches Rust, C, Zig, JS or Python only through `t27c gen-*`, and generated files are never hand-edited (L2). +> - Hand-written code in any other language is denied by the hooks and by CI: `.rs .py .ts .js .sh .zig .c .go .v .yml .toml`, Dockerfile, Makefile; the full list is in `specs/policy/own_language.t27`. +> - Existing foreign code is debt that only shrinks. Delete it, or replace it with a spec and its generated output. +> - Thin hand-written glue is capped at 40 added lines per file and 80 per PR. No label lifts the cap. Never split a PR to slip under it. +> - What gen cannot express yet is a compiler defect. File it on #5980 with a minimal `.t27` repro instead of writing the code by hand. +> - This rule overrides any step below that says to write a script or code in another language. The full text is in `AGENTS.md`, "Only t27". + +Owner directive 2026-10-18: orchestration through Opus 5.5, sub-tasks through Sonnet 5.5, because it is cheaper; the rule is part of TRI CLAW so development stays economical. + +**The law is `specs/claw/model_route.t27`.** This skill is how to follow it in a Claude Code session. If the two disagree, the spec wins; fix the skill. + +## The rule + +| Role | Kind | Model | +|---|---|---| +| orchestrate, plan, review-final | orchestration | **Opus 5.5** (`opus`, `claude-opus-5-5`) | +| implement, port, search, test, docs, fix | sub-task | **Sonnet 5.5** (`sonnet`, `claude-sonnet-5-5`) | + +- A sub-task goes to Opus only on evidence: **2 failed Sonnet attempts on the same task** (`ESCALATE_AFTER`), or the owner says so. Nothing else raises a tier. +- Orchestration is never routed down. Splitting the work, deciding what is true, and saying merge or stop stay on Opus. +- Why: epic #10066 measured Sonnet 5.5 at least as good as Opus 5.5 on ten bounded spec-to-RTL tasks (9 vs 8 direct Verilog, 7 vs 7 in .t27) at about 40% of the cost. + +## How it is wired in Claude Code + +- `.claude/settings.json` sets `CLAUDE_CODE_SUBAGENT_MODEL=claude-sonnet-5-5`, so any subagent with no model of its own runs on Sonnet. +- Every sub-task agent in `.claude/agents/` carries `model: sonnet`; the orchestrator `trinity.md` (Queen) carries `model: opus`. +- The main session is the orchestrator: pick **Opus 5.5** for it in the app's model menu. + +## When you are the orchestrator + +1. Plan on Opus: split the task into sub-tasks with a clear input, output and done-check each. +2. Spawn each sub-task with the Agent tool. Leave `model` unset (the default is Sonnet) or pass `model: "sonnet"`. Give the subagent everything it needs in the prompt: file paths, the issue, the acceptance check. A sub-task prompt that needs Opus to understand is a planning failure, not a reason to escalate. +3. Verify the result yourself (that is review-final, on Opus): read the diff or the output, run the check. +4. If the same sub-task fails twice on Sonnet, re-spawn it once with `model: "opus"`, and say in the result why it escalated. +5. In a Workflow script, set `model: 'sonnet'` on sub-task `agent()` calls and keep the orchestration logic in the script itself. + +Parallelism: at most 3 subagents at once on this 8 GB Mac (swap eats the disk); more on the Railway lab. + +## Audit + +`is_waste(role, tier, failed_attempts, owner_flag)` in the spec answers whether a run spent Opus on a sub-task without evidence. Use it when TRI CLAW or the Queen records which model ran a job. + +## Not covered yet + +- TRI CLAW's own chat agent (gHashTag/999-multibots-telegraf) and the Queen (gHashTag/trios) still pick models in their own code; they should read this table. Follow-up issues in those repos. +- Haiku is not in the rule. Add a tier to the spec first, with a measurement, before using it. diff --git a/.trinity/seals/claw_ClawModelRoute.json b/.trinity/seals/claw_ClawModelRoute.json new file mode 100644 index 0000000000..ffcf8e6f47 --- /dev/null +++ b/.trinity/seals/claw_ClawModelRoute.json @@ -0,0 +1,28 @@ +{ + "built_by": "t27c-bootstrap@0.5.2+9b556b7c3", + "closure": [], + "config": "gen=c,rust,verilog,zig;tests=zig", + "gen_hash_c": "sha256:bc9e7460cb2d53c2b552cc6ea1db3a87a41fea981237fca28e2e92a353d94092", + "gen_hash_rust": "sha256:d31ea1c2bfe1e7403ed63aeef7e8774461e9b122eb328ac75949f2f191ae578f", + "gen_hash_verilog": "sha256:0d8da221bea4f2da090aa8f840641d6d84e83dba26a4ed0df112cb263dd1c18c", + "gen_hash_zig": "sha256:f4fde0bf222b2cc78dd99301ea3c9f798548930830e3b85575fc504a6ce47c05", + "module": "ClawModelRoute", + "ring": 12, + "seal_schema": 2, + "sealed_at": "2026-10-18T15:12:43Z", + "sealed_by": "t27c-bootstrap@0.5.2", + "spec_hash": "sha256:f27cfca11fe116628decf5d0a935fc5a72db9a761ff06a85df6301f003bef24e", + "spec_path": "specs/claw/model_route.t27", + "tests": { + "failed": 0, + "failing": [], + "forced": false, + "passed": 6, + "total": 6, + "vacuous": 0 + }, + "toolchain": { + "test_runner": "sha256:1982ae948e24d00c5d221ccec12dfce1eb01204b53e37b0f857f93b16d64629d", + "zig": "0.16.0" + } +} \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md index f2b2d7ad83..1a61bb5a58 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -121,6 +121,14 @@ This triggers automatic branch creation for the next phase. Load these skills when their functionality matches the task. +### Model routing (owner directive 2026-10-18) + +The orchestrating session runs on **Opus 5.5**; every sub-task it delegates (implement, port, search, +test, docs, fix) runs on **Sonnet 5.5**, and escalates to Opus only after 2 failed attempts or on the +owner's word. The law is `specs/claw/model_route.t27`; how to follow it is the `model-routing` skill. +`.claude/settings.json` sets `CLAUDE_CODE_SUBAGENT_MODEL` and each agent in `.claude/agents/` names its +model. + --- ## FPGA hardware & flashing (SSOT) diff --git a/docs/claw/README.md b/docs/claw/README.md index c40941e83e..989fe8ff50 100644 --- a/docs/claw/README.md +++ b/docs/claw/README.md @@ -16,6 +16,7 @@ behind one front door, with the gate logic in `.t27` specs. Epic | SARIF code-scanning alerts on a pull request | `specs/claw/sarif_feed.t27` over `specs/claw/sarif.t27`, the `claw-sarif` job of `gate-topology.yml` | #10356, live once the owner steps below are done | | Suggestion review on a pull request | `specs/claw/suggest_feed.t27` over `specs/claw/suggest.t27` and `specs/tri/fmt_source.t27`, the `claw-suggest` job of `gate-topology.yml` | #10365, live once the owner steps below are done | | Service skeleton | Railway, thin I/O glue only | T5, merged (spec contract) | +| Model routing: Opus 5.5 orchestrates, Sonnet 5.5 runs sub-tasks | `specs/claw/model_route.t27`, skill `model-routing`, `.claude/settings.json` + `.claude/agents/*` | owner directive 2026-10-18 | | Positioning / pricing | `docs/claw/competitors.md` | T6, started | ## The T27F check in every `.t27` repository (#10268) diff --git a/specs/claw/model_route.t27 b/specs/claw/model_route.t27 new file mode 100644 index 0000000000..e16931918f --- /dev/null +++ b/specs/claw/model_route.t27 @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: Apache-2.0 +; specs/claw/model_route.t27 -- which Claude model does which job in TRI CLAW and in every agent +; session of this project: the orchestrator thinks on Opus 5.5, its sub-tasks run on Sonnet 5.5. +; Owner directive 2026-10-18: "orchestration through Opus 5.5, sub-tasks through Sonnet 5.5, it is +; cheaper; add this rule to TRI CLAW so development stays economical." +; -- +; WHY. Epic #10066 measured one-shot spec-to-RTL work on the same ten tasks: Sonnet 5.5 passed 9 of +; 10 direct-Verilog tasks against Opus 5.5's 8, and 7 of 10 .t27 tasks against Opus's 7, at about 40% +; of Opus's cost (~$0.41 vs ~$0.99 and ~$0.77 vs ~$1.53 per task, list-price estimates). N = 10, one +; shot: the robust part is that Sonnet is not worse on bounded tasks and is much cheaper. What Opus +; is kept for is the part no sub-task sees: splitting the work, deciding what is true, and saying +; "merge" or "stop". +; -- +; THE RULE. +; - A role is either ORCHESTRATION (orchestrate, plan, final review) or a SUB-TASK (implement, +; port, search, test, docs, fix). base_tier() maps the first to Opus and the second to Sonnet. +; - A sub-task escalates to Opus only on evidence: ESCALATE_AFTER failed Sonnet attempts on the same +; task, or the owner's explicit flag. route() is that rule; nothing else may raise a tier. +; - An orchestration role is never routed down. A cheaper orchestrator is a false economy: its +; mistakes are paid for by every sub-task it spawns. +; - The rule names models by the aliases Claude Code's Agent tool and agent frontmatter accept +; ("opus", "sonnet") and by the full API ids, so a host that is not Claude Code (TRI CLAW's own +; chat agent, the Queen) reads the same table. +; -- +; WHERE IT BINDS. Claude Code: `.claude/settings.json` sets CLAUDE_CODE_SUBAGENT_MODEL to the Sonnet +; id, the sub-task agents in `.claude/agents/` carry `model: sonnet`, and the skill +; `.claude/skills/model-routing/SKILL.md` tells the orchestrator how to spawn and when to escalate. +; TRI CLAW's app and the Queen read this table when they pick a model (follow-up in their repos). +; ASCII only (L3). phi^2 + 1/phi^2 = 3 | TRINITY + +module ClawModelRoute; + +; --- tiers --------------------------------------------------------------------------------------- +pub const TIER_OPUS : u32 = 0; +pub const TIER_SONNET : u32 = 1; + +pub const OPUS_ALIAS : str = "opus"; +pub const SONNET_ALIAS : str = "sonnet"; +pub const OPUS_ID : str = "claude-opus-5-5"; +pub const SONNET_ID : str = "claude-sonnet-5-5"; + +; --- roles --------------------------------------------------------------------------------------- +/// Orchestration: break the task down, delegate, combine results. +pub const R_ORCHESTRATE : u32 = 0; +/// Orchestration: a plan, an epic, the acceptance criteria. +pub const R_PLAN : u32 = 1; +/// Orchestration: the last review before a merge or before a claim leaves the repo. +pub const R_REVIEW_FINAL : u32 = 2; +/// Sub-task: write or change a spec, a test, a board top. +pub const R_IMPLEMENT : u32 = 3; +/// Sub-task: port foreign code to .t27. +pub const R_PORT : u32 = 4; +/// Sub-task: find files, read code, collect facts. +pub const R_SEARCH : u32 = 5; +/// Sub-task: run tests, gates, seals and report what they said. +pub const R_TEST : u32 = 6; +/// Sub-task: docs, issue and PR text, release notes drafts. +pub const R_DOCS : u32 = 7; +/// Sub-task: fix a failing check whose cause is already named. +pub const R_FIX : u32 = 8; +pub const ROLE_COUNT : u32 = 9; + +; --- escalation ---------------------------------------------------------------------------------- +/// Failed Sonnet attempts on the same task before it may go to Opus. +pub const ESCALATE_AFTER : u32 = 2; + +pub fn is_orchestration(role : u32) -> bool { + return role <= R_REVIEW_FINAL; +} + +/// The tier a role starts at. An unknown role is a sub-task: the cheap tier is the default, and an +/// orchestrator that wants Opus names its role. +pub fn base_tier(role : u32) -> u32 { + if (is_orchestration(role)) { return TIER_OPUS; } + return TIER_SONNET; +} + +/// The tier a job runs at: the base tier, raised to Opus for a sub-task only after ESCALATE_AFTER +/// failed attempts or on the owner's flag. Never lowered. +pub fn route(role : u32, failed_attempts : u32, owner_flag : bool) -> u32 { + if (base_tier(role) == TIER_OPUS) { return TIER_OPUS; } + if (owner_flag) { return TIER_OPUS; } + if (failed_attempts >= ESCALATE_AFTER) { return TIER_OPUS; } + return TIER_SONNET; +} + +/// Is a sub-task running on Opus without the evidence route() asks for? The audit question for a +/// session log or a TRI CLAW run record. +pub fn is_waste(role : u32, tier : u32, failed_attempts : u32, owner_flag : bool) -> bool { + return tier == TIER_OPUS and route(role, failed_attempts, owner_flag) == TIER_SONNET; +} + +test orchestration_roles_run_on_opus { + assert base_tier(R_ORCHESTRATE) == TIER_OPUS; + assert base_tier(R_PLAN) == TIER_OPUS; + assert base_tier(R_REVIEW_FINAL) == TIER_OPUS; +} + +test sub_tasks_run_on_sonnet { + assert base_tier(R_IMPLEMENT) == TIER_SONNET; + assert base_tier(R_PORT) == TIER_SONNET; + assert base_tier(R_SEARCH) == TIER_SONNET; + assert base_tier(R_TEST) == TIER_SONNET; + assert base_tier(R_DOCS) == TIER_SONNET; + assert base_tier(R_FIX) == TIER_SONNET; +} + +test an_unknown_role_is_a_cheap_sub_task { + assert base_tier(ROLE_COUNT) == TIER_SONNET; + assert base_tier(99) == TIER_SONNET; +} + +test a_sub_task_escalates_only_on_evidence { + assert route(R_IMPLEMENT, 0, false) == TIER_SONNET; + assert route(R_IMPLEMENT, 1, false) == TIER_SONNET; + assert route(R_IMPLEMENT, 2, false) == TIER_OPUS; + assert route(R_FIX, 5, false) == TIER_OPUS; + assert route(R_SEARCH, 0, true) == TIER_OPUS; +} + +test orchestration_is_never_routed_down { + assert route(R_ORCHESTRATE, 0, false) == TIER_OPUS; + assert route(R_PLAN, 0, false) == TIER_OPUS; + assert route(R_REVIEW_FINAL, 0, false) == TIER_OPUS; +} + +test negative_control_opus_on_a_fresh_sub_task_is_waste { + assert is_waste(R_PORT, TIER_OPUS, 0, false) == true; + assert is_waste(R_PORT, TIER_OPUS, 2, false) == false; + assert is_waste(R_PORT, TIER_OPUS, 0, true) == false; + assert is_waste(R_PORT, TIER_SONNET, 0, false) == false; + assert is_waste(R_PLAN, TIER_OPUS, 0, false) == false; +} + +invariant every_role_routes_to_a_known_tier { + var r : u32 = 0; + while (r < ROLE_COUNT) { + const t : u32 = route(r, 0, false); + assert t == TIER_OPUS or t == TIER_SONNET; + r += 1; + } +}