# Lanes, Model line, slice jobs, area maps Reference (released 2026-10-05). Lanes split work by task **size** and **pick policy**: a fast lane clears small, unblocking work and slices big tasks; a slow lane takes 1h slices; more lanes by config. The model is a per-task attribute (`Model:` line): interactive sessions take tasks with Model ≤ their own, orchestrated workers run on the task's Model. Area maps (code map + test recipe per area) are checked and refreshed by auto-added tasks. ## 0. The Model line - Task body line ` Model: haiku|sonnet|opus` (2-space indent like `Ref:`; `- Model:` also parsed), in the body tail before `After:` / `Ref:`. No line → `opus`. Order haiku < sonnet < opus. - Set by the task's writer at `wf add --model M`; `wf set ID --model M`; `--model ""` removes it (→ opus). - `haiku`: mechanical edit, exact instructions, no judgement. - `sonnet`: exact Done criteria + an existing pattern to copy + a real-data pass/fail test. - `opus`: design forks, debugging, reverse engineering / oracles, cross-source analysis, anything unclear. - Wrong level found mid-task: `wf set ID --model ` + `wf note ID ""` + `wf status ID clear`. - `wf check`: unknown value or two Model lines → error; extra words after the value → warning; missing → fine. ## 1. Lane config `workflow.toml`, optional; absent → built-in default equal to: ```toml slice_above = "1h" # effort above this → slice job (§3); one of EFFORTS [lanes.fast] efforts = ["<1h"] # efforts this lane implements order = "unblock" # pick policy (§2) slices = true # this lane also takes slice jobs (exactly one lane may set it) [lanes.slow] efforts = ["1h"] order = "priority" fallback = "fast" # nothing pickable here → pick from that lane ``` - Lane name: `[a-z][a-z0-9-]*`; used in worktree `.worktrees/`, branch `/`, registry file. - `efforts`: subset of `EFFORTS`, ≤ `slice_above`; lanes' efforts are disjoint; every effort ≤ `slice_above` belongs to some lane. Tasks without effort → the lane holding `<1h`. - `order`: `unblock` | `priority`. `fallback`: another lane name, optional, no cycles. - `slices = true` on exactly one lane; default: the lane holding `<1h`. - Validation errors in `config.load` (unknown keys are errors). Defining `[lanes.*]` replaces the whole default set (no merge). - Extra lanes: add tables (e.g. `[lanes.long] efforts = ["5h"]` with `slice_above = "5h"`). Several workers in one lane = existing `-2`, `-3` worktrees. ## 2. Pick order Pickable set (Pending, not blocked, no open slices, all `After:` archived, no live foreign claim), filtered to the lane's efforts (plus slice jobs on the `slices` lane) and to Model ≤ session model (interactive only). Effective priority = best (lowest P) of the task's own and that of every open task waiting on it, transitively ("waits on" = `After: [[x]]`, or a parent waiting on its open slices). Keys: - `unblock`: (1) waited-on count > 0 first, (2) more open tasks waiting on it (transitively) first, (3) effective priority, (4) file order. - `priority`: (1) effective priority, (2) waited on by another lane first, (3) waited-on count, (4) file order (section order, then position). ## 3. Slice jobs - A Pending task with effort > `slice_above` and no open slices = slice job. It is not pickable as an implementation task in any lane; it is pickable in the `slices` lane, ranked by that lane's order. - Shown with `slice:` prefix in `wf next`, `wf list --runner`, `wf lanes` counts (`2 pickable (1 slice)`). - `wf next` prints for it: `Slice job: wf add "" -e <1h|1h> --parent <id> --model M` per slice, each with Steps/Done/Ref; no code; `wf note <id> "sliced into …"`; `wf status <id> clear`. Not `wf done` (parent stays open until its slices are done). - Model of a slice job = the task's Model (default opus; slicing is judgement). - A task with open slices is never a slice job (already sliced). All slices done → parent pickable only if its effort ≤ `slice_above`; otherwise `wf done` of the last slice prints `parent <id>: all slices done → wf done <id> or add slices` (it is not offered as a slice job again while it has done slices: rule = no open slices AND no archived slices). ## 4. Sessions, registry, model - `wf next [--lane L] [--as M]`: `--as` = the session's model (haiku|sonnet|opus); none → haiku, with a hint line. `--lane` = lane name; no `--lane` → all lanes merged, `priority` order, slice jobs included. - Registry `.wf/sessions/<lane>.json` (`{"lane", "model", "socket", "pid", "session", "at"}`, from env `CLAUDE_CODE_MESSAGING_SOCKET`, `CLAUDE_PID`, `CLAUDE_CODE_SESSION_ID`; skipped without them); no `--lane` → `all.json` (`all` is reserved). `.wf/.gitignore` = `*`. Newest wins per lane unless another live session holds it: then kept, and `wf next` first prints `another live <lane> session holds this lane: uds:…`. Alive = pid and socket file exist. `wf lanes --unregister` drops this session's records. - Claims: `wf status ID progress …` writes `.wf/claims/ID.json` (`{"id", "lane", "model", "socket", "pid", "session", "at"}`); `status clear|blocked` and `wf done` remove it. `wf next` skips a task whose claim is alive, not mine and still `in progress`. - `wf lanes [--lane L]`: one line per configured lane: `fast: 3 pickable (1 slice) · 1 waiting · session uds:… (alive)` / `… · no session`. - Waiting block: `t-y waits on t-x (slow lane) → message uds:…: "t-x blocks my t-y, please take it"` / `… → no slow session: tell the owner` — lane of a task = lane by effort (slice lane for slice jobs). - `wf done`: tasks of other lanes that became pickable → `notify <lane> uds:…: now pickable t-y` / `<lane> work now pickable: t-y (no session: tell the owner)`. - Messages go with the agents' SendMessage tool, `to` = `uds:<socket>`. - `wf list`: model and lane columns; filters `--model M`, `--lane L`; `--runner --lane L` = ids in pick order for that lane (no session model filter; the orchestrator spawns per task model). ## 5. Orchestrator, batch, worker - `docs/orchestrator.md`, `shared/skills/wf-orchestrate`: lanes from `wf lanes`; per lane `wf list --runner --lane <lane>` → first id; spawn `wf-worker` with `model: <task's Model>`; worktree `.worktrees/<lane>`, branch `<lane>/<id>`. At most one worker per lane worktree; lanes in parallel. - `wf batch N [--lanes fast,slow]` (default: all configured lanes). - `shared/agents/wf-worker.md`: prompt line `Lane: <lane> Model: <model>`; slice job → slice only, no code. - `wf usage --log … --lane L`: cost line per worker; `--report` rows by lane × model × effort. ## 6. Area maps - Notes file: config `areas = "<path>"`, default project `CLAUDE.md`. Section `## Areas`, one `### <area>` each with lines (all optional): - `- Code map: …` — anchors = backticked tokens (`` `parse_item` ``). - `- Test recipe: …` - `- Paths: <globs, space-separated>` — default: whole repo. - `- Checked: <short sha>` — last refresh; set by `wf areas --mark`. - `wf areas [AREA]`: per area: missing anchors (`git grep -F -q <token> -- <paths>` fails), commits touching Paths since Checked (`git rev-list --count <sha>..HEAD -- <paths>`), stale yes/no. Exit 0. - `wf areas --mark AREA`: write `Checked: <HEAD short sha>` into the section (add the line if missing). - Stale = any missing anchor, or Checked set and commits ≥ `area_stale_commits` (config, default 20). No Checked → only the anchor test. - `wf check`: missing anchor → warning `area <a>: anchor <tok> not found`. Unknown Checked sha → warning. - `wf done`: after bookkeeping, for each stale area with no open task whose id is `t-map-<slug>` → add `t-map-<slug>` P2 `<1h` Model: sonnet, title `Refresh <area> area map`, Steps: `wf areas <area>`; fix missing anchors and test recipe from changed files (`git log --stat <Checked>..HEAD -- <paths>`); `wf areas --mark <area>`. Done: `wf areas <area>` shows not stale. Printed `added t-map-<slug> (area map stale)`. Id taken by an archived task → `t-map-<slug>-2`, … (ids never reused). - No `## Areas` section → feature silent. Template `templates/CLAUDE.md` area block has `Paths:`/`Checked:`.