Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .claude/agents/agent-c-compiler.md
Original file line number Diff line number Diff line change
@@ -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:
Expand Down
1 change: 1 addition & 0 deletions .claude/agents/agent-e-experience.md
Original file line number Diff line number Diff line change
@@ -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:
Expand Down
1 change: 1 addition & 0 deletions .claude/agents/agent-l-lsp.md
Original file line number Diff line number Diff line change
@@ -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:
Expand Down
1 change: 1 addition & 0 deletions .claude/agents/agent-v-verify.md
Original file line number Diff line number Diff line change
@@ -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:
Expand Down
1 change: 1 addition & 0 deletions .claude/agents/creator.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
model: sonnet
description: Creator Agent - Generates code from specs, implements features
color: "#3b82f6"
---
Expand Down
1 change: 1 addition & 0 deletions .claude/agents/experience.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
model: sonnet
description: Experience Agent - Manages learning history, provides context, retrieves patterns
color: "#f59e0b"
---
Expand Down
1 change: 1 addition & 0 deletions .claude/agents/learner.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
model: sonnet
description: Learner Agent - Researches patterns, discovers insights, builds knowledge base
color: "#8b5cf6"
---
Expand Down
1 change: 1 addition & 0 deletions .claude/agents/review-warden.md
Original file line number Diff line number Diff line change
@@ -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"
---
Expand Down
1 change: 1 addition & 0 deletions .claude/agents/t27c-steward.md
Original file line number Diff line number Diff line change
@@ -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"
---
Expand Down
1 change: 1 addition & 0 deletions .claude/agents/trinity.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
model: opus
description: Trinity Agent (Queen) - Orchestrates multi-agent coordination, executes AEL v2.0
color: "#ef4444"
orchestrator: true
Expand Down
1 change: 1 addition & 0 deletions .claude/agents/verifier.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
model: sonnet
description: Verifier Agent - Validates correctness, runs conformance tests, ensures law compliance
color: "#10b981"
---
Expand Down
3 changes: 3 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
{
"env": {
"CLAUDE_CODE_SUBAGENT_MODEL": "claude-sonnet-5-5"
},
"hooks": {
"Stop": [
{
Expand Down
57 changes: 57 additions & 0 deletions .claude/skills/model-routing/SKILL.md
Original file line number Diff line number Diff line change
@@ -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-rule -->
> **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.
28 changes: 28 additions & 0 deletions .trinity/seals/claw_ClawModelRoute.json
Original file line number Diff line number Diff line change
@@ -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"
}
}
8 changes: 8 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions docs/claw/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
142 changes: 142 additions & 0 deletions specs/claw/model_route.t27
Original file line number Diff line number Diff line change
@@ -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;
}
}
Loading