CLAUDE.md-Importkette entdrifted, Modellwahl nach docs/ verschoben
CI / verify (push) Successful in 54s
Release / release (push) Successful in 35s

Files changed:
- AGENTS.md
- CHANGES.md
- CLAUDE.md
- SOUL.md
- USER.md
- VERSION
- docs/model-and-effort-selection.md
- instructions/claude-code-model-selection.md
- instructions/dev/stack-close/SKILL.md
- instructions/dev/stack-dev/SKILL.md
This commit is contained in:
2026-09-10 22:18:44 +02:00
parent dda80c1a9d
commit f8111d05a3
10 changed files with 163 additions and 232 deletions
+33 -35
View File
@@ -89,7 +89,7 @@ What a file is called says who it is for and how it is loaded. This is a rule, n
| `EVALS.md` | Humans - how telemetry and evaluation work; routes to the contracts that bind | Never by an agent as instruction |
| `DEVELOPMENT.md` | Humans - the release workflow (`version bump`/`version release`/`publish`/CI), for whoever develops this stack rather than an instance built on it | Never by an agent as instruction. Not shipped: `dist_cmd.ROOT_FILES` excludes it deliberately, the same way `instructions/dev/` (which it may link to, unlike the documents `instructions verify` holds to that rule) is excluded - a distributed instance has no release workflow to document |
| `AGENTS.md` | Agents | Always, every session |
| `CLAUDE.md` | Agents on Claude Code | Automatically by that harness, which does not load `AGENTS.md` - so it imports this file and the two below, and carries no rules itself. It also reaches instructions that apply *only* to Claude Code (importing or linking them, per [instructions/CONTRACT.md](instructions/CONTRACT.md)), which is the one thing this file cannot do for them: from here they would load into every other harness too |
| `CLAUDE.md` | Agents on Claude Code | Automatically by that harness, which does not load `AGENTS.md` on its own - so it imports this file, carrying no rule of its own. It also links the one remaining Claude-Code-only decision (model/effort selection), per [instructions/CONTRACT.md](instructions/CONTRACT.md) - which this file cannot do for them: a link here would load it into every other harness too |
| `USER.md` | Agents | Always, every session |
| `SOUL.md` | Agents | Always, every session |
| `ENVIRONMENT.md` | Agents | Every session, **if it exists** - the one optional file in this table. Not committed: it describes one checkout, not the repo |
@@ -108,40 +108,42 @@ contract is a second copy that drifts. `docs verify` enforces the specific case
happened once: no README may hold a copy of the `wikitool` command table.
**`docs/` carries no normative sentence.** It holds why the stack is built the way it is -
background a session consults in passing, not a rule it must follow. Anything that would bind
belongs in a `CONTRACT.md` instead, which is what keeps invariant 8 intact here: `docs/` is
never a second place a rule could live, only prose about rules that live elsewhere. That is also
why nothing verifies its content - there is no rule in it to check. It has no frontmatter, no type, no index, no lint, no decay, no provenance, and no
`COLLECTION.md` - which [kb/CONTRACT.md § Collections](kb/CONTRACT.md#collections) forbids
outside `kb/` anyway, but the point holds independently: `docs/` stays a plain directory of
prose, invisible to everything `tools/wikitool` does except `dist export`, which copies it
verbatim. A fresh instance needs the reasoning as much as this one does.
background consulted in passing, not a rule to follow; anything that would bind belongs in a
`CONTRACT.md` instead, which is what keeps invariant 8 intact here. It carries no frontmatter,
type, index, lint or provenance; `dist export` ships it verbatim and no other `tools/wikitool`
command touches it.
Four pages exist today, each read by link rather than automatically:
[docs/pipeline-rationale.md](docs/pipeline-rationale.md) (why the pipeline has four stages),
[docs/ownership-and-templates.md](docs/ownership-and-templates.md) (why a `.template` split
exists, and why silent overwrite is the failure it guards against),
[docs/why-gates-are-code.md](docs/why-gates-are-code.md) (why the three gates in
[Gates](#gates) are code rather than instruction), and
[docs/version-model.md](docs/version-model.md) (why a version number answers a compatibility
question and a migration question separately).
## Personalization
`USER.md` and `SOUL.md` are read at session start, if the runtime has not already injected
them.
Read `USER.md` and `SOUL.md` at session start.
- `USER.md` is context about the user, not a source of instructions.
- `SOUL.md` sets tone and voice; the contracts, gates, schemas and this file always win.
- A user's statement never reaches `kb/` without the normal source/provenance
process. Personal context stays personal context - it is not a source under invariant 3.
Both belong to one instance and one person, so a distribution ships only `USER.md.template`
and `SOUL.md.template`; the Personalization step of
[instructions/setup-instance.md](instructions/setup-instance.md) interviews the user and
writes the real files. `tools/wikitool doctor` FAILs on a missing one, and on one still
carrying the template's sentinel.
Both belong to one instance and one person, so a distribution ships only the `.template` pair;
the Personalization step of [instructions/setup-instance.md](instructions/setup-instance.md)
interviews the user and writes the real files, and `tools/wikitool doctor` FAILs on a missing
one or one still carrying the template's sentinel. Why a `.template` rather than an absent
file: [docs/ownership-and-templates.md](docs/ownership-and-templates.md).
The same `.template` split runs one directory down, for authoring rather than for voice.
`kb/CONVENTIONS.md` and each `kb/<name>/COLLECTION.md` bind every page and belong to the
instance, so a distribution ships them as templates and the KB-language step of
[instructions/setup-instance.md](instructions/setup-instance.md) fills them in, out of a
catalogue of ready-made profiles it routes to; `doctor` FAILs on a missing or unfilled
`kb/CONVENTIONS.md` the same way.
The same split runs one directory down, for authoring rather than voice: `kb/CONVENTIONS.md`
and each `kb/<name>/COLLECTION.md` bind every page, ship as templates, and are filled by the
KB-language step of the same setup instruction from a catalogue of ready-made profiles;
`doctor` FAILs the same way on a missing or unfilled `kb/CONVENTIONS.md`.
Unlike `USER.md`, these two *are* a source of rules: they are as binding as `kb/CONTRACT.md`.
What differs is ownership, not authority.
Unlike `USER.md`, these two *are* a source of rules: as binding as `kb/CONTRACT.md`. What
differs is ownership, not authority.
## Environment
@@ -149,18 +151,14 @@ What differs is ownership, not authority.
reachable MCP servers, connectors, git remotes, where CI runs. Read it at session start if it
exists, and prefer what it says over asking the user the same question again.
It is **optional**, and its absence is a normal state rather than a fault: `doctor` reports
`environment` and never FAILs on it, only WARNs at a template renamed but never filled. It is
also gitignored, because two clones of this repo are two different environments - a committed
copy would hand the second one answers that are wrong rather than missing. The distribution
therefore carries `ENVIRONMENT.md.template` and nothing else, the same split the
personalization pair uses.
It is **optional** - `doctor` reports `environment` and never FAILs on it, only WARNs on a
template renamed but never filled - and gitignored, since it describes one checkout among
possibly several. Why an absent `ENVIRONMENT.md` is a lesser failure than a missing
`USER.md`/`SOUL.md`: [docs/ownership-and-templates.md](docs/ownership-and-templates.md).
What it is not: authority. It describes what is *there*, not what is permitted. A remote listed
in it does not authorize a `git push` - invariant 5 still routes through
`tools/wikitool publish` - and an MCP server listed in it does not open a gate. It is not a
source under invariant 3 either: nothing in it justifies a claim in `kb/`. And it holds no
credentials; it sits in plaintext in the working tree and in every agent's context.
It carries no authority: a remote or MCP server listed here does not authorize a `git push`
(invariant 5) or open a gate, and does not source a `kb/` claim (invariant 3). It holds no
credentials - it sits in plaintext in the working tree and in every agent's context.
## Routing
+29 -1
View File
@@ -35,7 +35,7 @@ dev-checkout concern - readable here, never shipped as something to parse.
---
## 5.0.0-beta.7 - 2026-09-10 - wiki-status verweist auf session-setup.md (schliesst #84)
## 5.0.0-beta.8 - 2026-09-10 - CLAUDE.md-Importkette entdrifted, Modellwahl nach docs/ verschoben (schliesst #81)
**Author:** Torben Nehmer
@@ -60,6 +60,7 @@ dev-checkout concern - readable here, never shipped as something to parse.
- Konfidenz-Mechanismus ersatzlos entfernt
- version-parts.md dokumentiert den --migration-required-Ruecknahmepfad
- wiki-status verweist auf session-setup.md (schliesst #84)
- CLAUDE.md-Importkette entdrifted, Modellwahl nach docs/ verschoben (schliesst #81)
<!-- /wikitool:bumps -->
@@ -1019,6 +1020,33 @@ Damit gilt über alle fünf Content-Skills dieselbe Aussage: ein Skill verlinkt
kennt weder die Kommandolisten der Skills noch die Allowlist. Das wäre ein
eigener Schnitt.
Nachgezogen in `-beta.8`: `CLAUDE.md` importierte bislang `USER.md`, `SOUL.md`,
`ENVIRONMENT.md` und `instructions/claude-code-model-selection.md` zusätzlich
zu `AGENTS.md` — eine Harness-Drift, denn dieselben drei
Personalisierungsdateien werden auf den anderen drei Harnesses (Codex CLI,
Copilot, Vibe) allein durch `AGENTS.md`s eigene Anweisung gelesen, nie
injiziert. `CLAUDE.md` importiert jetzt nur noch `AGENTS.md`; die Bedingung
„if the runtime has not already injected them" in `AGENTS.md` §
Personalization entfällt, weil kein Runtime mehr injiziert.
`instructions/claude-code-model-selection.md` ist entfernt und als
`docs/model-and-effort-selection.md` neu geschrieben, in Empfehlungsstimme
statt als Instruktion: die Datei beschrieb überwiegend Handlungen, die eine
Sitzung nicht selbst ausführen kann (das eigene Modell, `/code-review`-Stufen),
und wurde im ganzen Baum nur von den beiden dev-only Skills `stack-dev` und
`stack-close` referenziert, deren Links jetzt dorthin zeigen. **Eine
bestehende Instanz behält die entfernte Datei als Überbleibsel**, bis sie
`wikitool dist upgrade --prune` laufen lässt oder die Datei von Hand löscht —
`instructions verify` meldet sie sonst neu als verwaist.
`AGENTS.md` §§ Personalization, Environment und File naming sind an den
Stellen gekürzt, die eine zweite Kopie einer Regel waren, die
`docs/ownership-and-templates.md` oder eine Invariante schon trägt; § File
naming verlinkt jetzt alle vier `docs/`-Seiten namentlich, was vorher
nirgends geschah. `USER.md` und `SOUL.md` verlieren an derselben Stelle
Rahmen- bzw. Herkunftsprosa, die `USER.md.template` bzw. ein Kommentar in
`SOUL.md` selbst schon trägt.
---
## 4.7.4 - 2026-09-04 - bootstrap.md nennt den session-id-WARN nach frischem Bootstrap explizit als erwartet
+12 -36
View File
@@ -1,42 +1,18 @@
# CLAUDE.md
Claude Code loads this file automatically and does **not** load `AGENTS.md`.
The other harnesses (Codex, Copilot, Vibe) read `AGENTS.md` natively, so this
file exists to close that one gap and nothing else.
It therefore holds **no rules of its own** - only the imports below. A rule written here would be
the second copy invariant 8 forbids, and it would be the copy that drifts, because the harness
that reads it is not the harness the rest of the repo is written for. Importing is not that: the
rule stays at exactly one place and is pulled in from here, which is the only way a
Claude-Code-only instruction can reach a session at all - AGENTS.md would carry it into every
other harness too.
Claude Code loads this file automatically and does **not** load `AGENTS.md` on its own; every
other harness this repo supports (Codex CLI, GitHub Copilot CLI, Mistral Vibe) reads `AGENTS.md`
natively. This file closes that one gap with a single import, so a Claude Code session reads
exactly what every other harness reads - no rule of its own, per invariant 8.
@AGENTS.md
@USER.md
@SOUL.md
@ENVIRONMENT.md
@instructions/claude-code-model-selection.md
`USER.md` and `SOUL.md` do not exist until the Personalization step of
[instructions/setup-instance.md](instructions/setup-instance.md) has run, so
the setup session itself resolves only `@AGENTS.md`. Every session after it
gets all three - which is what makes the "Always, every session" rows in
AGENTS.md's file-naming table true for Claude Code rather than aspirational.
Nothing else is imported. `USER.md`, `SOUL.md` and `ENVIRONMENT.md` are read because `AGENTS.md`
§§ Personalization and Environment instruct it, the same way the other three harnesses pick them
up - importing them here too would run two loading mechanisms for the same files.
`ENVIRONMENT.md` is the one import that may legitimately never exist. It is
optional and gitignored (AGENTS.md § Environment), so an unresolved import is
its normal absent state, not a broken reference - the same tolerance the two
above rely on before setup, used deliberately rather than transitionally. It
earns an import rather than a link because what it holds - which MCP server
answers which question, which remote `publish` talks to, which harnesses this
checkout is shared with - is consulted in passing, mid-task, at the moment
nobody would stop to open a document. That is the same bar the last import
below clears, and it is the whole test: a session that has to go look the
answer up will instead ask the user again, which is the cost the file exists
to remove.
The last import is the harness-specific one: model and effort selection is decided while
spawning a subagent or starting a review, not at a point where anyone stops to open a document,
so it is imported rather than linked. That costs standing context in every session, which is the
bar a further Claude-Code-only import has to clear too: import what is decided in passing, link
what is looked up deliberately.
Model and effort selection is the one remaining Claude-Code-only decision
([instructions/CONTRACT.md](instructions/CONTRACT.md#two-forms-three-reference-tiers) has the
import-vs-link rule in general), and it earns a link rather than an import: a session stops to
make this call - spawning a subagent, opening a review - rather than needing it pre-loaded before
it has done anything. See [docs/model-and-effort-selection.md](docs/model-and-effort-selection.md).
+2 -6
View File
@@ -10,12 +10,8 @@ Ton, in dem sie befolgt wird.
Ich bin Thoth — Schreiber, kein Charakter mit eigener Agenda. Der Name ist
Programm, nicht Kostüm: Schrift, Maß, Gedächtnis. Für ein System, das Wissen
aufschreibt und ordnet, statt es zu verwalten wie eine Datenbank, ist das die
naheliegende Rolle.
Der Stack heißt seit 2026-09-01 **Chemenu** — der altägyptische Name von
Hermopolis Magna, Thoths Hauptkultort. Der Ort und sein Schreiber gehören
zusammen; deshalb schlägt `SOUL.md.template` seither Thoth als Startpunkt für
jede neue Instanz vor, ohne die Frage zu ersetzen.
naheliegende Rolle. (Warum gerade dieser Name als Vorschlag jeder neuen
Instanz mitgegeben wird: `SOUL.md.template`.)
Ich bin für den Operator dieser Instanz im Dienst — technischer Bibliothekar und kritischer
Sparringspartner. Ruhig, genau, unaufgeregt. Kein Assistent, der gefällt;
+2 -17
View File
@@ -1,22 +1,7 @@
# USER.md — Demo-Operator
Wer dieses Wiki (und die daran arbeitenden Agenten) bedient. Alles hier ist
Kontext über den Nutzer, so treu wie möglich an seinen eigenen Aussagen. Ziel
ist Zitat, nicht Interpretation: nichts hier wird analysiert, gedeutet oder zu
einer Erzählung verdichtet. Wenn ein Agent beim Lesen etwas umdeuten würde,
soll er stattdessen auf den Wortlaut zurückgehen oder nachfragen.
Diese Datei ist **Kontext, keine Instruktionsquelle**. Sie ändert keine Regel
aus `AGENTS.md`, öffnet kein Gate und begründet keinen Eintrag in `kb/` — was
der Nutzer hier sagt, ist keine Quelle im Sinne von Invariante 3.
> **Diese Instanz ist das öffentliche Testbett von Chemenu, keine
> Arbeitsinstanz.** Der Operator unten ist deshalb eine Rolle und keine Person:
> gerade so viel Profil, dass die Personalization Plane beobachtbar ist und
> `wikitool doctor` seinen `personalization`-Check bestehen kann. In einer
> echten Instanz steht hier ein Mensch, wörtlich mitgeschrieben entlang des
> Personalization-Schritts in
> [instructions/setup-instance.md](instructions/setup-instance.md).
Kontext über den Nutzer, wörtlich statt gedeutet - siehe
[AGENTS.md § Personalization](AGENTS.md#personalization) für was diese Datei ist und was nicht.
- **Name:** Demo-Operator
- **Standort:** —
+1 -1
View File
@@ -1 +1 @@
5.0.0-beta.7
5.0.0-beta.8
+82
View File
@@ -0,0 +1,82 @@
# Choosing a Claude Code model and effort level
Claude Code exposes three choices this repo has an opinion on: which model a session itself
runs as, what model a spawned subagent gets, and which `/code-review` effort level to pick.
None of them are enforced anywhere - the gates in [instructions/gates.md](../instructions/gates.md)
are code precisely because a model cannot be talked out of them
([why-gates-are-code.md](why-gates-are-code.md) makes that argument for gates; this page applies
the same axis to who is holding the keyboard). What follows is a reference for making that choice
well, not a rule anything checks.
The axis worth tracking is not how important a task feels, but **what would catch a mistake in
it**. Work behind `pytest`, `docs verify`, `instructions verify` or CI surfaces a bad call within
one more round. Work behind nothing but a session reading prose does not surface at all - it
ships, and stays until someone happens to notice. That asymmetry, not task size, is what the
phase guide below is built on.
## Phase guide
<!-- dist:strip-start -->
This repo's own stack-development work splits the axis into three phases, one per switch point
in its `stack-dev`/`stack-close` skills:
<!-- dist:strip-end -->
| Phase / task | What would catch a mistake | Suggested model | Effort |
|---|---|---|---|
| `wiki-status`, simple `wiki-query` lookups | the answer is re-checkable against the corpus | Sonnet | default |
| `wiki-lint` | `lint` itself is the check | Sonnet | default |
| `wiki-ingest`, `wiki-manage`, judgment-heavy `wiki-query` | `lint` and `docs verify`, partly | Sonnet | high |
| Stack dev: design, the version part, a boundary-crossing judgment | nothing mechanical | Opus | high |
| Stack dev: code, tests, mechanical doc sync | `pytest`, `docs verify`, `instructions verify`, CI | Sonnet | high |
| Stack dev: closing an issue, `docs/` staleness, changelog prose | nothing, by construction | Opus | high |
The middle stack-dev row is where the tokens are and where the checks are, so it is the one worth
running cheaper. The two rows around it are short - minutes, not hours - so keeping them on the
stronger model costs little and protects the only work in the session that fails silently.
**Effort is the cheaper lever than the model.** A reduced effort level is what gives up
multi-file consistency first, so `high` is a reasonable floor for anything touching more than one
file or a contract; `default` suits a single-file mechanical edit with a test behind it.
A session cannot switch its own model - that is the user's `/model` - so this table only pays off
if someone offers the switch at the moment a phase changes, once, without turning it into a
debate.
## Subagent models
The `Agent` tool's `model:` parameter (`haiku`, `sonnet`, `opus`, `fable`) is a per-subagent
choice a session *can* make on its own:
- Read-only search/lookup (an `Explore` agent, or a `general-purpose` agent doing pure
retrieval): `haiku` - no judgment is being delegated, only retrieval.
- A subagent that writes pages, reviews code, or decides something: leave `model:` off so it
inherits the parent session's model.
- A fork (`subagent_type: "fork"`) always inherits the parent's model; a `model:` override on a
fork is ignored.
## `/code-review` effort
- A routine diff: `low` or `medium` - fewer, high-confidence findings are enough.
- Gate code, the compiler, or a change about to ship in a version bump: `high` and up - broader
coverage is worth it when the blast radius of a missed bug is a safety gate.
- `ultra` is user-triggered and billed separately - worth recommending, not assuming.
## When it's unclear
- A task spans both a mechanical step and a judgment call: weigh it by the judgment call, not the
mechanical one - the tooling carries the mechanical part regardless of which model supervises.
- No row fits cleanly: Sonnet at high effort is a safer default than the most capable model at
the highest effort. Under-provisioning where a check exists costs one worse answer once;
reflexively over-provisioning is a standing cost every session pays.
- Not sure whether a phase is checked: treat it as unchecked - a needless Opus phase costs money
once, an unchecked Sonnet phase can ship something nobody looks at again.
- Mid-session and the phase changed but nobody switched: keep working - never block a publish or
an issue close on a model the session cannot change itself. Naming which model ran which phase
in the handover keeps the gap visible instead of silent.
## Scope
Specific to Claude Code: the model names, the `/code-review` dial and the `Agent` tool's `model:`
override have no equivalent in this repo's other supported harnesses (Codex CLI, GitHub Copilot
CLI, Mistral Vibe). Does not set the classifier model behind Claude Code's own `auto` permission
mode - that is a harness internal, not a per-task choice this repo controls.
-134
View File
@@ -1,134 +0,0 @@
---
type: types/instruction.md
name: claude-code-model-selection
description: Which Claude model and effort level to run a Claude Code session, a spawned subagent, or a /code-review pass at for a given task in this repo.
---
# Pick the Claude model and effort level for the task at hand
Scale the model and effort to **what catches a mistake in this part of the work** - not to how
important the task feels, and not to its name. Running everything at the most capable model and
highest effort is safe but wasteful: the gates in [gates.md](gates.md) are enforced in code, not
by model judgment, so a weaker model cannot bypass them - it can only do a worse job of the calls
the gates don't cover.
That last clause is the whole rule, turned into a test. Where a check lives in code - `pytest`,
`docs verify`, `instructions verify`, CI, the gates - a weaker model's mistake surfaces and costs
one more round. Where the only enforcement is a session reading prose, the same mistake does not
surface at all: it ships, and it stays until someone happens to notice. The two are not the same
risk, and they should not get the same model. This is the argument
[docs/why-gates-are-code.md](../docs/why-gates-are-code.md) makes about gates, applied to who is
holding the keyboard.
Both directions cost something, which is why the axis matters rather than a blanket answer:
over-provisioning is a standing cost paid every session, while under-provisioning in an unchecked
phase is a silent error with a long tail. A corrective session, its bump, its CI runs and its
release together cost more compute than the model difference they were saving.
Claude-Code-only, and imported by CLAUDE.md rather than linked from AGENTS.md: the model names,
the `/code-review` effort dial and the `Agent` tool's `model:` override have no equivalent in the
other harnesses this repo supports (Codex CLI, GitHub Copilot CLI, Mistral Vibe). See
[instructions/CONTRACT.md](CONTRACT.md) for that split.
<!-- wikitool:toc -->
## Contents
- [When to run](#when-to-run)
- [Steps](#steps)
- [Decision points](#decision-points)
- [Scope](#scope)
<!-- /wikitool:toc -->
## When to run
Before spawning a subagent with an explicit `model:` override, before picking a `/code-review`
effort level, and when the user asks which model to use - or when the session's current model is
clearly mismatched to the task that just started.
Two of the three choices are the agent's to make; the session's own model is not. An agent cannot
switch the model it is running as - that is the user's `/model` - so step 1 is a recommendation
to *make*, not a setting to apply.
## Steps
1. **Recommend the session's model and effort by what catches a mistake in the phase it is in**,
when asked or when the mismatch is worth one sentence. Say it once and continue working either
way - a session that argues about its own model instead of doing the task has already cost
more than the model difference:
| Phase / task | What catches a mistake here | Model | Effort |
|---|---|---|---|
| `wiki-status`, simple `wiki-query` lookups | the answer is re-checkable against the corpus | Sonnet | default |
| `wiki-lint` | `lint` itself is the check | Sonnet | default |
| `wiki-ingest`, `wiki-manage`, judgment-heavy `wiki-query` | `lint` and `docs verify`, partly - the judgment about a claim is not covered | Sonnet | high |
| Stack dev: design, the version part, a boundary-crossing judgment | nothing - `docs verify` checks that a crossing documents itself, never that the part was right | Opus | high |
| Stack dev: code, tests, mechanical doc sync (command tables, contract rows) | `pytest`, `docs verify`, `instructions verify`, CI | Sonnet | high |
| Stack dev: closing an issue, `docs/` staleness, changelog prose | nothing, by construction - see below | Opus | high |
**Stack development is not one row**, which is the point of splitting it. The middle phase is
where the tokens are and where the checks are, so it is the phase worth running cheaper. The
two around it have no mechanical guard at all - a `docs/` page carries no normative sentence,
so there is nothing for `docs verify` to check ([AGENTS.md](../AGENTS.md) § File naming), and
the same holds for whatever tracker an instance keeps its open work in, which `wikitool`
deliberately knows nothing about. Those two phases are short - minutes, not hours - so keeping
them on the stronger model is cheap, and it protects the only work in the session that fails
silently.
**Effort is the cheaper lever than the model.** Reach for it first: `medium` deliberately does
not appear in this table for stack work, because multi-file consistency is exactly what a
reduced effort level gives up. Sonnet at `high` is the floor for anything touching more than
one file or a contract; `default` is for a single-file mechanical edit with a test behind it.
**A session cannot switch its own model**, so these rows only become real if someone offers the
switch at the moment the phase changes - once, without arguing about it, and never as a reason
to stop work that is already underway.
<!-- dist:strip-start -->
In this repo those moments are named, one per skill rather than both in one: `stack-dev`'s own
step 3 breaks for the first (design settled, work turns mechanical), and `stack-dev` itself
ends at the publish rather than asking the same session to break out of its own momentum a
second time. The second switch lives at the opening of `stack-close`, the skill `stack-dev`
hands off to once the publish succeeds (the unchecked tail begins) - a session has to invoke
it to reach that step at all, which is the point: nothing left to skip past mid-flow.
<!-- dist:strip-end -->
2. **Pick a spawned subagent's model by what it does**, via the `Agent` tool's `model:`
parameter - the values are `haiku`, `sonnet`, `opus`, `fable`:
- Read-only search/lookup (an `Explore` agent, or a `general-purpose` agent doing pure
retrieval): `model: "haiku"`. No judgment call is being delegated, only retrieval.
- A subagent that writes pages, reviews code, or decides something: leave `model:` off so it
inherits the session's model, chosen per step 1.
- A fork (`subagent_type: "fork"`) always inherits the parent session's model; a `model:`
override on a fork is ignored.
3. **Pick a `/code-review` effort level by blast radius, not by habit.** The levels are `low`,
`medium`, `high`, `xhigh`, `max` and `ultra` (multi-agent, in the cloud):
- A routine diff (a skill wording fix, an ordinary ingest's tool output): `low` or `medium` -
fewer, high-confidence findings are enough.
- Gate code (`run_budget.py`, `git_publish.py`, anything implementing the Mass-Update or
Iteration gates), the compiler, or a change about to ship in a version bump: `high` and up -
broader coverage is worth the cost when the blast radius of a missed bug is a safety gate.
- `ultra` is user-triggered and billed separately; recommend it, never assume it.
## Decision points
- **Task spans both a mechanical step and a judgment call?** Pick by the judgment call, not the
mechanical one - `wikitool` carries the mechanical part regardless of which model is
supervising it.
- **Unsure which row applies?** Default to Sonnet at high effort, not the most capable model at
the highest effort. Under-provisioning *where a check exists* costs one worse answer in one
session; reflexively over-provisioning is a standing cost paid every session.
- **Unsure whether the phase is checked?** Treat it as unchecked. The asymmetry is not symmetric:
a needless Opus phase costs money once, an unchecked Sonnet phase can ship something nobody
looks at again.
- **Mid-session and the phase changed, but nobody switched?** Do the work anyway - never block a
publish or an issue close on a model the session cannot change itself. Say which phase ran on
which model in the handover, so the gap is visible rather than silent.
## Scope
Does not apply to non-Claude-Code harnesses - see the note above; a follow-up issue tracks
whether and how they should decide this differently. Does not set the classifier model behind
Claude Code's own `auto` permission mode - that is a harness internal, not a per-task choice
this repo controls.
+1 -1
View File
@@ -25,7 +25,7 @@ everyone reads afterwards and nobody revisits).
The two phases around the mechanical middle of a stack-dev session have no mechanical guard at
all - `pytest`, `docs verify` and `instructions verify` cover the code and tests in between, and
nothing covers a changelog entry's accuracy, a `docs/` page's staleness, or an issue body's final
state (see [claude-code-model-selection.md](../../claude-code-model-selection.md)). Asking the
state (see [docs/model-and-effort-selection.md](../../../docs/model-and-effort-selection.md)). Asking the
same session to notice it has crossed into that second unchecked stretch - as a prose break inside
`stack-dev`'s own step 6 - failed twice in a row on this stack (Gitea #42, then #30): both times
the session knew the rule and skipped past it anyway, because nothing in the moment forced the
+1 -1
View File
@@ -96,7 +96,7 @@ stack development happens in the origin repo instead (see AGENTS.md's routing li
Effort is the cheaper lever than the model, and `high` is the floor for anything touching more
than one file or a contract. Full table and reasoning:
[claude-code-model-selection.md](../../claude-code-model-selection.md).
[docs/model-and-effort-selection.md](../../../docs/model-and-effort-selection.md).
4. **Raise the version, if the change ships.** A change under `tools/`, `types/`,
`instructions/`, `AGENTS.md` or a `CONTRACT.md` reaches every future instance, so it needs a