diff --git a/.github/workflows/check-skill-names.yml b/.github/workflows/check-skill-names.yml index d1b22e7..93d39d0 100644 --- a/.github/workflows/check-skill-names.yml +++ b/.github/workflows/check-skill-names.yml @@ -15,3 +15,4 @@ jobs: with: node-version: 22 - run: node scripts/check-skill-names.mjs + - run: node scripts/check-models.mjs diff --git a/README.md b/README.md index 0ebbec1..5faf44e 100644 --- a/README.md +++ b/README.md @@ -258,7 +258,7 @@ cursor already has a great plan mode which works great with oddstack. but person type [`/automate-me`](./skills/automate-me/SKILL.md). it mines your recent transcripts, drafts a `-mode` skill from how you've actually worked, and routes through oddstack underneath. you keep oddstack as the base and end up with your own routing skill alongside `odd-mode`. -models are configurable too. type [`/setup-oddstack`](./skills/setup-oddstack/SKILL.md). it detects the models this harness can select and edits [`skills/odd-mode/models.txt`](./skills/odd-mode/models.txt), the map every skill reads. cursor, claude code, codex, t3 code, and grok bot all see it, because the file lives inside the odd-mode skill and each skill links to it as a sibling. a `~/.cursor/rules/oddstack-models.mdc` file, when you still have one, overrides the map on that machine. +models are configurable too. type [`/setup-oddstack`](./skills/setup-oddstack/SKILL.md). it detects the models this harness can select and edits [`skills/odd-mode/models.txt`](./skills/odd-mode/models.txt), the map every skill reads. cursor, claude code, codex, t3 code, and grok bot all see it, because the file lives inside the odd-mode skill and each skill links to it as a sibling. [`harness.md`](./skills/odd-mode/harness.md) beside it says how each harness spawns an entry. when a default changes, a map edited before the change still pins the old default. delete those role lines, then run `/setup-oddstack` again. a rerun keeps any role whose model differs from the default by family, list, or alias. diff --git a/docs/dispatcher.md b/docs/dispatcher.md index d15d33d..e6c098f 100644 --- a/docs/dispatcher.md +++ b/docs/dispatcher.md @@ -4,7 +4,7 @@ For a bot (such as Grok Bot) that starts T3 Code threads through the T3 MCP tool ## The lead -Launch every lead thread with `modelSelection: {"instanceId":"claudeAgent","model":"claude-opus-5-5","options":{"effort":"high"}}`, the `judgment and prose` line of `models.txt`. Without it, a launch from outside T3 gets the project's default model. The lead plans, routes each role per `models.txt`, reviews, and never builds. Never launch a lead on `cursor`. A `cursor` thread never reaches a terminal state in T3 Code (see odd-mode's Subagents section), so you would never see it finish. +Launch every lead thread with `modelSelection: {"instanceId":"claudeAgent","model":"claude-opus-5-5","options":{"effort":"high"}}`, the `judgment and prose` line of `models.txt`. Without it, a launch from outside T3 gets the project's default model. The lead plans, routes each role per `models.txt`, reviews, and never builds. Never launch a lead on `cursor`. The lead's work is judgment, which stays on Claude Opus, and a `cursor` thread on a long path never finishes (see odd-mode's Subagents section). Do not pick models for the lead's children. The lead reads `models.txt` from the repo it runs in. diff --git a/docs/guide/01-setup.md b/docs/guide/01-setup.md index c31b8da..c29afd8 100644 --- a/docs/guide/01-setup.md +++ b/docs/guide/01-setup.md @@ -24,9 +24,9 @@ Run: The committed map runs at `high` reasoning, the same as the `medium` budget. `large` raises each model to `xhigh`. `unlimited` lifts each model to its highest tier, up to `max`. Opus goes to `max`. Grok tops out at `xhigh`, so it stays there. `small` lowers the reasoning and spends fewer tokens. -You only override what you care about. A role with no line in the map keeps the skill's default. To restore a default, delete that role's line. A rerun of `/setup-oddstack` keeps any role whose model differs from the default by family, list, or alias. When a default changes, a map edited before the change still pins the old default, so delete those role lines, then run `/setup-oddstack` again. An old `~/.cursor/rules/oddstack-models.mdc` still overrides the map on that machine until you delete it. +Every role needs a line in the map. A skill that finds no line for its role stops and says so, rather than guessing a model. To restore the committed choices, check out `skills/odd-mode/models.txt` from git. A rerun of `/setup-oddstack` keeps any role whose model differs from the committed map by provider, model, list, or `inherit`. -You might be wondering what happens if you use Auto. Set a role to `inherit-parent` or `auto` and oddstack omits the subagent `model` field, so the subagent inherits your parent chat model. Both values mean the same thing, and neither is a model slug. For a panel role the value is a list, and one subagent runs per entry, so the list length sets the panel size. Setup also configures `swarm workers`, the default model for every `/swarm` worker unless a race names a model for each arm. +You might be wondering what happens if you use Auto. Set a role to `inherit` and oddstack omits the subagent `model` field, so the subagent inherits your parent chat model. For a panel role the value is a list, and one subagent runs per entry, so the list length sets the panel size. Setup also configures `swarm workers`, the default model for every `/swarm` worker unless a race names a model for each arm. ## Accept the verification offer, or don't @@ -43,7 +43,7 @@ The map applies the next time a skill is read. A Cursor override file, if you ke oddstack spends extra tokens on subagents and review panels. That's the price of the rigor. To spend fewer: - Rerun `/setup-oddstack` and pick a smaller reasoning budget or cheaper models. A strong model in the main chat with cheaper, faster models in the code roles is a good split. -- Set a role to `auto` or `inherit-parent` so it runs on the chat's own model. +- Set a role to `inherit` so it runs on the chat's own model. - Shorten a panel list. Each entry runs one subagent. - Save `/odd-mode` for work that needs rigor. A small, obvious edit doesn't. diff --git a/docs/guide/10-recipes-and-pitfalls.md b/docs/guide/10-recipes-and-pitfalls.md index c008744..541ab23 100644 --- a/docs/guide/10-recipes-and-pitfalls.md +++ b/docs/guide/10-recipes-and-pitfalls.md @@ -147,7 +147,7 @@ That's the whole prompt. [`/bro`](../../skills/bro/SKILL.md) restates the last m - **Correcting the same mistake by hand.** A correction in chat helps one run. `/correct` fixes the repo so no later run repeats it. - **Using `/arena` for coverage.** `/arena` repeats one design or code brief, then picks a base and grafts the best parts. `/swarm` partitions slices or declared race arms and aggregates one report. - **Accepting every review comment.** Bots and humans both file real catches and noise in one list. `/interrogate` sorts findings into act-on and dismissed buckets with reasons, and you can override either way. -- **Treating `auto` as a model slug.** `auto` and `inherit-parent` mean "omit the model field so the subagent inherits the parent chat model." [Setup](./01-setup.md) covers the roles. +- **Treating `inherit` as a model.** `inherit` means "omit the model field so the subagent inherits the parent chat model." [Setup](./01-setup.md) covers the roles. - **Reporting success off a green build.** A build proves it compiles. Ask for the real command, flow, stored value, or profile, and expect the evidence in the reply. - **Writing a `SKILL.md` freehand.** Route it through the [Authoring or modifying a skill playbook](../../skills/odd-mode/playbooks/authoring-a-skill.md) so validation and review happen. diff --git a/scripts/check-models.mjs b/scripts/check-models.mjs new file mode 100644 index 0000000..471ba15 --- /dev/null +++ b/scripts/check-models.mjs @@ -0,0 +1,46 @@ +#!/usr/bin/env node +import { execFileSync } from "node:child_process"; +import fs from "node:fs"; +import process from "node:process"; + +const mapPath = "skills/odd-mode/models.txt"; +const entryPattern = /^(inherit|\S+ \S+( [A-Za-z_]+=\S+)*)$/; +const errors = []; + +const roles = new Map(); +for (const [index, raw] of fs.readFileSync(mapPath, "utf8").split(/\r?\n/).entries()) { + const line = raw.trim(); + if (!line || line.startsWith("#")) continue; + const where = `${mapPath}:${index + 1}`; + const colon = line.indexOf(":"); + if (colon === -1) { + errors.push(`${where}: no ":"`); + continue; + } + const role = line.slice(0, colon).trim(); + if (roles.has(role)) errors.push(`${where}: duplicate role "${role}"`); + roles.set(role, where); + for (const entry of line.slice(colon + 1).split("|").map((e) => e.trim())) { + if (!entryPattern.test(entry)) errors.push(`${where}: bad entry "${entry}"`); + } +} + +const docs = execFileSync("git", ["ls-files", "-z", "--", "skills/*.md"], { encoding: "utf8" }) + .split("\0") + .filter(Boolean); +const referencePatterns = [/`([^`]+)` line\b/g, /\(`([^`]+)` in `\.\.\/models\.txt`/g, /\| `([^`]+)` \| `references\//g]; +let referenceCount = 0; +for (const doc of docs) { + const text = fs.readFileSync(doc, "utf8"); + for (const pattern of referencePatterns) { + for (const match of text.matchAll(pattern)) { + if (match[1].includes(":")) continue; + referenceCount++; + if (!roles.has(match[1])) errors.push(`${doc}: reads role "${match[1]}", which ${mapPath} has no line for`); + } + } +} + +for (const error of errors) console.error(error); +if (errors.length) process.exit(1); +console.log(`${roles.size} roles parse, and ${referenceCount} role reads in skills all resolve`); diff --git a/skills/architect/SKILL.md b/skills/architect/SKILL.md index e24cb17..1c730ec 100644 --- a/skills/architect/SKILL.md +++ b/skills/architect/SKILL.md @@ -30,7 +30,7 @@ Skip Phase A only when the work is genuinely greenfield with no surrounding syst Run the **arena** skill with the design-sketch task and the Phase A grounding artifacts. Pass `references/runner-prompt.md` as each runner's prompt. Each candidate produces a design package shaped per `references/rationale-template.md`. -Take the runners from the `architect runners` line in [`../odd-mode/models.txt`](../odd-mode/models.txt), in place of the `arena runners` line. If that line is missing, use `claude-opus-5-5-high` and `grok-4.7-high-fast`. A same-named line in `~/.cursor/rules/oddstack-models.mdc` overrides the map when that file exists. Alias entries, a `grok-*` seat this harness cannot select, and a `claude-*` seat this harness cannot select follow the runner rules in the **arena** skill's Phase A. An Opus seat is flagged for a Claude thread and is never filled with Grok. +Take the runners from the `architect runners` line in [`../odd-mode/models.txt`](../odd-mode/models.txt), in place of the `arena runners` line. Spawn each entry per the Models section of [`../odd-mode/harness.md`](../odd-mode/harness.md). Design it twice. Require at least two structurally distinct candidates before synthesis, even when the first looks sufficient. This is the **exhaust-the-design-space** principle skill made concrete. Whole-shape alternatives, not point fixes inside one shape. diff --git a/skills/arena/SKILL.md b/skills/arena/SKILL.md index dd13532..8e43289 100644 --- a/skills/arena/SKILL.md +++ b/skills/arena/SKILL.md @@ -25,7 +25,7 @@ The N candidates will receive the same prompt, so the prompt is the contract. 1. State the artifact each candidate is producing. 2. Derive the rubric. State what success looks like for *this* task, then turn it into 3-6 concrete gradeable criteria. The rubric is the picker's tool in Phase D. Candidates only see the task. -3. Pick the runners from the `arena runners` line in [`../odd-mode/models.txt`](../odd-mode/models.txt). If that line is missing, default to one each on `claude-opus-5-5-high` and `grok-4.7-high-fast`. Read the file and follow its `# harness` section. The relative path is the odd-mode skill's `models.txt`, and it resolves through a per-skill symlink. If it misses, open the odd-mode skill and read `models.txt` there. A same-named line in `~/.cursor/rules/oddstack-models.mdc` overrides the map when that file exists. An `auto` or `inherit-parent` entry in this line or the cross-judge line means the parent model, so omit `model` for it. Never fill a `claude-*` seat with Grok. Spawn the seats this harness can run. When this harness should be able to select the family and the tool rejects the exact slug, use the closest valid slug of the same family (`claude-*` or `grok-*`) and say so. Spawn more when the arena covers multiple design directions. Same model N times when the work is generation-bound rather than judgment-sensitive. +3. Pick the runners from the `arena runners` line in [`../odd-mode/models.txt`](../odd-mode/models.txt). Spawn each entry per the Models section of [`../odd-mode/harness.md`](../odd-mode/harness.md). Spawn more when the arena covers multiple design directions. Same model N times when the work is generation-bound rather than judgment-sensitive. 4. Assign output paths. Each candidate writes to its own location (a git worktree where possible, otherwise `/tmp/arena-/candidate-/`), per the **separate-before-serializing-shared-state** principle skill. ## Phase B: Fan out @@ -38,7 +38,7 @@ If a candidate fails to produce output, proceed with N-1 and note the dropout in ## Phase C: Cross-judge -After all Phase B candidates complete, choose one model from the `arena cross-judge pool` line in [`../odd-mode/models.txt`](../odd-mode/models.txt). If that line is missing, choose from `claude-opus-5-5-high` and `grok-4.7-high-fast`. The same line in `~/.cursor/rules/oddstack-models.mdc` overrides the map when that file exists. Prefer a different model family from the parent's, among seats this harness can select. Follow the file's `# harness` section. A `claude-*` seat is never replaced with Grok. If no different-family seat can run here, say that and judge from the parent. Spawn one readonly judge subagent on the chosen model. It sees the rubric and the candidates by path label, scores each criterion, and recommends a base with rationale. It runs in parallel with the parent's reading in Phase D, not with the candidates themselves. Don't spawn the judge while candidates are still writing. +After all Phase B candidates complete, choose one model from the `arena cross-judge pool` line in [`../odd-mode/models.txt`](../odd-mode/models.txt). Prefer an entry on a different provider from the parent's, among those this harness can route per the Models section of [`../odd-mode/harness.md`](../odd-mode/harness.md). If no different-provider entry can run here, say that and judge from the parent. Spawn one readonly judge subagent on the chosen model. It sees the rubric and the candidates by path label, scores each criterion, and recommends a base with rationale. It runs in parallel with the parent's reading in Phase D, not with the candidates themselves. Don't spawn the judge while candidates are still writing. ## Phase D: Pick a base diff --git a/skills/how/SKILL.md b/skills/how/SKILL.md index 96b1ce9..1763806 100644 --- a/skills/how/SKILL.md +++ b/skills/how/SKILL.md @@ -8,7 +8,7 @@ disable-model-invocation: true Explore the codebase to answer "how does X work?" questions. Produce architectural explanations at the level of a senior engineer onboarding onto a subsystem, enough to build a working mental model, not so much that it reads like annotated source code. -Each spawn below names a role line in [`../odd-mode/models.txt`](../odd-mode/models.txt) and a default. Read that file and follow its `# harness` section. The relative path is the odd-mode skill's `models.txt`, and it resolves through a per-skill symlink. If it misses, open the odd-mode skill and read `models.txt` there. A same-named line in `~/.cursor/rules/oddstack-models.mdc` overrides the map when that file exists. Leave `model` unset when the value is `auto` or `inherit-parent`. Never run a `claude-*` seat on Grok. When this harness should be able to select the family and the tool rejects the exact slug, use the closest valid slug of the same family and say so. +Each spawn below names a role line in [`../odd-mode/models.txt`](../odd-mode/models.txt). Spawn each entry per the Models section of [`../odd-mode/harness.md`](../odd-mode/harness.md). ## Step 1. Assess Complexity @@ -24,7 +24,7 @@ When in doubt, take the simple path. Decompose the question into 2 to 4 exploration angles, each a distinct slice of the subsystem. Spawn all explorers in a single message: - `subagent_type`: `generalPurpose` -- `model`: the `how explorer` line, default `grok-4.7-high-fast` +- `model`: the `how explorer` line - `readonly`: `true` Each explorer gets the prompt in `references/explorer-prompt.md` with its angle filled in. Then go to Step 3. @@ -34,7 +34,7 @@ Each explorer gets the prompt in `references/explorer-prompt.md` with its angle Spawn one Task subagent that explores and explains in one pass: - `subagent_type`: `generalPurpose` -- `model`: the `how explainer` line, default `claude-opus-5-5-high` +- `model`: the `how explainer` line - `readonly`: `true` Build its prompt from `references/explainer-prompt.md` without the explorer-findings section. Go to Step 4. @@ -44,7 +44,7 @@ Build its prompt from `references/explainer-prompt.md` without the explorer-find Once all explorers have returned, spawn one Task subagent to synthesize their findings into one explanation: - `subagent_type`: `generalPurpose` -- `model`: the `how explainer` line, default `claude-opus-5-5-high` +- `model`: the `how explainer` line - `readonly`: `true` Build its prompt from `references/explainer-prompt.md` with every explorer's findings filled in. diff --git a/skills/interrogate/SKILL.md b/skills/interrogate/SKILL.md index bf0fe2c..092b14d 100644 --- a/skills/interrogate/SKILL.md +++ b/skills/interrogate/SKILL.md @@ -33,20 +33,13 @@ Write one clear paragraph. If you're unsure about the intent, ask the user befor ## Step 3, Spawn Reviewers -Launch all reviewers in a single message using the Task tool. Read the `interrogate reviewers` line in [`../odd-mode/models.txt`](../odd-mode/models.txt) and follow its `# harness` section. The relative path is the odd-mode skill's `models.txt`, and it resolves through a per-skill symlink. If it misses, open the odd-mode skill and read `models.txt` there. A same-named line in `~/.cursor/rules/oddstack-models.mdc` overrides the map when that file exists. Spawn one reviewer per entry this harness can run, extending or shrinking the Reviewer A/B labels below to that count. If the line is missing, use the table defaults. +Launch all reviewers in a single message using the Task tool. Read the `interrogate reviewers` line in [`../odd-mode/models.txt`](../odd-mode/models.txt). Spawn each entry per the Models section of [`../odd-mode/harness.md`](../odd-mode/harness.md). Spawn one reviewer per entry this harness can run, labeled Reviewer A, B, and so on. -| Subagent | Default model | -|----------|---------------| -| Reviewer A | `claude-opus-5-5-high` | -| Reviewer B | `grok-4.7-high-fast` | - -For each reviewer this harness can run: +For each reviewer: - `subagent_type`: `generalPurpose` -- `model`: the configured `interrogate reviewers` entry, or the table default with no configured line. For an `auto` or `inherit-parent` entry, omit `model` so that reviewer runs on the parent model. +- `model`: that reviewer's entry - `readonly`: `true` -Never fill a `claude-*` seat with Grok. When this harness should be able to select the family and the tool rejects the exact slug, use the closest valid slug of the same family (`claude-*` or `grok-*`) and say so. If it rejects that too, check the valid slugs in the tool's error message, pick the closest same-family equivalent, spawn with it, and open a separate PR to update the default table. Do not block the review on the slug issue. Never treat an alias entry as a rejected slug. - Read `references/reviewer-prompt.md` and fill in the template with: 1. The stated intent 2. The diff or file contents diff --git a/skills/odd-mode/SKILL.md b/skills/odd-mode/SKILL.md index 376ba76..799ccaf 100644 --- a/skills/odd-mode/SKILL.md +++ b/skills/odd-mode/SKILL.md @@ -95,30 +95,30 @@ Read the leaf skill in full for any principle you apply. Each entry names when i **Use `subagent_type: "odium-agent"` for any subagent you spawn inside a playbook step** (code-writing delegates, ad-hoc helpers). The chat that receives `/odd-mode` runs the playbook. Never spawn an `odium-agent` to run the playbook itself. Routed workflow skills (`how`, `why`, `interrogate`, `reflect`, `swarm`) set their own `subagent_type` for diverse-model review. Respect what the skill prescribes, don't override to `odium-agent`. -**The lead never builds.** The lead plans, reviews, and verifies. It never writes a diff, in any playbook. That covers fixes, repros, instrumentation, harnesses, prototypes, refactor subtractions, and babysit fixes. A child writes each one at any size, a one-line fix included. A delegate step is never marked `skip: `, and Laziness Protocol does not override it. A child that is not allowed to spawn and needs code written reports back, and its parent spawns the builder. Route every child per the `# harness` section of `models.txt`. +**The lead never builds.** The lead plans, reviews, and verifies. It never writes a diff, in any playbook. That covers fixes, repros, instrumentation, harnesses, prototypes, refactor subtractions, and babysit fixes. A child writes each one at any size, a one-line fix included. A delegate step is never marked `skip: `, and Laziness Protocol does not override it. A child that is not allowed to spawn and needs code written reports back, and its parent spawns the builder. Route every child per the Models section of [`harness.md`](harness.md). -**Read `models.txt` before the first spawn.** Read it in full once per session and map each role you will use to its slug and route. +**Read `models.txt` before the first spawn.** Read it once per session and map each role you will use to its entries, then route each entry per the Models section of [`harness.md`](harness.md). -**Review runs on the other provider.** The reviewer's provider differs from the builder's (`claudeAgent` vs `cursor` in T3 Code). The other provider is the route `models.txt` gives the reviewer's slug, normally `cursor` with `grok-4.7` for a Grok reviewer. It is not whichever non-Claude provider happens to be available. A Claude reviewer uses the `judgment and prose` slug. A Grok reviewer uses the code slug of the builder's playbook. A lead's own review counts only when the lead's provider differs from the builder's. If that route cannot start, stop and report that the diff is not reviewed. Do not fall back to Gemini, Codex, or T3's native `grok` provider unless the operator says so. Never substitute the session model. +**Review runs on the other provider.** The reviewer's provider differs from the builder's (`claudeAgent` vs `cursor` in T3 Code). The other provider is the one named in the reviewer's `models.txt` entry, normally `cursor` with `grok-4.7` for a Grok reviewer. It is not whichever non-Claude provider happens to be available. A Claude reviewer uses the `judgment and prose` entry. A Grok reviewer uses the `cursor` entry of the builder's playbook line. A lead's own review counts only when the lead's provider differs from the builder's. If that route cannot start, stop and report that the diff is not reviewed. Do not fall back to Gemini, Codex, or T3's native `grok` provider unless the operator says so. Never substitute the session model. -**Cursor children never finish on their own.** In T3 Code, a `delegate_task` child on the `cursor` provider, on any model, restarts its whole turn about 45 seconds after its final message. It has no memory of the first run, and it never reaches a terminal state, so its completion never wakes you. This was measured on 2026-10-16 against T3's bundled `@cursor/sdk` 1.0.35. `claudeAgent` children complete normally. The trigger is a Windows path limit (cursor forum thread 173594, T3 issue #19112): the SDK saves checkpoints under a folder named after the child's working folder, and the save fails once that name passes 51 characters. Before you spawn a `cursor` child, take the absolute path it will run in, replace each run of characters other than letters and digits with one `-`, and trim `-` from both ends. If the result is longer than 51 characters, run the child in a worktree with a shorter path, or route the role to `claudeAgent` and say so. Threads with no project always fail this check. Every `cursor` brief still carries a done marker, an absolute path you pick in the OS temp folder, named after the task's `clientRequestId`. That covers builders, reviewers, helpers, and the seats a routed skill spawns (`interrogate`, `swarm`, `reflect`, `arena`, `architect`), even after a template the skill says to pass verbatim. Put these two lines first and last, verbatim apart from the path: +**Cursor children on a long path never finish.** In T3 Code, a `delegate_task` child on the `cursor` provider, on any model, can restart its whole turn about 45 seconds after its final message. It has no memory of the first run, and it never reaches a terminal state, so its completion never wakes you. This was measured on 2026-10-16 against T3's bundled `@cursor/sdk` 1.0.35. On 2026-10-17 a `cursor` child in `C:\wt\odium-stack\models-map` completed normally. `claudeAgent` children always complete normally. The trigger is a Windows path limit (cursor forum thread 173594, T3 issue #19112): the SDK saves checkpoints under a folder named after the child's working folder, and the save fails once that name passes 51 characters. Before you spawn a `cursor` child, take the absolute path it will run in, which is this thread's checkout unless you pass `isolation: "worktree"`. Replace each run of characters other than letters and digits with one `-`, and trim `-` from both ends. If the result is longer than 51 characters, run the child in a worktree with a shorter path, or route the role to `claudeAgent` and say so. Threads with no project always fail this check. Every `cursor` brief still carries a done marker, `/.done`, which must not exist before the spawn. That covers builders, reviewers, helpers, and the seats a routed skill spawns (`interrogate`, `swarm`, `reflect`, `arena`, `architect`), even after a template the skill says to pass verbatim. Put these two lines first and last, verbatim apart from the path: - First: "Before anything else, read the file `` with your file read tool. Do not search for it. If the read succeeds, reply only DONE and end your turn." - Last: "As your last action, write the word done to the file `` with your file tool, then send your report. End the report with the line `REPORT-END`." A search tool such as `glob` misses a file in the temp folder, so the first line names the read tool. -A `cursor` child's completion never arrives, so stay in the turn and wait for it yourself, even though `delegate_task` says to end the turn. Keep its `taskId` and `childThreadId`. Loop: +A `cursor` child's completion may never arrive, so stay in the turn and wait for it yourself, even though `delegate_task` says to end the turn. Keep its `taskId` and `childThreadId`. Loop: 1. Call `t3_thread_wait` on the `childThreadId` with `timeoutMs: 120000`. 2. Call `t3_thread_read` with `afterPosition` set to the previous call's `nextPosition` (0 the first time). -3. If an assistant message ends in `REPORT-END`, act on the first one, ignore anything later, `task_cancel` the `taskId`, delete the marker, and stop. -4. If the thread reached a terminal state, read it once, delete the marker, and stop. A `completed` status means T3 fixed the driver, so drop this rule. +3. If an assistant message ends in `REPORT-END`, act on the first one and ignore anything later. Unless the thread is already terminal, `task_cancel` the `taskId`. Delete the marker and stop. +4. If the thread reached a terminal state with no `REPORT-END`, read it once, delete the marker, and stop. 5. Otherwise go back to step 1. After 60 minutes with no `REPORT-END`, or the brief's timebox if it set one, `task_cancel`, delete the marker, and report that child as timed out. -Drop this rule once a `cursor` child's thread reaches `completed` on its own. +Keep the path check, the marker, and this loop until T3 ships a `@cursor/sdk` with Cursor's fix for forum thread 173594. Then drop all three together. A child that completes on a short path does not mean the fix shipped. -**Defaults for every `Task` call.** `run_in_background: true`, agent mode (readonly strips MCP), file pointers not inlined context, and an explicit model per role from [`models.txt`](models.txt) in this skill (`/setup-oddstack` edits that file). Code defaults to `grok-4.7-high-fast`. Prose and judgment default to `claude-opus-5-5-high`. Code delegates tier by difficulty. The hardest changes (cross-cutting design, gnarly concurrency, subtle algorithms) go to the `hardest tasks` model (`claude-opus-5-5-high`), whether the task needs judgment on vague intent or is a precisely specified sequence of steps to execute to the letter. Trivial mechanical edits go to the fast code model. Follow the `# harness` section of `models.txt` for any role this harness cannot select. Design and judgment authoring stays on Claude Opus, never on Grok. The cross-provider review seat is exempt. A role line in `~/.cursor/rules/oddstack-models.mdc` overrides the same line in `models.txt` when that file exists. A missing role line keeps the default in the routed skill. `inherit-parent` or `auto` runs on the parent chat model (omit Task `model`). Each code playbook's configured model comes from its line in `models.txt` (`feature, refactoring`, `bug-fix`, `perf-issue`, or `hillclimb`), and the hardest changes read `hardest tasks`. Prose and judgment read `judgment and prose`. The routed skills (`how`, `why`, `arena`, `swarm`, `architect`, `interrogate`, `reflect`) read the same file via `../odd-mode/models.txt`. +**Defaults for every `Task` call.** `run_in_background: true`, agent mode (readonly strips MCP), file pointers not inlined context, and an explicit model per role from [`models.txt`](models.txt) in this skill, spawned per the Models section of [`harness.md`](harness.md). Each code playbook reads its own line (`feature, refactoring`, `bug-fix`, `perf-issue`, or `hillclimb`). Code delegates tier by difficulty. The hardest changes (cross-cutting design, gnarly concurrency, subtle algorithms) read `hardest tasks`, whether the task needs judgment on vague intent or is a precisely specified sequence of steps to execute to the letter. Trivial mechanical edits use the playbook's line. Prose and judgment read `judgment and prose`. Design and judgment authoring stays on Claude Opus, never on Grok. The cross-provider review seat is exempt. The routed skills (`how`, `why`, `arena`, `swarm`, `architect`, `interrogate`, `reflect`) read the same file as `../odd-mode/models.txt`. You own every subagent's work. Review the diff and write your own summary, don't pass through what it said. A second opinion is the same prompt against a different model. Agreement is high-signal. diff --git a/skills/odd-mode/harness.md b/skills/odd-mode/harness.md index 54dea1a..a8788bc 100644 --- a/skills/odd-mode/harness.md +++ b/skills/odd-mode/harness.md @@ -1,6 +1,6 @@ # oddstack outside Cursor -oddstack skills use Cursor names. In Claude Code or a T3 Code thread, read this file once per session, then map each Cursor name with the tables below. `` means the folder that holds `odd-mode/`, which is this file's grandparent. If a Cursor field has no row, drop it and say so. Never pass a field or value the tool schema rejects. +oddstack skills use Cursor names. In Claude Code or a T3 Code thread, read this file once per session, then map each Cursor name with the tables below. `` means the folder that holds `odd-mode/`, which is this file's grandparent. If a Cursor field has no row, drop it and say so. Never pass a field or value the tool schema rejects. The Models section applies in every harness, Cursor included. ## Skills @@ -13,7 +13,7 @@ oddstack skills use Cursor names. In Claude Code or a T3 Code thread, read this | Cursor | Here | | --- | --- | -| `Task` | `Agent` in Claude Code. `delegate_task` in a T3 Code thread, for every role, per the `# Harness` section of `models.txt`. A `cursor` child also needs the done marker in odd-mode's Subagents section. | +| `Task` | `Agent` in Claude Code. `delegate_task` in a T3 Code thread, for every role, per Models below. A `cursor` child also needs the done marker in odd-mode's Subagents section. | | `AskQuestion` | `AskUserQuestion`. In `-p` mode it is absent, so ask in plain text. | | Open a todolist | `TodoWrite` if the session offers it. Otherwise `.odd-todo.md`, per odd-mode's Playbooks section. | | `Grep`, `Glob` | `Bash` with `rg` when the session has neither. | @@ -35,13 +35,20 @@ oddstack skills use Cursor names. In Claude Code or a T3 Code thread, read this ## Models -Read the role's slug from `models.txt`, then route it. +Every skill picks models the same way. Read the role's line in `models.txt` beside this file, then spawn each entry with this table. -| Slug | Claude Code | T3 Code thread | -| --- | --- | --- | -| `claude---`, such as `claude-opus-5-5-high` | `Agent` with `model: "opus"` and `effort: "high"`. `model` takes only `opus`, `sonnet`, `haiku`, `fable`, so this is the closest same-family slug that `models.txt` allows. | `delegate_task` per the `# Harness` section of `models.txt`. | -| `grok-*` | No route. Follow the `# Harness` section of `models.txt`. | `delegate_task` per the `# Harness` section of `models.txt`. | -| `auto`, `inherit-parent` | Omit `model`. | Omit `model`. | +| Entry | T3 Code thread | Claude Code | Cursor | +| --- | --- | --- | --- | +| `claudeAgent effort=` | `delegate_task` with `target: {providerInstanceId: "claudeAgent", model: "", options: {effort: ""}}` | `Agent` with `model` set to the family word in `` (`opus`, `sonnet`, `haiku`, or `fable`) and `effort: ""` | `Task` with `model: "-"` if Cursor accepts it, else rule 2 | +| `cursor reasoning_effort= fastMode=true` | `delegate_task` with `target: {providerInstanceId: "cursor", model: "", options: {reasoning_effort: "", fastMode: true}}`, after the path check and with the done marker in odd-mode's Subagents section | Rule 3 | `Task` with `model: "--fast"`, such as `grok-4.7-high-fast`. Drop `-fast` when the entry has no `fastMode=true`. | +| `inherit` | Omit `target` | Omit `model` | Omit `model` | + +1. In T3 Code, spawn every entry through `delegate_task` on its own provider, even when this thread could run the model natively. Never send a `cursor` entry to T3's `grok` provider. If the route cannot start, stop and report. Do not fall back to another provider unless the operator says so. +2. A `claudeAgent` entry with no route here stays unspawned. Say it belongs in Claude Code or a T3 Code thread. Never run it on Grok, or on a session model that is not Claude Opus. A panel still spawns the entries it can. +3. A `cursor` entry with no route here runs on the session model. Omit `model` and say so in one line. The cross-provider review seat is the exception: odd-mode's "Review runs on the other provider" rule decides it. +4. If the tool rejects the exact model or option, use the closest valid one from the same provider and family, and say so. A rejection never moves an entry to the other provider. +5. If the role has no line in `models.txt`, stop and report it. Do not guess a model. +6. Leave any option the entry does not name at its default. Give each `delegate_task` a `title` naming the role, and a distinct `clientRequestId` per spawn. ## Paths diff --git a/skills/odd-mode/models.txt b/skills/odd-mode/models.txt index ef5132d..ae7960f 100644 --- a/skills/odd-mode/models.txt +++ b/skills/odd-mode/models.txt @@ -1,74 +1,26 @@ -# oddstack model map -# One role per line. The form is `: ` or `: , `. -# `inherit-parent` or `auto` means omit the Task `model` field. The role runs on the parent chat model. -# An alias entry in a panel list still counts toward its fan-out. -# A missing role line falls back to the default named in the skill that spawns it. +# oddstack model map. /setup-oddstack writes this file. harness.md beside it says how to spawn an entry. # -# Find this file -# It lives in the odd-mode skill as models.txt. -# From a sibling skill, read ../odd-mode/models.txt. -# That relative path works in the repo and when each skill folder is linked on its own into -# ~/.agents/skills, ~/.claude/skills, ~/.cursor/skills, ~/.codex/skills, or Grok Bot's skill library. -# odd-mode is installed beside the other skills, so the path resolves through the symlink or junction. -# A path up to the repo root, such as ../../models.txt, fails once the skill folder is linked by itself. `../` is then the skills directory, not the repo. -# If the relative path misses, open the odd-mode skill the same way you opened the current skill and read models.txt there. +# : | ... +# is `