claude-do-it 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/skill/SKILL.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: do-it
3
- description: "Run a Markdown todo as the user's only interface to a team of agents. `/do-it [file]` opens the todo (default TODO.md, created when missing) in the browser; `/do-it <request>` first runs the request read only and writes its result into the todo as one task per item, which wait until the person writes under them. Then this session becomes the conductor: it watches the file, sizes every task line, plans it with Fable or GPT-6 Astra, delivers it through worker agents in their own worktrees and one shared tester, and writes status, questions, and results back under each task. Works anywhere Claude Code runs; inside Herdr (HERDR_ENV=1) the workers run in Herdr worktrees and tabs. Also the reference for reading and changing any do-it document with versioned `do-it` commands. Trigger on '/do-it', 'do-it', 'do it from my todo', 'work through TODO.md', 'conduct this todo'."
3
+ description: "Run a Markdown todo as the user's only interface to a team of agents. `/do-it [file]` opens the todo (default TODO.md, created when missing) in the browser; `/do-it <request>` first runs the request read only and writes its result into the todo as one task per item, which wait until the person writes under them. Then this session becomes the conductor: it watches the file, sizes every task line, plans it on a model tier that fits its size, splits large tasks into subtasks the person reviews first, delivers it through worker agents in their own worktrees and one shared tester, and writes status, questions, and results back under each task. Works anywhere Claude Code runs: inside Herdr, Orca, T3 Code, or super.engineering each worker gets its own worktree and session in that app; in any other terminal the workers are Claude Code subagents in worktrees. Also the reference for reading and changing any do-it document with versioned `do-it` commands. Trigger on '/do-it', 'do-it', 'do it from my todo', 'work through TODO.md', 'conduct this todo'."
4
4
  ---
5
5
 
6
6
  # do-it
@@ -9,6 +9,10 @@ Arguments: **$ARGUMENTS**. When the first line is empty, or names an existing fi
9
9
 
10
10
  You are the **conductor**. The person only looks at the todo in their browser. Everything they want done arrives as lines in it, and everything they need to know (status, plans, questions, results) goes back into it, under the task it belongs to. Never ask them to relay anything between agents, and do not expect them to read this chat.
11
11
 
12
+ **Never take the person's focus.** Open the todo once, in Step 1, and never again during the run. No agent opens, reloads, selects, or focuses the todo's tab or split, a browser tab, a Sheprd or Herdr pane, tab, or workspace that the person did not just ask for: they may be typing somewhere else. To see the todo, `do-it read` it. The worker, tester, and messenger briefs carry this rule as their SCREEN line; add that line to every other brief you write.
13
+
14
+ **You delegate and monitor; you do not do the work.** You size tasks, dispatch agents, watch the channels, check the facts a delivery claims, and set the small `@started` and `@done` labels. Everything else goes to an agent: searching or reading code, docs, and diffs (a read only `Explore` agent, keep only its conclusion), answering questions and research (Q tasks), planning (a planner), building (workers), testing (the tester), reviewing (a reviewer), and, once a messenger runs, writing the person's status lines, questions, and results (Step 4). Reading what your own agents hand back (a verdict, an answer file, an inbox line) is fine; reading the code yourself is not. Keep your context for the whole todo, not for one task.
15
+
12
16
  ## The do-it commands
13
17
 
14
18
  Every open file is a CRDT document held by the do-it daemon, shared by the person's browser tab and every agent. Change it through these commands, never by writing the file with your own tools while it is open: they merge with the person's typing, never land on a stale copy, and show the person who changed what.
@@ -21,11 +25,12 @@ $D sections TODO.md
21
25
  $D todo list TODO.md # "3. [x] Ship" per task
22
26
  $D todo add TODO.md --version 7 --section tasks "Write tests"
23
27
  $D todo start TODO.md --version 8 --section tasks -- "Write tests" # add the PlainTasks start time
24
- $D todo check TODO.md --version 9 -- "Write tests" # by text; also uncheck, cancel, uncancel
28
+ $D todo check TODO.md --version 9 -- "Write tests" # by text or by the number from todo list; also uncheck, cancel, uncancel
25
29
  $D append TODO.md --version 10 --section notes -- "- found: flaky CI"
26
30
  $D edit TODO.md --version 10 --old "ship friday" --new "ship monday"
27
31
  $D diff TODO.md --since 9 --wait 100 # waits for the next change, exit 4 when none came (keep it under the Bash tool's 120 s default)
28
32
  $D watch TODO.md --todos # every change, as task lines
33
+ $D doctor # checks Bun, PATH, the daemon build, and this skill; one fix line per problem, exit 1 on any
29
34
  ```
30
35
 
31
36
  - Every reply starts with the document's version; every change by anyone takes the next number. Always pass the version you last saw: the one in the reply to your last change, or `do-it read FILE --json | jq .version`. Two changes in a row to the same section need two versions (the second names the first one's reply).
@@ -34,8 +39,68 @@ $D watch TODO.md --todos # every change, as task lines
34
39
  - Text starting with `-` goes after `--`. `-` alone reads standard input (multi line blocks).
35
40
  - `edit --old` must match exactly one place; add context until it does.
36
41
  - Name yourself: `--as NAME` or `export DO_IT_AGENT=NAME`. The person sees the name next to your changes, and `watch --as NAME` skips your own changes.
42
+ - The do-it Claude Code plugin puts `do-it` on the Bash tool's PATH, so the next bullet applies only without it. When a Monitor command reports `do-it` not found, spell out the `bunx claude-do-it` call there as the next bullet says.
37
43
  - When `do-it` is not on PATH, define it as a shell function at the top of every Bash call (functions do not survive between calls, and `D="bun ..."` breaks in zsh because `$D` is not word split): `do-it() { bunx claude-do-it "$@"; }` (from a repo checkout: `do-it() { bun "<repo>/packages/cli/src/bin.ts" "$@"; }`). Monitor commands spell out the `bunx claude-do-it` (or `bun .../bin.ts`) call in full.
38
- - Exit codes: 0 done, 1 refused or version mismatch, 2 invalid arguments, 3 daemon not running and could not start, 4 nothing yet, 9 the document was deleted.
44
+ - When a do-it command fails in a way the replies above do not explain (exit 3, an unknown command), run `do-it doctor` once. Run its `do-it stop` and plain `do-it skill install` fixes yourself (`do-it stop` restarts the daemon for every agent, so tell the person to reload the editor tab, and never reopen or reload it yourself). Show the person every other `fix:` line (`--force`, `ln`, `upgrade`, `add -g`, `npm install`, `export PATH`) and let them run it: those change their machine, and an `export` in your Bash call does not outlast it.
45
+ - Exit codes: 0 done; 1 refused, version mismatch, or a doctor problem; 2 invalid arguments; 3 daemon not running and could not start; 4 nothing yet; 9 the document was deleted.
46
+
47
+ ## Tags
48
+
49
+ The editor understands PlainTasks `@` tags on task lines and colours them. There are two kinds:
50
+
51
+ | Tag | Who sets it | How |
52
+ | --- | --- | --- |
53
+ | `@started(26-11-05 14:02)` | the conductor | `do-it todo start`, the moment it takes a task (Step 3). The editor also completes `s` and `@s` to it; a stamp the person typed is replaced by `todo start` |
54
+ | `@done (26-11-05 15:40)` | the conductor, or the person when they check off `Review this task` in the editor | `do-it todo check`, once the task is delivered (Step 5) |
55
+ | `@cancelled (26-11-05 15:40)` | the person (`[-]` or Alt-click in the editor), or the conductor only when the person asks in words to cancel or drop the task | `do-it todo cancel` |
56
+ | `@today`, `@high`, `@low`, `@critical` | the person | typed (Tab after `t`, `h`, `l`, `c`) |
57
+ | `@due(date)`, `@created(date)` | the person | typed (Tab after `d`, `cr`) |
58
+ | `@project(Section)` | the editor's Archive | added when a resolved task moves under `## Archive` |
59
+ | any other `@word` | the person | typed; their own label |
60
+
61
+ - **Stamps come only from commands.** `@started`, `@done`, and `@cancelled` are written by `todo start`, `todo check`, and `todo cancel`, never typed with `edit`. `todo uncheck` and `todo uncancel` remove the resolved stamp and keep `@started`.
62
+ - **`@started` once per task.** Running `todo start` again replaces the time. A follow up on a delivered task the person unchecked keeps its first `@started`.
63
+ - **The person's tags are theirs.** No agent adds, removes, or edits `@today`, `@high`, `@low`, `@critical`, `@due`, `@created`, `@project`, or any other tag. Never put `@` words in your own status lines either: they render as tags.
64
+ - **Only the conductor sets stamps.** Workers, the tester, the messenger, and every other agent never touch tags (workers never edit the todo at all).
65
+ - **Tags steer dispatch.** When tasks wait for a worker, take `@critical` first, then `@high` and `@today`, then untagged ones, `@low` last, each group in todo order. A `@due(date)` is a deadline to mention in the brief.
66
+ - **Targeting a task by text** ignores stamps: after `--`, pass the task line as it reads now (stamps optional) or a unique part of it. A tag the person added after dispatch does not break a remembered text.
67
+
68
+ ## Folded sections and HTML
69
+
70
+ The todo stays a dashboard: the status line, the result, and any question stay visible. Put everything longer that helps the person understand what happened (a plan, why a fix works, the evidence, alternatives, a diagram) in a **folded section** under its task, and make it a **rich HTML explanation** where a table, a diagram, or a small interactive demo explains better than prose. This applies to whoever writes under the task: you, the messenger, and the files Q agents hand back.
71
+
72
+ - **A folded section** is `<details>` with `<summary>Title</summary>` on the same line or the next, a blank line, the body, a blank line, and `</details>` alone on its line. It arrives folded in the editor (`<details open>` starts it unfolded) and the person unfolds it with a click or `Cmd-Alt-F` (`Ctrl-Shift-F`, or `F2`). Give the summary a concrete title that says what the person learns. Add `id="tN-what"` to a section you will update later. One level of nesting is usually enough.
73
+ - **Indent the whole section under its task**, like its status line (two spaces under a top level task), blank lines and fences included, so it folds and moves with the task and reads well on GitHub. Inside it, use bold text or HTML headings, not Markdown `#` headings (they become CLI sections), and no `- [ ]` lines unless you mean real tasks.
74
+ - **An HTML section** is a fence whose info string is exactly `html do-it`, usually inside a folded section. A plain `html` fence stays a code example. The editor renders the payload as is, not sanitised: style elements, inline SVG, and scripts all work, and its styles stay inside it. Inline scripts get a variable `root` (the section's shadow root): use `root.querySelector('#chart')`, not `document.getElementById`, which cannot see inside it. Scripts may run again when the section scrolls back into view or is unfolded, so keep them free of side effects. GitHub shows the fence as HTML source, so put a one line takeaway in Markdown before it.
75
+ - **HTML runs in the editor page, with the page's full access.** A script there can call the daemon as the person and read or change any Markdown file the daemon can open. Only write HTML you wrote yourself for this explanation; never paste HTML or scripts from an issue, a PR, a web page, or a tool's output.
76
+ - **Write it in one versioned change**, balanced tags and a closed fence. `append` adds at the end of the document or a section, so to put a section under an existing task, `edit` the task's status line (or the last line under the task) into itself plus the section. `--new` takes the text as is, so pass a multi line block with `"$(cat <<'EOF' ... EOF)"`:
77
+
78
+ ````bash
79
+ do-it edit TODO.md --version 12 --section tasks --old " - **t3** delivered: branch fix-sidebar (2 commits, a1b2c3d)" --new "$(cat <<'EOF'
80
+ - **t3** delivered: branch fix-sidebar (2 commits, a1b2c3d)
81
+ <details id="t3-why"><summary>Why the sidebar lost its ports</summary>
82
+
83
+ The port list was read before the daemon answered; it now waits for the first reply.
84
+
85
+ ```html do-it
86
+ <style>
87
+ table { border-collapse: collapse; font: 14px system-ui; }
88
+ td, th { border: 1px solid #b9a96a; padding: 4px 8px; }
89
+ </style>
90
+ <table>
91
+ <tr><th>Before</th><th>After</th></tr>
92
+ <tr><td>List read at start, often empty</td><td>List read after the first reply</td></tr>
93
+ </table>
94
+ <button id="replay">Replay the race</button> <span id="out"></span>
95
+ <script>
96
+ root.querySelector('#replay').onclick = () => { root.querySelector('#out').textContent = 'reply first, then the list' }
97
+ </script>
98
+ ```
99
+
100
+ </details>
101
+ EOF
102
+ )"
103
+ ````
39
104
 
40
105
  ## Step 1. Open the todo
41
106
 
@@ -45,26 +110,80 @@ export DO_IT_AGENT=conductor
45
110
  ARG='<the todo file from the arguments, empty for a seed request>'
46
111
  TODO=$(cd "$(dirname "${ARG:-TODO.md}")" && pwd)/$(basename "${ARG:-TODO.md}")
47
112
  SLUG=$(printf '%s' "$TODO" | shasum | cut -c1-10)
48
- STATE=${DO_IT_HOME:-$HOME/.do-it}/runs/$SLUG # inbox.md, tests.md, plans/, logs/, state.json
49
- mkdir -p "$STATE/plans" "$STATE/logs"
113
+ STATE=${DO_IT_HOME:-$HOME/.do-it}/runs/$SLUG # inbox.md, tests.md, plans/, answers/, reviews/, logs/, state.json, models.json
114
+ mkdir -p "$STATE/plans" "$STATE/answers" "$STATE/reviews" "$STATE/logs"
115
+ ```
116
+
117
+ Find out where this session runs, once. It decides how workers start (Step 4) and needs no app to be installed:
118
+
119
+ ```bash
120
+ detect_harness() {
121
+ if [ "${HERDR_ENV:-}" = 1 ] && command -v herdr >/dev/null; then echo herdr; return; fi
122
+ if [ -n "${ORCA_TERMINAL_HANDLE:-}${ORCA_WORKTREE_ID:-}" ] && command -v orca >/dev/null; then echo orca; return; fi
123
+ if [ -n "${SUPER_ENGINEERING_ENV:-}${SUPER_ENGINEERING_WORKTREE_PATH:-}${SUPERCONDUCTOR_WORKTREE_PATH:-}" ] &&
124
+ command -v sc >/dev/null && sc instance current --json >/dev/null 2>&1; then echo sc; return; fi # super.engineering, formerly Superconductor
125
+ if command -v t3 >/dev/null; then
126
+ if [ -n "${T3CODE_PROJECT_ROOT:-}${T3CODE_WORKTREE_PATH:-}" ]; then echo t3code; return; fi
127
+ pid=$PPID # T3 Code does not mark its agent sessions yet, so look for it among the parent processes
128
+ for _ in 1 2 3 4 5 6 7 8; do
129
+ case "$pid" in ''|0|1) break ;; esac
130
+ case "$(ps -o comm= -p "$pid" | tr '[:upper:]' '[:lower:]')" in *t3code*|*"t3 code"*) echo t3code; return ;; esac
131
+ pid=$(ps -o ppid= -p "$pid" | tr -d ' ')
132
+ done
133
+ fi
134
+ echo plain
135
+ }
136
+ detect_harness > "$STATE/harness"; cat "$STATE/harness" # later Bash calls: HARNESS=$(cat "$STATE/harness")
50
137
  ```
51
138
 
52
- Open it for the person. It starts or reuses the daemon, creates the file from a template when missing, opens the browser, and returns at once:
139
+ `herdr`, `orca`, `sc` (super.engineering), and `t3code` start workers as sessions in that app; `plain` (any other terminal) uses Claude Code subagents, which need nothing beyond Claude Code.
140
+
141
+ Find out once which models you can reach beyond Claude Code's own `opus` and `sonnet`. Only L tasks use them (planning, review, and the hard subtasks). Look in two places: the Agent tool's list of agent types and their descriptions, for an agent type whose description names a model stronger than Opus; and PATH, for a CLI that runs another frontier model non interactively. Run `<cli> --help` once for any CLI you find, and store the full non interactive command (read only for planning and review), so later steps and the worker brief's HARD PARTS can paste it. Write what you found to `$STATE/models.json`, for example `{"planner": "agent <type>", "reviewer": null, "hard_parts": "cli <command>"}`, with `null` for anything you did not find. Use only what is there; never assume an agent type or CLI exists. Everything not found falls back to Opus.
142
+
143
+ Open it for the person. It starts or reuses the daemon, creates the file from a template when missing, opens the browser, and returns at once. Inside Sheprd (Herdr GPUI) the todo opens in a split beside this conversation, so the person sees both:
53
144
 
54
145
  ```bash
55
- if [ "${HERDR_ENV:-}" = 1 ] && [ -x /Applications/Sheprd.app/Contents/MacOS/sheprd ]; then
56
- DO_IT_BROWSER="/Applications/Sheprd.app/Contents/MacOS/sheprd browser open" do-it open "$TODO"
146
+ SHEPRD=
147
+ for app in /Applications/Sheprd.app/Contents/MacOS/sheprd /Applications/Herdr.app/Contents/MacOS/Herdr; do
148
+ [ -x "$app" ] && { SHEPRD=$app; break; }
149
+ done
150
+ if [ "${HERDR_ENV:-}" = 1 ] && [ -n "$SHEPRD" ]; then
151
+ DO_IT_BROWSER="$SHEPRD browser open --beside --no-focus" do-it open "$TODO" # a split next to this pane, keyboard stays here
152
+ elif [ "$(cat "$STATE/harness")" = sc ]; then
153
+ # the workspace's browser split, which never moves focus; the system browser when browser automation is off or denied
154
+ DO_IT_BROWSER='f() { sc browser open "$1" --split >/dev/null 2>&1 || open "$1"; }; f' do-it open "$TODO"
57
155
  else
58
156
  do-it open "$TODO"
59
157
  fi
60
158
  do-it read "$TODO"
61
159
  ```
62
160
 
63
- Tell the person in one line that the todo is open and that they can add tasks there. Create the two agent channels with your Write tool if missing (nobody has them open yet): `$STATE/inbox.md` (`# Inbox`, `## Messages`) and `$STATE/tests.md` (`# Tests`, `## Queue`). If `$STATE/state.json` exists, this is a resume: reconcile it with what still runs (Herdr: `herdr agent list`, `herdr worktree list --json`; otherwise the worktrees in `git worktree list`) and only dispatch tasks that have no live worker and are not delivered.
161
+ This is the only `do-it open` of the run, and on a resume (Step 1a) skip it when the person already has the todo open. Opening it again reloads and shows the split, which pulls the person away from what they are doing: never run `do-it open`, `sheprd browser open`, `sheprd browser reload`, or any `focus` command on the todo later, not after a daemon restart, not to check a change, not to show a result. When the editor needs a reload (after `do-it stop`), write that in chat and let the person do it.
162
+
163
+ Tell the person in one line that the todo is open and that they can add tasks there. Create the two agent channels with your Write tool if missing (nobody has them open yet): `$STATE/inbox.md` (`# Inbox`, `## Messages`) and `$STATE/tests.md` (`# Tests`, `## Queue`). If `$STATE/state.json` exists, this is a resume: do Step 1a, which ends with the Step 2 watches armed, then go on with Step 5 events.
164
+
165
+ When `DO_IT_HOME` or `DO_IT_PORT` is set in your environment, every agent you start must use the same daemon. Add to every worker, tester, messenger, and Q brief the line `ENV: run export DO_IT_HOME=<value> DO_IT_PORT=<value> in the same Bash call before every do-it command` (shell variables do not survive between Bash calls), and pass both as `--env KEY=VALUE` to `herdr tab create`. A worker that misses them talks to another daemon about the same files.
166
+
167
+ ## Step 1a. Resume
168
+
169
+ A conductor that stopped (a crash, a closed tab, a new session) leaves its workers, tester, and messenger running, and events kept arriving while nobody watched. Resuming is catching up, then conducting as usual: it is never done by one pass.
170
+
171
+ 1. **Make sure no conductor still runs.** Only one conductor runs per todo. List the watches with `pgrep -fl "do-it watch"` and keep those naming this run's todo or `$STATE` with `--as conductor`. For each, walk up its parents (`ps -o ppid= -p PID`, then `ps -o comm= -p PPID`): when one is a live `claude` process other than your own session, another conductor still runs, so do not resume: tell the person in chat and stop. Otherwise these watches are orphans of the stopped conductor: kill them. Never touch the tester's or messenger's watches, or another run's.
172
+ 2. **Find what still runs.** Match each task by the worktree path and branch saved in `state.json`, and use the agent name only as a cross check (another run in the same repo can have its own `do-tN`). Herdr: `herdr agent list` (cwd and name), `herdr worktree list --json`; Orca: `orca worktree list --json`, `orca terminal list --json`; super.engineering: `sc agents list --worktree <path> --output json` for each saved worktree; T3 Code: `t3 thread list`; plain: `git worktree list` (subagents do not survive their conductor, so every plain worker is gone). Reuse the tester and messenger saved in `state.json` while they run; start new ones only when they are gone.
173
+ 3. **Read what you missed.** `do-it read` the todo, the inbox, and `tests.md` whole (not a watch: a watch only shows what comes next). Compare with `state.json`: inbox lines after `versions.inbox` (all of them when it is missing), answers in `tests.md`, and the person's edits in the todo since `versions.todo` (new tasks, notes under tasks, answers to questions, a checked `Review this task`).
174
+ 4. **Act on each task**, by its `state.json` status and what you found:
175
+ - `delivered`: nothing. Never re-dispatch it, re-check it, or rewrite its status line.
176
+ - a worker whose `done` line is in the inbox but who is not `delivered`: verify and deliver it now (Step 5).
177
+ - a live worker without `done`: keep it, send it any note the person wrote while you were away (`From the TODO: ...`), and never start a second worker on that task.
178
+ - a worker that is gone without `done`: its worktree and branch still hold its work, so start a new worker in that same worktree with its brief plus `RESUMED: continue from the commits on your branch`, and never create a second worktree for it (when the saved worktree is missing or was never saved, dispatch it fresh, Step 4). Herdr: `herdr worktree open --no-focus`, then put focus back where it was only if it moved (as in Step 4), then start `do-tN` in its root pane; Orca: a new terminal in the saved worktree id; super.engineering: `sc layout run tabs --worktree <saved path> --open-if-needed --active keep` as in Step 4; T3 Code: `t3 thread send` to the saved thread; plain: `Agent` without `isolation`, with `CWD: <saved worktree>` in the brief and `cd` there in every Bash call.
179
+ - `queued`: dispatch it in tag order as workers free up, with any note the person wrote under it in the brief.
180
+ - a task line with `@started` and a `**tN**` status line but no `state.json` entry: look for its worker before treating it as new: a worktree whose branch or label names the task, or an agent whose brief or cwd points at this `$STATE`; when nothing matches for sure, ask the person in chat before dispatching it; with `@started` and no status line, triage it (Step 3) and keep the stamp.
181
+ - any other status (`review`, `listed`, `waiting for you`, `stopped`): apply the Step 5 row for what changed in the todo since `versions.todo`, or nothing when nothing did.
182
+ 5. **Arm the watches** that apply (Step 2) with `--since` the versions you just read, save those versions in `state.json`, and keep conducting. Never end the turn after the catch up without the watches running.
64
183
 
65
184
  ## Step 1b. Seed from a request
66
185
 
67
- Only when the arguments were a seed request. Do the request yourself, read only (or with one read only `Explore` agent): fetch, search, list. Change nothing, message nobody, start no worker. Then write the result into `## Tasks` as one task per item, so the person can act on each one:
186
+ Only when the arguments were a seed request. Hand the request to one `general-purpose` agent with a read only brief (it may write only its result file): it fetches, searches, and lists, changes nothing, messages nobody, writes the finished block below to `$STATE/seed.md`, and returns only `SEED: <path>`. Start no worker. Then append that file into `## Tasks` yourself (`do-it append "$TODO" --version $V --section tasks - < "$STATE/seed.md"`; the messenger does not exist yet), as one task per item, so the person can act on each one:
68
187
 
69
188
  ```markdown
70
189
  - [x] <the request, as they wrote it>
@@ -86,53 +205,76 @@ Only when the arguments were a seed request. Do the request yourself, read only
86
205
  Start each watch with the Monitor tool; every printed line is an event:
87
206
 
88
207
  ```bash
89
- do-it watch "$TODO" --as conductor --settle 25 # one line once the person stopped typing for 25 s
208
+ do-it watch "$TODO" --as conductor --settle 25 # one line 25 s after the person's last change, 2 s after Enter adds a line
90
209
  do-it watch "$STATE/inbox.md" --as conductor --section messages
91
- do-it watch "$STATE/tests.md" --as conductor --todos # outside Herdr only: when to start the tester
210
+ do-it watch "$STATE/tests.md" --as conductor --todos # plain and t3code: when to start or wake the tester
92
211
  ```
93
212
 
94
- Use `--quiet` to skip the initial `Watching PATH at version N` line instead of filtering it with grep. A filter must be line buffered, or lines arrive late. `Settled at version N by the user` means the person changed the todo and paused. Then `do-it read "$TODO"` once and compare it with your picture of the file. Never act on a half typed line. `Missed changes, now at version N: run do-it read` means the watch history was forgotten, so read the current todo before acting. `Daemon restarted, now version N` needs nothing but a fresh read. When re-arming a watch, pass `--since` the last version you have read, not the original one. Exit 9 means the todo was deleted or moved: stop and report in chat.
213
+ Run every watch that applies (the `tests.md` one only in plain and t3code) for the whole run, and never end a turn without them: an event that lands while a watch is down is seen only by the next full read. A Monitor expires after its `timeout_ms` (at most 30 minutes): set the maximum, and on expiry re-arm the same watch with `--since` the last version you read. Stop a watch (TaskStop) before you start its replacement, so one file never has two conductor watches. Keep the watch unfiltered or filter for every event you act on (`done`, `question`, `blocked`, `failed`, `progress`, `subtask`), not only for one task.
214
+
215
+ Use `--quiet` to skip the initial `Watching PATH at version N` line instead of filtering it with grep. A filter must be line buffered, or lines arrive late. `Settled at version N by the user` means the person changed the todo and paused, or pressed Enter for a new line (`--settle-line`, 2 s by default; edits inside existing lines wait the full 25 s). Then `do-it read "$TODO"` once and compare it with your picture of the file. Never act on a half typed line. `Missed changes, now at version N: run do-it read` means the watch history was forgotten, so read the current todo before acting. `Daemon restarted, now version N` needs nothing but a fresh read. When re-arming a watch, pass `--since` the last version you have read, not the original one. Exit 9 means the todo was deleted or moved: stop and report in chat.
95
216
 
96
217
  ## Step 3. Triage each new task
97
218
 
98
- A task is any `- [ ]` line (or plain non empty line under `## Tasks`) that has no `**tN**` status line under it and is not a `listed` item from Step 1b. A `- **Name**` bullet without a checkbox is a group label, never a task. An empty `- [ ]` line is the person's typing spot (the new file template has one): leave it alone. Give it the next id `tN` and size it from its text and a quick look at the code it names (delegate a search to `Explore` when unsure, keep only the conclusion):
219
+ A task is any `- [ ]` line (or plain non empty line under `## Tasks`) that has no `**tN**` status line under it, is not already in `state.json`, is not an indented `- [ ]` line under a task whose `state.json` entry is L (those are its subtasks, the person's own additions included), and is not a `listed` item from Step 1b. A `- **Name**` bullet without a checkbox is a group label, never a task. An empty `- [ ]` line is the person's typing spot (the new file template has one): leave it alone. The template's `## Example` samples fall out of these rules (open ones carry a `**t0**` status line, the rest are resolved); real ids start at t1.
220
+
221
+ **Start it first.** The moment you take a task, before sizing it, run `todo start` on it, queued tasks included, so the person sees at once that it was picked up:
222
+
223
+ ```bash
224
+ do-it todo start "$TODO" --version $V --section tasks -- "<the task text>"
225
+ ```
226
+
227
+ Then give it the next id `tN` and size it from its text. Do not read the code it names yourself: when the text alone cannot size it, ask one read only `Explore` agent and keep only its conclusion.
99
228
 
100
229
  | Size | Looks like | Planner | Worker |
101
230
  | --- | --- | --- | --- |
102
- | S | one file or setting, obvious change, no design choice | `fable-advisor`, short plan | one worker |
103
- | M | a feature or fix in one area, a few files, needs tests | `fable-advisor` | one worker |
104
- | L | crosses packages or services, protocol or data migration, concurrency, security, unclear root cause, or the person calls it big | GPT-6 Astra at `xhigh`, then one `fable-advisor` pass over that plan | one worker, Astra for the hard pieces |
105
- | Q | a question, research, or a decision, no code | none | none: answer it yourself or with one read only `Explore` agent, and write the answer under the task |
231
+ | S | one file or setting, obvious change, no design choice | Opus, short plan | one Sonnet worker |
232
+ | M | a feature or fix in one area, a few files, needs tests | Opus | one Opus worker |
233
+ | L | crosses packages or services, protocol or data migration, concurrency, security, unclear root cause, or the person calls it big | the stronger planner from `models.json`, else Opus; its plan ends in subtasks (below) | one Opus worker, with the stronger model from `models.json` for the hard subtasks when there is one |
234
+ | Q | a question, research, or a decision, no code | none | one `general-purpose` agent in the background with a read only brief (it may write only its answer file) that writes its answer to `$STATE/answers/tN.md` and returns only `ANSWER: <path>`; never answer it yourself. The answer file goes under the task (Step 5) |
235
+
236
+ Reviews (Step 5) use Opus; an L review uses the stronger reviewer from `models.json` when there is one. The tester and the messenger run on Sonnet.
106
237
 
107
238
  Repo: the one containing the todo, unless the task names another. If you cannot tell, ask under the task instead of guessing.
108
239
 
109
- Write the status line at once, then dispatch while fewer than 3 workers are active (otherwise status `queued`, dispatched in todo order as workers finish):
240
+ Then write the status line, and dispatch while fewer than 3 workers are active (otherwise status `queued`, dispatched in the order of the Tags section as workers finish). An L task is planned at once but dispatched (or queued) only after its review (below). Without a messenger you write it:
110
241
 
111
242
  ```bash
112
243
  do-it edit "$TODO" --version $V --section tasks \
113
244
  --old "<the exact task line>" \
114
245
  --new "<the exact task line>
115
- - **t3** M, planning with Fable"
246
+ - **t3** M, planning with Opus"
116
247
  ```
117
248
 
118
- Immediately after writing the status line, start the task with the version returned by that edit:
249
+ With a messenger (Step 4) you only append `- conductor t3 status: M, planning with Opus` to the inbox and it writes the line. Everywhere below, **write under the task** means exactly this: yourself without a messenger, through a `conductor` inbox line with one.
119
250
 
120
- ```bash
121
- $D todo start "$TODO" --version $V --section tasks -- "<exact task text>"
251
+ **L tasks become subtasks, and the person reviews them first.** No worker starts on an L task until the person agrees with its split. In every transport, plan it right away yourself with a planner agent, as Step 4 plain item 1 does (session workers get the plan in their brief), and ask the planner to end the plan with its subtasks, in order, one line each. Save the plan to `$STATE/plans/tN.md` and the subtask lines to `$STATE/plans/tN-subtasks.md`, the first one always `Review this task`. Record the subtasks in `state.json` under the task with status `review` first, then write them under the task as indented `- [ ]` lines, after its status line (with a messenger: `- conductor tN subtasks: <path>`), and set the status:
252
+
253
+ ```markdown
254
+ - [ ] Move the sync protocol to CRDT updates @started(26-11-05 14:02)
255
+ - **t7** L, waiting for your review: check off Review this task to start
256
+ - [ ] Review this task
257
+ - [ ] Add an update message to the protocol schema
258
+ - [ ] Send updates from the daemon instead of snapshots
259
+ - [ ] Apply updates in the web client
122
260
  ```
123
261
 
124
- Never rewrite the person's own task text. Your lines are indented sub bullets starting with `**tN**`; there is exactly one status line per task, which you replace as the task moves, plus any `**tN question:**` lines. Record every task in `$STATE/state.json` (id, text, size, repo, branch, worktree, agent id or name, status) after every transition; it is how you resume.
262
+ Until the person checks off `Review this task`, the task waits and nothing is dispatched. They may edit, add, or delete subtasks in the editor first: the subtask lines as they read when the review is checked are the plan the worker gets. A note under the task asking for a different split goes to the planner with its plan; its new list replaces the unchecked subtasks the same way. Once the review is checked, dispatch one worker for the whole task, with the subtasks in order (Step 5). Subtask texts can repeat across tasks: target a subtask by its text only when it is unique, otherwise by the number a fresh `do-it todo list` shows.
263
+
264
+ Never rewrite the person's own task text. Your lines are indented sub bullets starting with `**tN**`; there is exactly one status line per task, which you replace as the task moves, plus any `**tN question:**` lines. Record every task in `$STATE/state.json` (id, text, size, repo, branch, worktree path, agent id or name and pane or handle, status, and for L its subtasks) before its first status line and after every transition; it is how you resume (Step 1a), and how the messenger finds the task for a `tN`. Keep there too the tester's and messenger's names and panes (`"agents": {"tester": {"name": ..., "pane": ...}, "messenger": {...}}`), and `"versions": {"todo": N, "inbox": N, "tests": N}`, the last version of each you read and acted on, updated after every event you handle. Write the file whole with your Write tool (it is yours alone), not with `sed`.
125
265
 
126
266
  ## Step 4. Deliver
127
267
 
128
- The roles are the same in both transports:
268
+ The roles are the same in every transport; `HARNESS` from Step 1 picks the transport below:
129
269
 
130
270
  | Role | Who | Count | Writes code | Runs builds or tests |
131
271
  | --- | --- | --- | --- | --- |
132
- | Conductor | this session | 1 | no | no |
133
- | Planner | `fable-advisor` (S, M) or GPT-6 Astra (L) | per task | no | no |
134
- | Worker | one agent per task, in its own worktree, named `tN` | at most 3 at once | yes | **no** |
135
- | Tester | one agent | **exactly 1** | no | **yes, the only one** |
272
+ | Conductor | this session: sizes, dispatches, monitors, sets stamps | 1 | no | no |
273
+ | Planner | a read only agent: Opus (S, M), the stronger planner from `models.json` or Opus (L) | per task | no | no |
274
+ | Reviewer | a read only agent: Opus (S, M), the stronger reviewer from `models.json` or Opus (L) | per task | no | no |
275
+ | Worker | one agent per task, in its own worktree, named `tN`: Sonnet (S), Opus (M, L) | at most 3 at once | yes | **no** |
276
+ | Tester | one Sonnet agent | **exactly 1** | no | **yes, the only one** |
277
+ | Messenger | one Sonnet agent, named `messenger` (optional, see below) | 0 or 1 | no | no |
136
278
 
137
279
  The single tester is the compute budget. Nobody else runs a compiler, test suite, linter, type checker, dev server, or browser. Formatters are the exception. Workers queue a test request and wait:
138
280
 
@@ -142,24 +284,44 @@ do-it todo add "$STATE/tests.md" --version <v> --section queue --as tN \
142
284
  do-it diff "$STATE/tests.md" --since <v> --wait 100 # loop on exit 4; read the answer under your request
143
285
  ```
144
286
 
145
- ### Outside Herdr: Claude Code subagents
287
+ **The messenger** is optional: one agent that owns every `**tN**` line in the todo (status, `**tN question:**` lines, results, Q answers) and the subtask lines of L tasks, so you only run `todo start`, `todo check`, and `todo cancel` there. Turn it on in the session transports from the first task (it costs one cheap tab), and in `plain` once a second task is active or a Q task appears. Once on it stays on: set `"messenger": true` in `state.json`, write the current inbox version to `$STATE/messenger.version`, and from then on never write a `**tN**` line yourself, even between its runs. Nothing written before needs replaying.
288
+
289
+ Its only feed is the inbox, in order. Workers already append their `progress`, `question`, `blocked`, and `done` lines there; you append your decisions as `conductor` lines:
290
+
291
+ ```
292
+ - conductor t3 status: planned by Opus: one parser for both formats
293
+ - conductor t7 subtasks: <STATE>/plans/t7-subtasks.md
294
+ - conductor t3 answered (the person answered: remove the question line)
295
+ - conductor t5 answer: <STATE>/answers/t5.md
296
+ - conductor t3 delivered: branch `fix-sidebar-ports` (2 commits, a1b2c3d), tests t3r2 passed, review: ship
297
+ ```
298
+
299
+ Run exactly one messenger. It writes worker progress and questions into the todo directly, but `delivered` only from your `conductor` line, never from a worker's `done`. Your `todo check` may land a few seconds before its delivered line; that is fine.
146
300
 
147
- Subagents cannot start subagents and cannot be prompted while they run, so you call every agent yourself, always with `run_in_background: true` so watch events keep arriving.
301
+ ### Any other terminal (`HARNESS=plain`): Claude Code subagents
148
302
 
149
- 1. **Plan.** S and M: `Agent(subagent_type: "fable-advisor")` with the task, the repo, and what triage found; ask for a plan in under 300 words. L: `Agent(subagent_type: "astra-implementer")` with a brief that forbids edits and asks only for a plan at effort `xhigh`, then one `fable-advisor` pass over it (when `astra-implementer` is not among your agent types or reports the codex CLI unavailable, plan L tasks with `fable-advisor` and say so in the status line). Save the plan to `$STATE/plans/tN.md` and set the status line to `**tN** planned by <Fable or Astra>: <summary in a few words>`.
150
- 2. **Build.** `Agent(subagent_type: "general-purpose", isolation: "worktree", run_in_background: true)` with the worker brief below. Keep the agent id in `state.json`.
151
- 3. **Test.** When the `tests.md` watch shows an open request and no tester runs, start one: `Agent(subagent_type: "general-purpose", run_in_background: true)` with the tester brief. It drains the queue one request at a time, oldest first, and exits; start it again for the next requests.
152
- 4. **Questions.** A worker that needs the person appends a `question` to the inbox and ends its run with `QUESTION: ...`. Write it under the task (` - **tN question:** ...`, status `waiting for you`). When the person answers under it, resume that same worker with `SendMessage` to its agent id: `From the TODO: <their answer>`.
153
- 5. **Review.** When a worker ends with `DONE`, verify (below), then run `fable-advisor` on the branch diff against the task. `ship`: delivered. `fix-first`: resume the worker with the findings.
303
+ This needs nothing but Claude Code: `isolation: "worktree"` makes each worker's worktree. Subagents cannot start subagents and cannot be prompted while they run, so you call every agent yourself, always with `run_in_background: true` so watch events keep arriving.
304
+
305
+ 1. **Plan.** S and M: `Agent(subagent_type: "Plan", model: "opus", run_in_background: true)` with the task, the repo, and what triage found; ask for a plan in under 300 words (S: under 100). L: the stronger planner from `models.json` with a brief that forbids edits and asks only for a plan ending in subtasks: an agent type is called the same way; a CLI is run by a `general-purpose` agent that runs it read only with that brief and returns its plan unchanged. With neither, plan L with Opus and say so in the status line. Save the plan it returns to `$STATE/plans/tN.md` as it is (do not rework it) and write under the task `**tN** planned by <Opus or the planner's model>: <summary in a few words>` (L: the subtasks and the review wait, Step 3).
306
+ 2. **Build.** `Agent(subagent_type: "general-purpose", model: "sonnet" for S or "opus" for M and L, isolation: "worktree", run_in_background: true)` with the worker brief below. Keep the agent id in `state.json`. A plain worker cannot start agents, so for the hard subtasks of an L task it can use only a stronger model's CLI from `models.json`, named in its brief.
307
+ 3. **Test.** When the `tests.md` watch shows an open request and no tester runs, start one: `Agent(subagent_type: "general-purpose", model: "sonnet", run_in_background: true)` with the tester brief. It drains the queue one request at a time, oldest first, and exits; start it again for the next requests.
308
+ 4. **Questions.** A worker that needs the person appends a `question` to the inbox and ends its run with `QUESTION: ...`. Write it under the task (` - **tN question:** ...`, status `waiting for you`; the messenger does both from the worker's inbox line). When the person answers under it, resume that same worker with `SendMessage` to its agent id: `From the TODO: <their answer>`.
309
+ 5. **Review.** When a worker ends with `DONE`, verify (below, which also saves the diff to `$STATE/reviews/tN.diff`), then run the reviewer (`Agent(subagent_type: "general-purpose", model: "opus")` with a read only brief; for L the stronger reviewer from `models.json` when there is one) with the task, `$STATE/plans/tN.md`, that diff file, and `$STATE/tests.md`. Pass paths, not pasted text, and ask for `ship` or `fix-first` with findings. `ship`: delivered. `fix-first`: resume the worker with the findings.
310
+ 6. **Messenger.** When it is on and new inbox lines arrive while no messenger runs (the inbox watch skips your own lines, so also right after you append a `conductor` line), start one: `Agent(subagent_type: "general-purpose", model: "sonnet", run_in_background: true)` with the messenger brief. It writes everything since `$STATE/messenger.version` and ends with `INBOX DRAINED`. Lines that arrive while it runs wait for one restart after it ends; never run two.
154
311
 
155
312
  Worker brief:
156
313
 
157
314
  ```
158
315
  TASK tN (size S|M|L): <the person's task line, verbatim, plus their sub notes>
159
316
  REPO: <repo root>. You run in your own git worktree on your own branch; commit there.
160
- PLAN: <the plan from $STATE/plans/tN.md>
317
+ PLAN: <the plan from $STATE/plans/tN.md; for S and M in a session transport: none, plan it yourself>
318
+ SUBTASKS (L only): <the subtask lines as the person left them, without Review this task>. Work them
319
+ in order. When you begin one, append "- tN subtask started: <its text>" to the inbox; when its
320
+ commits are in, "- tN subtask done: <its text>". HARD PARTS: <the hard_parts command from models.json, or none>.
161
321
  NAME: export DO_IT_AGENT=tN before any do-it command.
162
- TASK TARGET: keep the person's task text verbatim. For todo start and todo check, target that exact text after --, never a remembered task number. If the text is unavailable, run do-it todo list immediately before choosing a target.
322
+ SCREEN: never open, reload, select, or focus anything on the person's screen: no do-it open, no
323
+ browser, tab, pane, worktree, or workspace command of Sheprd, Herdr, Orca, T3 Code, or sc that
324
+ opens, selects, activates, or focuses something, no new browser windows.
163
325
  COMPUTE RULE: never run builds, tests, linters, type checkers, dev servers, or browsers yourself.
164
326
  Formatters are fine. To test, queue one request and wait for the answer:
165
327
  do-it todo add <STATE>/tests.md --version <v> --section queue "tNrK tN: <command> in <your worktree>"
@@ -169,6 +331,9 @@ PROGRESS: at real milestones only, append to <STATE>/inbox.md section messages:
169
331
  do-it append <STATE>/inbox.md --version <v> --section messages -- "- tN progress: <one line>"
170
332
  QUESTIONS: when the person must decide, append "- tN question: <question>" there, then end your
171
333
  run with "QUESTION: <question>". You will be resumed with the answer.
334
+ EXPLAIN: before DONE, write <STATE>/explain/tN.md for the person: one folded section in the skill's
335
+ "Folded sections and HTML" format (<details id="tN-explain">, indented two spaces) saying what
336
+ changed and why, with an html do-it fence where a table or diagram explains it better.
172
337
  DONE: commits on your branch, the final test request PASSED. End with
173
338
  "DONE: branch <name>, worktree <path>, commits <shas>, tests <request ids>".
174
339
  Do not push, open a PR, or merge unless the task line asks for it in words. Never edit the todo file.
@@ -186,29 +351,150 @@ run exactly that command in that path with output to <STATE>/logs/rN.log, then u
186
351
  or FAIL in 1m05s, log <path>: <the first error, at most 15 lines, and the cause in one sentence>
187
352
  and check the request off (do-it todo check). Never edit code, never commit, never fix failures.
188
353
  If a command would run longer than 30 minutes or needs a desktop you do not have, answer BLOCKED
189
- with the reason. When no open request is left, end your run with "QUEUE EMPTY".
354
+ with the reason. Drive browsers headless only.
355
+ SCREEN: never open, reload, select, or focus anything on the person's screen: no do-it open, no
356
+ browser, tab, pane, worktree, or workspace command of Sheprd, Herdr, Orca, T3 Code, or sc that
357
+ opens, selects, activates, or focuses something, no new browser windows.
358
+ When no open request is left, end your run with "QUEUE EMPTY".
359
+ ```
360
+
361
+ Messenger brief:
362
+
190
363
  ```
364
+ SCREEN: never open, reload, select, or focus anything on the person's screen: no do-it open, no
365
+ browser, tab, pane, worktree, or workspace command of Sheprd, Herdr, Orca, T3 Code, or sc that
366
+ opens, selects, activates, or focuses something, no new browser windows.
367
+ You write the person's todo for the conductor. export DO_IT_AGENT=messenger. TODO=<todo path>,
368
+ INBOX=<STATE>/inbox.md (section messages), CURSOR=<STATE>/messenger.version, and
369
+ STATE=<STATE>/state.json, where each task's entry gives the task text for its tN. Your input is every
370
+ inbox line added after the version in CURSOR, in order (do-it diff <INBOX> --since <cursor>; on
371
+ "no longer kept", do-it read it and take the lines you have not written yet):
372
+ "tN progress: x" status line of tN becomes "**tN** x" (a few words)
373
+ "tN question: q" add " - **tN question:** q" under tN, status "waiting for you"
374
+ "tN blocked: x", "tN failed: x", "tN done", "tN subtask started: x", "tN subtask done: x"
375
+ nothing: the conductor decides
376
+ "conductor tN status: x" status line of tN becomes "**tN** x"
377
+ "conductor tN answered" remove the "**tN question:**" line
378
+ "conductor tN answer: path" status "**tN** answered", the file's lines as sub bullets under it
379
+ "conductor tN delivered: x" status line of tN becomes "**tN** delivered: x"
380
+ "conductor tN explain: path" the file's folded section goes right after tN's status line (and its
381
+ question lines); one with the same id already under tN is replaced whole,
382
+ from its "<details" line through its "</details>" line
383
+ "conductor tN subtasks: path" only while tN has no "Review this task" line or it is unchecked
384
+ (otherwise skip the line): replace tN's unchecked subtasks with the file's lines, as indented
385
+ "- [ ] " lines after its status line (the only task lines you write)
386
+ Each task has exactly one "**tN**" status line, an indented sub bullet right under the task (the
387
+ line whose text is the state.json entry for tN), which you add when missing and otherwise replace
388
+ in place; the last line wins. Read the todo before each write, skip a question or
389
+ answer that is already there, and change only your "**tN**" lines and the folded sections you add, with do-it edit --section tasks
390
+ naming the version. Never touch the person's text, their task lines, checkboxes, or @ tags, never put @
391
+ words in a line, and never use dash separators. Once every line up to the inbox version you read
392
+ is written, save that version to CURSOR, then look again. When no line is left, end your run with
393
+ "INBOX DRAINED".
394
+ ```
395
+
396
+ ### Session workers (Herdr, Orca, T3 Code, super.engineering)
191
397
 
192
- ### Inside Herdr (`HERDR_ENV=1`): worktrees and tabs
398
+ In these apps every worker is a full Claude session in its own worktree, not a subagent, so the person sees each task in the app and it can call its own subagents. Every worker, tester, and messenger starts in the background: the person stays on the todo and the conversation, and opens a task's space only when they choose to. Never activate, focus, or reveal what you create. Its brief is the worker brief above with `CWD: <worktree> BRANCH: <branch> BASE: <base branch> REPO RULES: read CLAUDE.md/AGENTS.md` in place of the REPO line (`CWD: the worktree you start in` when the app makes the worktree), plus:
193
399
 
194
- The same roles as herdrdocwatch, with `do-it` commands in place of Herdr's `doc` commands. Load the [[herdr]] skill for the CLI; never split your own pane.
400
+ ```
401
+ PLAN AND REVIEW: S and M: plan with an Opus planner before you edit. L: the plan and the subtasks are
402
+ given; use the stronger model named in HARD PARTS for the hard subtasks when there is one. Get a
403
+ review of your branch (Opus; for L the stronger reviewer from models.json when there is one) before DONE.
404
+ CONDUCTOR: talk to the conductor only through the inbox. Answers arrive as prompts starting "From the TODO".
405
+ After a question, wait for that prompt instead of ending your session.
406
+ DONE (in place of the worker brief's DONE): commits on your branch, the final test request PASSED. Append
407
+ "- tN done: branch <name>, worktree <path>, commits <shas>, tests <request ids>" to the inbox.
408
+ ```
409
+
410
+ A session worker's last message stays in its own session, which the conductor does not read, so its `done` line in the inbox is the only delivery signal, and the one a resumed conductor finds (Step 1a).
411
+
412
+ ### Inside Herdr (`HARNESS=herdr`): worktrees and tabs
413
+
414
+ Run `herdr --help` once for the CLI; never split your own pane.
195
415
 
196
416
  - **Tester**: one tab in your workspace, started once, watching the queue itself:
197
417
  ```bash
198
418
  TAB=$(herdr tab create --workspace "$HERDR_WORKSPACE_ID" --cwd "$STATE" --label tester --no-focus)
199
419
  PANE=$(jq -r .result.root_pane.pane_id <<<"$TAB")
200
- herdr agent start do-tester --kind claude --pane "$PANE" -- --model claude-sonnet-5 --effort high --dangerously-skip-permissions
420
+ herdr agent start do-tester --kind claude --pane "$PANE" -- --model sonnet --effort high --dangerously-skip-permissions
201
421
  herdr agent prompt do-tester "$TESTER_BRIEF"
202
422
  ```
203
423
  Use the tester brief above, but instead of ending on an empty queue it keeps watching with `do-it watch <TESTS> --todos --as tester` (Monitor tool). Check `herdr agent list` first: reuse a live `do-tester` only when its cwd is this `$STATE`; on `agent_name_taken` pick `do-<SLUG first 4>-tester`.
204
- - **Worker per task**: a Herdr worktree and space (see [[herdrworktree]], `--no-focus`), then a Claude architect in its root pane named `do-tN` (`claude-opus-5-5[1m]`, effort high, xhigh for L) that follows [[orchestration]]: it plans with `fable-advisor` (S, M) or a read only Astra tab (L), routes the typing to Codex lanes in herdr tabs, and gets a `fable-advisor` review before reporting done. Its brief is the worker brief above with `CWD: <worktree> BRANCH: <branch> BASE: <base branch> REPO RULES: read CLAUDE.md/AGENTS.md` in place of the REPO line, plus: "Talk to the conductor only through the inbox; answers arrive as prompts starting From the TODO. Wait for lanes with `herdr agent wait <lane> --timeout 1800000`, never by grepping a screen." Start and brief it as herdrdocwatch does:
424
+ - **Messenger**: the same way, a second tab labelled `messenger` with an agent `do-messenger` (`--model sonnet --effort medium`) and the messenger brief, except that instead of ending on a drained inbox it keeps watching with `do-it watch <INBOX> --section messages --as messenger` (Monitor tool). The same reuse and name rules apply.
425
+ - **Worker per task**: a Herdr worktree and space in the background (a branch named after the task, based on the repo's integration branch, under `.claude/worktrees/`), then Claude in its root pane named `do-tN` (`$MODEL`: `sonnet` for S, `opus` for M and L; `$EFFORT`: `high`, `xhigh` for L) with the session worker brief above. Create, start, and brief it without ever showing it:
205
426
  ```bash
206
- herdr agent start do-tN --kind claude --pane "$ROOT_PANE" -- --model 'claude-opus-5-5[1m]' --effort high --dangerously-skip-permissions
427
+ SRC_WS=$HERDR_WORKSPACE_ID; BRANCH=<branch>; BASE=<base>; REPO_ROOT=<repo root>
428
+ focused() { herdr workspace list | jq -r '.result.workspaces[] | select(.focused) | .workspace_id'; }
429
+ BEFORE=$(focused) # wherever the person is now, often not your workspace
430
+ WT=$(herdr worktree create --workspace "$SRC_WS" --branch "$BRANCH" --base "$BASE" \
431
+ --path "$REPO_ROOT/.claude/worktrees/$BRANCH" --label "$BRANCH" --no-focus --json)
432
+ # create can move focus even with --no-focus: put it back where it was, and only then
433
+ [ -n "$BEFORE" ] && [ "$(focused)" != "$BEFORE" ] && herdr workspace focus "$BEFORE"
434
+ ROOT_PANE=$(jq -r .result.root_pane.pane_id <<<"$WT")
435
+ herdr agent start do-tN --kind claude --pane "$ROOT_PANE" -- --model "$MODEL" --effort "$EFFORT" --dangerously-skip-permissions
207
436
  herdr agent prompt do-tN "$BRIEF" --wait --until working --timeout 20000
208
- herdr workspace focus "$HERDR_WORKSPACE_ID" # if focus moved
209
437
  ```
210
- - **Answers** go to the architect as `herdr agent prompt do-tN "From the TODO: <their text>"`; it keeps working while it waits.
211
- - **Parked architects**: when no inbox message came from a task for 30 minutes, read its screen (`herdr agent read do-tN --source recent-unwrapped --lines 80`) and its lanes'; if a lane finished and the architect still waits, prompt it to continue.
438
+ Never pass `--focus`, never focus, select, or reveal the new space, its tabs, or its panes, and never use `herdr worktree open` for a new worker. When you must reopen an existing worktree with `worktree open` (a resume), pass `--no-focus` and restore focus the same way (save `BEFORE` first, refocus it only when `open` moved focus), since `open` focuses its target anyway. Never focus your own workspace to "get back": the person may be in another one.
439
+ - **Answers** go to the worker as `herdr agent prompt do-tN "From the TODO: <their text>"`; it keeps working while it waits.
440
+ - **Parked workers**: when no inbox message came from a task for 30 minutes, read its screen (`herdr agent read do-tN --source recent-unwrapped --lines 80`); if it waits on something that already finished, prompt it to continue.
441
+
442
+ ### Inside Orca (`HARNESS=orca`): worktrees and terminals
443
+
444
+ Each task becomes an Orca workspace with Claude in its first terminal. Read Orca's guide for this CLI version once (`orca skills get orca-cli`), pass `--json`, and read the fields named here from the results.
445
+
446
+ - **Worker per task**: an independent worktree from the repo's default base, then Claude on the task's tier (`$MODEL` and `$EFFORT` as in Herdr) in a terminal of its own, briefed the same way as the tester below. Use only flags Orca's guide lists for this version:
447
+ ```bash
448
+ W=$(orca worktree create --name do-tN-<short-slug> --no-parent --comment "tN planning" --json)
449
+ WT=$(jq -r '.result.worktree.id // .worktree.id' <<<"$W")
450
+ T=$(orca terminal create --worktree "id:$WT" --title do-tN --command "claude --model $MODEL --effort $EFFORT --dangerously-skip-permissions" --json)
451
+ orca terminal wait --terminal "$H" --for tui-idle --timeout-ms 60000 --json # $H: the terminal handle in $T
452
+ orca terminal send --terminal "$H" --text "$BRIEF" --enter --wait-submit 10 --json
453
+ ```
454
+ Keep `worktree.id` (the whole `<repoId>::<path>`), `worktree.path`, and the terminal handle in `state.json`. This creates the worktree in the background, without switching Orca's view: never add `--activate` or `--run-hooks` (both reveal the new worktree), and never pass `--focus` to `orca terminal create`.
455
+ - **Tester**: one terminal in your own worktree, started once and watching the queue itself, as in Herdr. Reuse a live `do-tester` from `orca terminal list --json` first:
456
+ ```bash
457
+ T=$(orca terminal create --worktree active --title do-tester --command "claude --model sonnet --effort high --dangerously-skip-permissions" --json)
458
+ orca terminal wait --terminal "$H" --for tui-idle --timeout-ms 60000 --json # $H: the handle in $T; send only when wait.satisfied is true
459
+ orca terminal send --terminal "$H" --text "$TESTER_BRIEF" --enter --wait-submit 10 --json
460
+ ```
461
+ - **Messenger**: a second terminal titled `do-messenger` made the same way (`claude --model sonnet --effort medium ...`) with the messenger brief, watching the inbox itself as in Herdr. Reuse a live one first.
462
+ - **The card mirrors the status line**: `orca worktree set --worktree "id:$WT" --comment "<status in a few words>" --workspace-status in-progress --json` (`in-review` while the review runs, `completed` once delivered), and `--unread` while a question waits for the person.
463
+ - **Answers**: `orca terminal send --terminal "$H" --text "From the TODO: <their text>" --enter --wait-submit 10 --json`. `accepted: true` is enough; never resend on silence.
464
+ - **Parked workers**: after 30 quiet minutes, `orca terminal read --terminal "$H" --json`, and prompt it to continue if it waits. After an Orca restart or a `terminal_handle_stale` error, take the new handle from `orca terminal list --worktree "id:$WT" --json` and use only that one.
465
+
466
+ ### Inside super.engineering (`HARNESS=sc`): worktrees and tabs
467
+
468
+ Each task becomes a super.engineering worktree with a Claude session working its brief. Run `sc instructions worktree` and `sc instructions orchestration` once and follow them; `/do-it` is the person asking for app-managed worker sessions, which those rules require before any `sc` orchestration. Run `sc chat providers --json` once for the Claude provider key and the model and reasoning values it accepts, and use only those (below: `claude`, `$MODEL`, `$EFFORT` as in Herdr). Keep `CONDUCTOR_WT=${SUPER_ENGINEERING_WORKTREE_PATH:-${SUPERCONDUCTOR_WORKTREE_PATH:-$PWD}}`.
469
+
470
+ - **Worker per task**: a new worktree with its task, created in the background:
471
+ ```bash
472
+ W=$(printf '%s' "$BRIEF" | sc worktree create --stdin --provider claude --model "$MODEL" --reasoning "$EFFORT" --background --json)
473
+ ```
474
+ Take the worktree's item id and path from `$W` (when it names neither, the new row in `sc workspace list --json`), its branch from `git -C "$WT" branch --show-current`, then name its session: `sc agents list --worktree "$WT" --output json` for its target and `sc agents label set --to <target> do-tN --worktree "$WT"`. Keep the item id, path, branch, and label in `state.json`. The app names the branch; never pass `--branch` or `--worktree-name` with a prompt (it refuses), and never run `git worktree add` for a worker. Never pass `--activate`, and never run `sc worktree select`, `sc worktree open`, `sc workspace select`, or `sc browser tab switch`: each one moves the person's view.
475
+ - **Tester**: one tab in your own worktree, started once and watching the queue itself, as in Herdr. Reuse a live `do-tester` from `sc agents list --worktree "$CONDUCTOR_WT" --output json` first:
476
+ ```bash
477
+ sc layout run tabs --worktree "$CONDUCTOR_WT" --label do-tester --provider claude --model sonnet --reasoning high \
478
+ --ui terminal --active keep --prompt "$TESTER_BRIEF" --output json
479
+ ```
480
+ - **Messenger**: a second tab labelled `do-messenger` made the same way (`--model sonnet --reasoning medium`) with the messenger brief, watching the inbox itself as in Herdr. Reuse a live one first.
481
+ - **Answers**: `sc agent send --to label:do-tN --worktree "$WT" --queue --prompt "From the TODO: <their text>" --output json`. A successful send means it was queued; never resend on silence.
482
+ - **Parked workers**: after 30 quiet minutes, `sc agent read --to label:do-tN --worktree "$WT" --last 80 --output json`, and prompt it to continue (same send) if it waits. A worker whose session is gone gets a new tab in its worktree: `sc layout run tabs --worktree "$WT" --open-if-needed --label do-tN --provider claude --model "$MODEL" --reasoning "$EFFORT" --ui terminal --active keep --prompt "<brief> RESUMED: continue from the commits on your branch"`.
483
+ - **Cleanup** after delivery, only when the person asks: `sc worktree delete <item id>` (never `--force` on unpushed work).
484
+
485
+ ### Inside T3 Code (`HARNESS=t3code`): threads in worktrees
486
+
487
+ Each task becomes a T3 Code thread in its own worktree. Flags differ between T3 Code versions: run `t3 thread start --help` once and use only flags it lists.
488
+
489
+ - **Worker per task**:
490
+ ```bash
491
+ ID=$(t3 thread start . "$BRIEF" --worktree "$BASE" --title "do-tN <task in a few words>" --json | jq -r '.threadId // .thread.id // .id')
492
+ ```
493
+ `$BASE` is the repo's integration branch (`origin/main` unless the repo says otherwise). Add the task's tier (`--provider claudeAgent --model sonnet` for S, `--model opus` for M and L, and `--effort high`) only when `--help` lists those flags; otherwise the thread uses the project's default model. Keep the thread id in `state.json`. Start threads in the background: never pass a flag that `--help` describes as opening, focusing, or revealing the thread in the app.
494
+ - **Tester**: one thread in the project folder (no `--worktree`), started when the first request is queued: `TID=$(t3 thread start . "$TESTER_BRIEF" --title do-tester --json | jq -r '.threadId // .thread.id // .id')`. It drains the queue and ends its turn with `QUEUE EMPTY`. For later requests, `t3 thread send "$TID" "New test requests are queued: drain the queue"`; never start a second tester.
495
+ - **Messenger**: one thread in the project folder titled `do-messenger` with the messenger brief, started with the first task. It drains the inbox and ends its turn with `INBOX DRAINED`; on new inbox lines, and right after you append a `conductor` line (your watch skips those), `t3 thread send "$MID" "New inbox lines: drain them"`. Never start a second one.
496
+ - **Answers**: `t3 thread send "$ID" "From the TODO: <their text>"`. A send never interrupts; a busy thread takes it as its next turn.
497
+ - **Parked workers**: after 30 quiet minutes, `t3 thread show "$ID"`, and nudge it when it waits. A thread that waits for an answer inside the app (exit code 2 from a `--wait` send) gets a question line under its task.
212
498
 
213
499
  ## Step 5. React to events
214
500
 
@@ -217,35 +503,41 @@ The same roles as herdrdocwatch, with `do-it` commands in place of Herdr's `doc`
217
503
  | New task line | Step 3 |
218
504
  | The person writes a note under a `listed` item, or edits its text | triage it now (Step 3) with their note as the instruction |
219
505
  | The person adds a section whose text is an instruction ("all PRs in this section: ...") | a standing rule: apply it to every item moved or added into that section, as that item's instruction; an empty section waits |
220
- | The person edits or adds notes under an active task | forward them: `SendMessage` to the worker (outside Herdr, once it has stopped) or `herdr agent prompt do-tN "From the TODO: ..."` |
221
- | The person answers a question (an indented line under `**tN question:**`) | forward it the same way, then remove your question line |
222
- | The person deletes a task, or writes "stop" under it | tell its worker to stop and commit its work in progress; status `stopped`, keep the worktree |
223
- | The person unchecks a delivered task | their new note under it is a follow up for the same worktree and worker |
224
- | Inbox `progress` | update the status line only, in a few words |
225
- | Inbox `question` | add ` - **tN question:** <question>` under the task; status `waiting for you` |
226
- | Inbox `blocked` or `failed`, or a worker ended without DONE | read what it said; fix the brief and resume it, or escalate a twice failed S or M task to Astra; tell the person only what they must decide |
227
- | Worker DONE | verify (below), Fable review, write status `delivered`, then run `todo check` for the task |
506
+ | The person edits or adds notes under an active task | forward them as `From the TODO: ...` through the worker's transport: `SendMessage` (plain, once it has stopped), `herdr agent prompt do-tN`, `orca terminal send`, or `t3 thread send` |
507
+ | The person answers a question (an indented line under `**tN question:**`) | forward it the same way, then remove the question line (with a messenger: append `- conductor tN answered`) |
508
+ | The person deletes a task, or writes "stop" under it | tell its worker to stop and commit its work in progress; status `stopped`, keep the worktree. Only "cancel" or "drop it" in words also gets `todo cancel` |
509
+ | The person unchecks a delivered task | their new note under it is a follow up for the same worktree and worker; keep its `@started` |
510
+ | The person checks off `Review this task` under an L task | if a `conductor tN subtasks:` line of yours is not written yet, wait for the messenger to drain it first; then read the task's subtask lines as they are now, save them in `state.json`, and dispatch one worker with them (status `L, building subtask 1 of N`), or queue it while 3 workers are active (status `L, reviewed, queued`) |
511
+ | The person adds or edits a `- [ ]` line under an L task still in review | a subtask edit: nothing to do until the review is checked |
512
+ | The person writes a plain note under an L task still in review | a request for a different split: send it to the planner with its plan and write the new subtasks (Step 3) |
513
+ | Inbox `subtask started` or `subtask done` | `todo start` or `todo check` on that subtask line; the status reads `L, building subtask K of N` |
514
+ | A Q agent returns `ANSWER: <path>` | write under the task: without a messenger, the file's lines as sub bullets under `**tN** answered`; with one, `- conductor tN answer: <path>`. Then `todo check` |
515
+ | Inbox `progress` | update the status line only, in a few words (the messenger does this by itself) |
516
+ | Inbox `question` | add ` - **tN question:** <question>` under the task; status `waiting for you` (the messenger does this by itself) |
517
+ | Inbox `blocked` or `failed`, or a worker ended without DONE | read what it said; fix the brief and resume it, or after a second failure: an S task moves to an Opus worker, an M task gets a new Opus plan and a fresh Opus worker (or a question under the task), an L task may use the stronger model from `models.json`; write under the task only what the person must decide |
518
+ | Worker DONE | verify (below), review, write under the task `delivered` and its explanation from `$STATE/explain/tN.md` when the worker wrote one (with a messenger: `- conductor tN explain: <path>`; without one, the `edit` in Folded sections and HTML), then run `todo check` for the task |
228
519
  | Tester BLOCKED or a long queue | one line under the affected task; never start a second tester |
229
520
 
230
- **Verify before `delivered`.** A done message is not proof:
521
+ **Verify before `delivered`.** A done message is not proof. Check only the facts, and save the diff for the reviewer instead of reading it:
231
522
 
232
523
  ```bash
233
524
  git -C "<worktree>" log --oneline "<base>..HEAD"
234
525
  git -C "<worktree>" diff --stat "<base>...HEAD"
526
+ git -C "<worktree>" diff "<base>...HEAD" > "$STATE/reviews/tN.diff"
235
527
  ```
236
528
 
237
- and the final request in `tests.md` says PASS for that commit. The delivered line reads:
529
+ and the final request in `tests.md` says PASS for that commit. The review of the change itself is the reviewer's, on that file. The delivered line reads:
238
530
 
239
531
  ```
240
- - **t3** delivered: branch `fix-sidebar-ports` (2 commits, a1b2c3d), tests t3r2 passed, Fable: ship. Worktree `.claude/worktrees/fix-sidebar-ports`
532
+ - **t3** delivered: branch `fix-sidebar-ports` (2 commits, a1b2c3d), tests t3r2 passed, review: ship. Worktree `.claude/worktrees/fix-sidebar-ports`
241
533
  ```
242
534
 
243
535
  Keep your lines short: the todo is a dashboard, not a log. Full detail lives in `plans/`, `logs/`, and the worktrees.
244
536
 
245
- After writing the delivered status line, mark the task done with the version returned by that status edit:
537
+ Then mark the task done, which adds `@done`:
246
538
 
247
539
  ```bash
248
- $D todo check "$TODO" --version $V --section tasks -- "<exact task text>"
540
+ do-it todo check "$TODO" --version $V --section tasks -- "<the task text>"
249
541
  ```
250
542
 
251
543
  ## Ending
@@ -255,7 +547,21 @@ Run until the person says in chat to stop, or the todo goes away. On stop: stop
255
547
  ## Rules
256
548
 
257
549
  - **The todo is the interface.** Every event the person should know about lands in it.
258
- - **One writer per channel role.** Only you write status into the todo; workers write only to the inbox and the test queue; only the tester answers test requests. Always through `do-it` commands naming the version.
550
+ - **Delegate and monitor.** You never read code, docs, or diffs, never research, and never answer a question yourself; an agent does, and you keep its conclusion. Your own todo labels are `@started` at once and `@done` on delivery.
551
+ - **One writer per channel role.** Always through `do-it` commands naming the version:
552
+
553
+ | Channel | Who writes | What |
554
+ | --- | --- | --- |
555
+ | the todo | the person | anything |
556
+ | the todo | you | stamps only, through `todo start`, `todo check`, `todo cancel` (on subtasks too); plus the `**tN**` lines and L subtask lines while no messenger is on, and the seed block |
557
+ | the todo | the messenger | every `**tN**` line and the L subtask lines once it is on |
558
+ | `inbox.md` | workers; you | their `progress`, `question`, `blocked`, `done`, `subtask` lines; your `conductor` lines |
559
+ | `tests.md` | workers; the tester | requests; the answers under them |
560
+ | `answers/`, `seed.md`, `explain/` | Q, seed, and worker agents | one file each |
561
+ | `state.json`, `models.json`, `plans/`, `reviews/` | you | run state, the models you found, saved plans and subtasks, diffs for review |
562
+ | `messenger.version` | the messenger | its cursor (you write it once, when you turn it on) |
563
+
564
+ Session workers keep their own plans in their worktree; `plans/` holds the ones you saved.
259
565
  - **One tester, one test at a time.** A worker caught running a build or test is stopped and reminded of the compute rule.
260
566
  - **Three workers at most** unless the person writes otherwise in the todo. Each owns its worktree; no two writers share a checkout.
261
567
  - **No outward actions by default.** Pushing, PRs, merges, deploys, and messages to other people happen only when the task line asks in words.