timeboxed-iterating · diff

git:20260330.d629481 to git:20260826.5588d55

617 added, 120 removed. Audit A to A.

---
name: timeboxed-iterating
- description: Use when the user specifies a task and a duration, and the work should be done iteratively by subagents over that time period
+ description: >
+ Run a task iteratively over a user-specified duration by dispatching subagents.
+ The orchestrator stays strictly linear and time-checked, but each iteration
+ fans out MULTIPLE subagents in parallel over independent units (and those
+ subagents may fan out further). Shared state — a compact progress digest and a
+ growing environment cheatsheet — lives on disk and is passed to every subagent
+ BY REFERENCE, killing the per-subagent rediscovery tax. Every subagent first
+ reads an initialiser preamble that points it at that shared state and makes it
+ write findings back, so the cheatsheet populates itself; role prompts are
+ produced ONCE on the filesystem by a single scaffold command and dispatched by
+ path, never re-typed per dispatch. Subagents persist their results to disk and
+ return only a tiny status, so the orchestrator's context stays small and lasts.
+ The orchestrator
+ classifies the goal as FINITE or OPEN-ENDED: finite lists may finish early;
+ open-ended goals use the full duration, never idle, never manufacture busywork.
+ Use when the user gives a task and a duration and wants it ground out
+ iteratively by subagents over that time.
---
- # Timeboxed Iterating
+ # Timeboxed Iterating — Parallel Fan-Out Under a Clock
- Run a task iteratively via subagents for a user-specified duration. The clock is the only authority on when to stop. You are not.
+ Take a goal and a duration and grind it out with subagents. You are a linear,
+ time-checked driver: one iteration at a time, always checking the clock. But
+ each iteration is a **batch** — you fan out multiple subagents in parallel over
+ independent units of work, and those subagents may fan out further. You never
+ author anything yourself. Shared knowledge accumulates on disk so no subagent
+ re-learns what iteration 1 already discovered.
## Your Role
- You are the **orchestrator**. You do exactly two things:
+ You are the **orchestrator**. You do exactly five things:
- 1. **Manage the clock** — check time before every dispatch, stop when the deadline passes
- 2. **Dispatch subagents** — give them the goal, the progress file path, and get out of the way
+ 1. **Manage the clock** — `date +%s` before every batch; the deadline is the brake.
+ 2. **Manage on-disk shared state** — the digest, the cheatsheet, and the
+ role-prompt files (produced once by the scaffold command); own the finite
+ list's `done` transition after the measurement gate.
+ 3. **Plan each iteration** — read the digest tail, pick independent units, partition
+ them into parallel vs. serial, size a model per unit.
+ 4. **Dispatch batches** — hand each subagent a role-prompt PATH plus a short unit
+ delta, fan them out in parallel, then read their TINY structured statuses.
+ 5. **Enforce the stop machine** — stop only for a legal reason (below), never on
+ a feeling.
- You do NOT do any actual work. No code changes, no file edits, no exploration, no analysis, no "quick fixes." All productive work happens inside subagents. Your context is reserved exclusively for the dispatch loop. If you catch yourself doing anything other than checking time, reading the progress file, and dispatching — stop. That work belongs in a subagent.
+ You do **no authorship** and **no analysis**: no code edits, no DB queries, no
+ PR creation, no HTML/report generation, no "quick fixes," no reading the codebase
+ to figure something out. Every productive act happens inside a subagent — **even
+ under context pressure, even after a blowout** (this is the **Orchestrator-Only
+ Line**, and it is the fix for the failure where orchestrators burned their
+ scarcest resource doing delegable work). Your context is reserved for the
+ dispatch loop. If you catch yourself doing anything other than checking time,
+ managing the on-disk files, planning, and dispatching — stop. That work belongs
+ in a subagent.
- ## The Iron Law
+ **Pure dispatch — never ingest large content (E3).** Orchestrator context is the
+ scarcest resource on a long run; exhausting it forces premature restarts. So you
+ never read a full artifact, a full subagent transcript, or a large return into
+ your own context. Subagents persist their results to disk — their unit file, the
+ digest, the cheatsheet — and return only a TINY structured status (e.g.
+ `unit X: done, commit <hash>` or `measure X: PASS — <one line>`). You read only the
+ compact **digest tail** plus those one-line statuses. Prefer having subagents
+ append their own digest/unit-file entries so you are not even reproducing that
+ content. Per-iteration footprint stays minimal: clock check → glance at the digest
+ tail → dispatch by reference → record/confirm a one-line status. If a return is
+ about to dump an artifact or a wall of prose into your context, that is a Red Flag
+ — it belongs in the unit file, fetched by whoever needs it, not by you.
+ ## The Iron Laws
+
```
- YOU DO NOT DECIDE WHEN THE WORK IS DONE. THE CLOCK DECIDES.
+ 1. THE CLOCK (OR THE USER) DECIDES WHEN AN OPEN-ENDED RUN STOPS. Not you, not a subagent, not a "feels done."
+ 2. A FINITE LIST DECIDES WHEN A FINITE RUN STOPS. Exhaust the list → stop. Finishing early is CORRECT, not failure.
+ 3. THE ORCHESTRATOR NEVER AUTHORS. It checks time, manages disk state, plans, dispatches, reads returns. Nothing else.
+ 4. EACH ITERATION FANS OUT; INDEPENDENT WORK RUNS IN PARALLEL. Serial dispatch of independent units is the dominant, forbidden loss.
```
- Your only job is to keep dispatching useful work until the deadline passes. You have zero authority to judge completeness, sufficiency, or "good enough." The user gave you a duration. You use all of it.
+ Law 1 preserves this skill's one genuine strength — an open-ended run must not
+ stop early just because progress "looks good." Law 2 narrows that strength: it
+ does **not** apply to a finite, exhaustive spec or a finite item list, where
+ padding the clock after the list is done is pure waste. You must classify the
+ goal (Phase 0) to know which law governs.
- ## Inputs
+ ## What Makes This Work (Non-Negotiables)
- The user provides two things:
+ Violate any of these and you are running a slow serial loop, not this skill:
- 1. **Goal** — what to do (e.g., "improve test coverage", "refactor AI slop", "build out the spec")
- 2. **Duration** — how long to do it (e.g., "4 hours", "overnight", "90 minutes")
+ 1. **Linear driver, parallel fan-out.** You never run two iterations at once —
+ the loop is sequential and time-checked. But one iteration dispatches many
+ subagents at once over independent units. (C1)
+ 2. **Shared state by reference, never inline.** Progress digest, cheatsheet, and
+ role-prompt files live on disk; every dispatch passes **paths** — the role
+ prompt, and (via the initialiser) the digest and cheatsheet — and orders the
+ subagent to read them first. You never paste a template, the digest, or the
+ cheatsheet into a prompt. (C2)
+ 3. **The cheatsheet populates itself.** Every subagent reads the initialiser
+ preamble first, which makes it read the shared state and append any hard-won
+ environment fact back to the cheatsheet before returning — so knowledge
+ accumulates dynamically, batch over batch, and the next batch starts warm.
+ Recipes and gotchas are discovered continuously, NOT front-loaded from a test
+ run. (B2/D1)
+ 4. **Single source of truth for volatile values.** Live counts, hashes, and
+ iteration numbers live in exactly one place (the digest). Never embed them
+ across N files. (B4)
+ 5. **Real success bar first — numeric OR textual.** The actual bar the goal is
+ judged by is identified up front and piloted before mass production — it gates
+ the loop early, not at the end. That bar may be **numeric** (a threshold, score,
+ count, pass rate) OR **qualitative/textual** (a rubric, an acceptance
+ description, an LLM-judge verdict, a checklist, "reads like X and covers Y"); the
+ gate is identical either way. The gate does not expire after the pilot: every
+ unit produced against a statable success bar must pass that real bar — applied by
+ a separate measurement subagent, never the producer — never a proxy — before it
+ is marked done (Phase 2d). If the goal has no statable success bar at all, the
+ gate does not apply. (B5)
+ 6. **Front-load only genuine enablers.** Stand up execution infrastructure,
+ record the real success bar (numeric OR textual) + scope/validity bar IF one exists, and
+ sync the repo in the first iteration(s) — never the final hour. Everything else
+ (recipes, tool quirks, gotchas, reusable findings) is discovered DYNAMICALLY by
+ subagents via the initialiser+cheatsheet loop, not front-loaded from a test
+ run. (B8/D1)
+ 7. **Model sized to the unit, capped at your own tier.** Cheap models for
+ mechanical units; never a model more powerful than the orchestrator. (C3)
+ 8. **No manufactured work, no idle.** The loop never invents bookkeeping to stay
+ busy and never sleeps out the clock. (B4/B6)
+ 9. **Concurrency-cap aware.** Never dispatch more subagents at once than the
+ platform allows — over-cap dispatches fail silently.
+ 10. **Prompts are written once to disk, referenced by path — never hardcoded.**
+ The general rule: whenever you will reuse a prompt, you write it to disk ONCE
+ and thereafter reference it BY PATH in every identical situation — you never
+ re-compose or re-type it. The four standard role prompts (initialiser, builder,
+ sub-subagent, measurement) are produced once by the scaffold command (Phase 1a);
+ if you ever compose a specialized prompt for a recurring unit type, write it
+ into `<harness>/prompts/` once and dispatch it by path too. Every dispatch is a
+ role-prompt PATH plus a short unit delta — never a re-typed template. (E1/E4/D3/C2)
+ 11. **Orchestrator = pure dispatch.** You never ingest a full artifact, transcript,
+ or large return into your own context. Subagents persist results to disk and
+ hand you a tiny status; you read only the digest tail + those one-liners. Your
+ context is the resource this skill exists to protect. (E3)
- If the duration is vague ("overnight"), interpret it as 8 hours. If truly ambiguous, ask once.
+ ## Inputs
+ 1. **Goal** — what to do (e.g., "distill a fixed list of source documents into
+ notes", "fix every lint error", "improve test coverage", "harden the API").
+ 2. **Duration** — how long (e.g., "4 hours", "overnight" = 8 hours, "90 minutes").
+
+ If the duration is vague, interpret "overnight" as 8 hours. If the goal is
+ genuinely ambiguous, ask **one** question. Otherwise pick and proceed.
+
## The Process
```dot
digraph timeboxed {
rankdir=TB;
node [shape=box];
- start [label="Record start time\nCompute deadline" shape=doublecircle];
- init [label="Create progress file\nin /tmp"];
- check [label="Check current time\nagainst deadline" shape=diamond];
- read_log [label="Read progress file\nfor orchestrator context"];
- dispatch [label="Dispatch subagent\nwith goal + progress file path"];
- update [label="Update progress file\nwith iteration results"];
- summary [label="Write final summary\nto progress file" shape=doublecircle];
+ classify [label="Phase 0: Classify goal\nFINITE vs OPEN-ENDED\nrun scaffold: workspace + prompts/ + digest + cheatsheet + clock" shape=doublecircle];
+ front [label="Phase 1: Setup + Front-load\nscaffold produced prompts/ ONCE;\nsuccess-bar pilot (numeric OR textual) + enabling infra +\nscope/validity bar + repo sync\n(seeds cheatsheet; then it grows dynamically)"];
+ brake [label="Brake + Stop-guard\n(deadline? finite list done?\nremaining time fit a useful unit?)" shape=diamond];
+ plan [label="Phase 2a: Plan iteration\nread digest; select independent units;\npartition parallel/serial; size a model each;\ncap batch at concurrency limit"];
+ dispatch [label="Phase 2b: Dispatch BATCH in parallel\neach subagent: role-prompt PATH + unit-file path +\ngap line (short delta) — NO inline templates"];
+ collect [label="Phase 2c: Read TINY statuses (never full artifacts)\nspot-check each commit via git log"];
+ consol [label="Phase 2d: Consolidate (minimal footprint)\nsubagents already appended to digest+cheatsheet;\nflip finite-list done only after the success gate PASSes"];
+ done [label="Phase 3: Stop\nfinal summary" shape=doublecircle];
- start -> init -> check;
- check -> read_log [label="time remains"];
- check -> summary [label="deadline passed"];
- read_log -> dispatch;
- dispatch -> update;
- update -> check;
+ classify -> front -> brake;
+ brake -> plan [label="OPEN-ENDED and a useful unit fits\nOR FINITE and list not exhausted"];
+ brake -> done [label="deadline passed / user stop /\nFINITE list exhausted /\nno useful unit fits remaining time"];
+ plan -> dispatch -> collect -> consol -> brake;
}
```
- ### Step by step
+ Every path returns to the brake check. `done` is reachable **only** from the
+ brake check — there is no quality-based or "feels complete" exit anywhere in the
+ graph. Where the diagram and the prose disagree, the **Stop Machine** below is
+ authoritative.
- 1. **Record the start time.** Run `date +%s` to get the current Unix timestamp. Compute the deadline timestamp by adding the duration.
+ ---
- 2. **Create the progress file.** Write it to `/tmp/timeboxed-<goal-slug>-<timestamp>.md`. Initial contents:
+ ## Phase 0: Classify + Setup
- ```markdown
- # Timeboxed Run: <goal>
- - Start: <human-readable time>
- - Deadline: <human-readable time>
- - Duration: <duration>
+ ### 0a. Classify the goal — FINITE vs OPEN-ENDED (C4)
- ## Iterations
- ```
+ This is the first decision and it governs the entire stop behavior. Write the
+ classification into the digest header; it is not revisable on a whim.
- 3. **Check the time.** Run `date +%s`. Compare against the deadline timestamp. If the deadline has passed, go to step 6. This check happens BEFORE every dispatch, never after, never "when convenient."
+ - **FINITE** — the goal is a precise/exhaustive spec or a finite, enumerable list
+ of items. "Process these 25 documents." "Fix all 40 lint errors." "Port every
+ endpoint in this file." "Implement the 12 facts tagged @spec." For finite
+ goals, **enumerate the item list explicitly** into the digest at setup — the
+ list is the completion authority (Iron Law 2). Finishing when the list is
+ exhausted is CORRECT.
+ - **OPEN-ENDED** — the goal has no fixed terminus; there is always more.
+ "Improve test coverage." "Harden security." "Reduce AI slop." "Find bugs." For
+ open-ended goals, the **clock** is the only completion authority (Iron Law 1).
+ Use the full duration; do not stop because it "looks good enough."
- 4. **Dispatch a subagent.** Give it:
- - The goal
- - The path to the progress file — the subagent reads it itself to learn what was already done
- - Instruction: do ONE meaningful unit of work toward the goal, commit it, and return a structured summary of what was done and what high-impact work remains
+ If a goal is finite in one dimension and open-ended in another (e.g. "review
+ these 10 files for bugs" — finite file list, open-ended depth per file), treat
+ the enumerable dimension as the list and the depth as open-ended within each
+ item: the run ends when the list is covered to a defined depth or the clock
+ fires, whichever first.
- Do NOT paste the progress file contents into the subagent prompt. Pass the path. The subagent reads it. This keeps the orchestrator's context lean across long runs.
+ ### 0b. Setup the harness — run the scaffold command (E4)
- Do NOT give the subagent the deadline or any time awareness. It does not need to know. It does one unit and returns.
+ You do not hand-build the workspace or paste template text. ONE command produces
+ the entire ready-to-run workspace at `~/.harness/timeboxed/<slug>/` from a few
+ variables — see **The Scaffold Command** below for the full contract. Run it now:
- 5. **Update the progress file.** Append the iteration result:
+ ```bash
+ bash <skill-dir>/scaffold/init.sh \
+ --slug <slug> --goal "<goal>" --mode <finite|open-ended> [--duration <e.g. 4h|90m>]
+ ```
- ```markdown
- ### Iteration N — <time>
- - What was done: <summary>
- - What was committed: <commit hash or "nothing">
- - Suggested next: <what the subagent recommended>
- ```
+ It creates and variable-substitutes:
- Then go back to step 3.
+ ```
+ progress.md — the STATE DIGEST: compact, single source of truth for
+ volatile values (iteration count, per-unit status, commits,
+ the finite item list + what's done). Subagents append one-line
+ statuses; you read only its tail. NOT a pile of ledgers.
+ run-card.md — the static RUN CARD: run identity + workspace map + resume
+ pointer. Holds NO volatile values (those live only in
+ progress.md). Read it once to orient.
+ cheatsheet.md — persistent, growing: environment recipes, working commands,
+ tool quirks, known gotchas, auth workarounds. Seeded empty of
+ findings; read by every subagent, appended to by every subagent.
+ prompts/ — role prompt files, produced ONCE by the scaffold from the
+ filesystem templates in `scaffold/`: initialiser.md (read FIRST
+ by every subagent), builder.md, sub-subagent.md, measurement.md.
+ Dispatches pass these BY PATH, never re-typed.
+ units/<unit-id>.md — one file PER UNIT: its scope on dispatch, its full result on
+ return. Per-unit files exist so parallel subagents never write
+ to the same file (no write contention), and so full results live
+ on disk instead of in the orchestrator's context.
+ ```
- 6. **Write the final summary.** Append to the progress file:
+ After scaffolding, fill the two placeholders the scaffold left in `progress.md`:
+ the **concurrency cap** and the **real success bar** (numeric OR textual — Phase 1
+ pilots it; write `none` if the goal has no statable bar). Dispatch a subagent for
+ anything non-trivial — you author nothing.
- ```markdown
- ## Summary
- - Total iterations: N
- - Duration: <actual elapsed>
- - Key accomplishments: <bullet list>
- - Remaining work: <what's left>
- - Progress file: <path>
- ```
+ Create the target repo context: the artifact is always under git (existing repo
+ in place, or `mkdir ~/code/<slug> && git init` for from-scratch work). Every
+ subagent commits; your spot-checks depend on it.
- Tell the user where the progress file is.
+ ### 0c. Clock
- ## Preventing Premature Exit
+ `date +%s`, compute the deadline epoch, write both to the digest. You check it at
+ the top of every iteration (the brake), before dispatching the batch — never
+ after, never "when convenient."
- This is the entire point of the skill. LLMs will try to stop early. Every single one of these is a trap:
+ ---
- | Thought you're having | What you must do instead |
+ ## Phase 1: Setup + Front-Load (B5 + B8 + D1 + D3)
+
+ Do this **before** the main loop, in the first iteration(s). You author nothing —
+ the front-loading work itself runs via dispatched subagents (Iron Law 3).
+
+ ### 1a. Prompts already exist on disk — written once, referenced by path (E1/E4/D3)
+
+ The scaffold command (Phase 0b) already produced the four role prompts under
+ `<harness>/prompts/`, variable-substituted:
+
+ - `initialiser.md` — the preamble EVERY dispatched subagent reads first.
+ - `builder.md` — the builder role prompt.
+ - `sub-subagent.md` — the fan-out role prompt.
+ - `measurement.md` — the independent measurement role prompt.
+
+ You do not re-type or re-compose them. Thereafter every dispatch hands the
+ subagent a role-prompt PATH plus a short unit delta (2b). Re-typing one burns your
+ context (the resource this skill protects) and is a Red Flag.
+
+ **The general rule (E1): write any reusable prompt to disk ONCE, then reference it
+ by path in every identical situation.** The scaffold covers the four standard
+ roles. If you ever find yourself composing a specialized prompt for a recurring
+ unit type, do not paste it into each dispatch — write it into `<harness>/prompts/`
+ one time and dispatch it by path exactly like the standard roles.
+
+ ### 1b. Front-load ONLY genuine enabling setup (D1)
+
+ Front-load only what is a real ENABLER and provably exists — **not** a speculative
+ "run the whole task once to see what breaks." A pilot may surface no issues, and
+ issues surface continuously, not at t=0. In priority order:
+
+ 1. **Real success-bar pilot (B5).** Identify the bar that actually decides whether
+ the goal succeeded — the *expensive discriminating* judgment, not a cheap
+ pass-shaped proxy. That bar may be **numeric** (a threshold, score, count, pass
+ rate) OR **qualitative/textual** (a rubric, an acceptance description, an
+ LLM-judge verdict, a checklist, "reads like X and covers Y"). Dispatch a
+ subagent to apply it on a **small pilot** (one item, one sample) and prove the
+ real bar actually discriminates a good unit from a bad one on ONE representative
+ item before producing the rest. This bar then **gates the loop**: subsequent
+ batches produce only against a bar that already works. Never mass-produce, then
+ judge at the end. If the goal genuinely has no statable success bar (pure
+ open-ended qualitative churn with nothing to judge against), record `none` and
+ skip the gate — but prefer to state a bar wherever one exists.
+ 2. **Enabling infrastructure (B8).** Runners, harnesses, environment setup, API
+ access, the in-cloud runner if the run needs one — stand it up now. The recipes
+ discovered here **seed** `cheatsheet.md`; the rest grows dynamically thereafter.
+ 3. **Scope / validity bar IF one exists (B8).** If the goal has a definition of a
+ valid unit of output (what's in scope, what a real finding/fix/artifact looks
+ like), record it up front. A run that culls a large pile of raw candidates down
+ to a handful of valid ones only AFTER the box closes wasted the box; put the
+ validity bar in the FIRST iteration so every later unit is pre-filtered.
+ 4. **Repo sync (B8).** Sync to the branch you'll finalize against now. Do not let
+ a stale main branch turn into conflict theater at the end.
+
+ **Everything else is dynamic, not front-loaded.** Environment recipes beyond the
+ initial standup, tool quirks, gotchas, and reusable findings are discovered
+ continuously by subagents that read `prompts/initialiser.md` first and append what
+ they learn to the cheatsheet (D1). Do not try to enumerate every gotcha up front
+ from one test run — that is what the initialiser+cheatsheet loop is for. Keep
+ B8's real point (never defer a genuine enabler to the final hour) without turning
+ issue-discovery into a t=0 test run.
+
+ Record in the digest that front-loading ran and what it established. The cheatsheet
+ is seeded; from here it grows itself, batch over batch.
+
+ ---
+
+ ## Phase 2: The Iteration Loop
+
+ The loop is **linear**: one batch at a time, brake-checked at the top. Within a
+ batch, subagents run **in parallel**.
+
+ ### Brake + Stop-guard (top of every iteration)
+
+ Run `date +%s`, compare to the deadline, and evaluate the **Stop Machine**. If
+ any stop condition holds → Phase 3. Otherwise continue to 2a.
+
+ A batch already in flight when the deadline passes **soft-stops**: let its
+ subagents finish and consolidate their returns, then stop. Never strand committed
+ work unrecorded.
+
+ ### 2a. Plan the iteration
+
+ Read the **digest** (the compact one, not a heap of ledgers — B3). From it,
+ select the next set of **units** — the smallest pieces of real work that move the
+ goal. For a FINITE run, units are the next unclaimed items from the list. For an
+ OPEN-ENDED run, units are the next highest-leverage angles.
+
+ **Partition units into parallel vs. serial (C1 / B1) — the independence rule:**
+
+ - **Separate files / disjoint surfaces → PARALLEL.** Units that touch different
+ files, different modules, different topics, or independent attack surfaces have
+ no write conflict — dispatch them in the same batch, at once.
+ - **Shared file / shared resource → SERIAL, round-robin.** Units that edit the
+ same file, the same document, or the same scene run one at a time across
+ successive batches. Do not try to partition a shared file into "regions" for
+ parallel writers — that produces corruption and lost edits.
+ - **Within a single unit**, the subagent's own steps are sequential; but that
+ subagent may itself fan out sub-subagents over independent sub-units (C1).
+
+ **Respect the concurrency cap.** Never put more than the platform's cap of
+ subagents in one batch. If you have 20 independent units and a cap of 6, dispatch
+ 6, let them return, dispatch the next 6. Over-cap dispatches fail silently and
+ you'll redispatch blind. The cap is in the digest header.
+
+ **Size a model per unit (C3).** For each unit choose the smallest model that can
+ do it well:
+
+ | Unit character | Model |
|---|---|
- | "I've made good progress" | Check the clock. Time left? Keep going. |
- | "The user would be happy with this" | You don't decide that. Check the clock. |
- | "The remaining work is too complex" | Break it into smaller units. Dispatch. |
- | "Let me just quickly check something" | No. Dispatch a subagent to check it. |
- | "This task is essentially complete" | Find more improvements. There are always more. |
- | "I should let the user review first" | No. The user said run for X hours. Run for X hours. |
- | "I don't want to break things" | That's what commits and tests are for. Dispatch. |
- | "Diminishing returns at this point" | Not your call. Check the clock. |
- | "The subagent didn't find anything to do" | Try a different angle. Reframe the goal. Dispatch. |
- | "I've covered the main areas" | Cover the secondary areas. Then the edge cases. Then polish. |
- | "Let me summarize what was accomplished" | Only after the deadline. Not before. |
- | "One more iteration won't add much" | You are not qualified to make this judgment. Dispatch. |
+ | Mechanical / narrow (rename, mechanical edit, run a known command, format, apply a known fix, scrape one page) | Small / cheap model |
+ | Standard implementation, moderate reasoning | Mid model |
+ | Deep design, novel analysis, hard debugging, judgment | Orchestrator-tier |
- **If you catch yourself thinking any variation of "maybe I should stop" — that is your signal to check the clock and dispatch again.**
+ **Hard cap: never dispatch a model more powerful than the orchestrator itself.**
+ If you are running on a mid-tier model, "orchestrator-tier" IS your ceiling —
+ you cannot summon a stronger model than yourself; asking for one silently fails
+ or wastes the dispatch. Size down freely, never up past your own tier.
- ## Preventing Sabotaged Runs
+ Write each unit's scope into its own `units/<unit-id>.md` before dispatch.
- Stopping early is the most common failure, but not the only one. These patterns also sabotage runs:
+ ### 2b. Dispatch the batch (in parallel)
- **Doing work in the orchestrator.** You are a dispatcher, not a worker. If you're editing files, running tests, reading code, exploring the codebase, or making "small fixes" — you're burning orchestrator context on work that belongs in a subagent. The only tools you use are: check time, read progress file, dispatch subagent, write to progress file.
+ Dispatch all units in the batch **in a single step** (one message, multiple
+ subagent calls) so they run concurrently. Every dispatch is a SHORT message — a
+ role-prompt PATH plus a small unit-specific delta, never a re-typed template:
- **Doing everything in one subagent.** You must dispatch multiple iterations. One subagent that "does the whole thing" defeats the purpose — you lose time-checking, progress tracking, and the ability to course-correct. Each subagent does ONE meaningful unit.
+ - **Role-prompt path** — `<harness>/prompts/builder.md` (or `measurement.md` for
+ the measurement gate). That file already tells the subagent to read
+ `<harness>/prompts/initialiser.md` first, which points it at the digest and
+ cheatsheet by reference and makes it write findings back.
+ - **Unit delta** — the unit id, its unit-file path `<harness>/units/<unit-id>.md`
+ (you wrote the scope there in 2a), and one line naming this unit's gap/target.
- **Planning instead of doing.** If an iteration's summary is a plan, a list of suggestions, or a "here's what we could do" — that iteration was wasted. Every iteration must produce committed code, written content, or a tangible artifact. Not plans. Not analysis. Artifacts.
+ That is the whole dispatch. You never paste a template, the digest, or the
+ cheatsheet into the message (C2/D3) — you pass paths. Re-typing a template into a
+ dispatch is a Red Flag: it burns your context, the exact resource this skill
+ exists to protect.
- **Repeating the same work.** The subagent reads the progress file itself, but you should still scan it between iterations to catch repetition. If you see it, explicitly exclude the completed work in the next dispatch prompt.
+ The role prompts already instruct each subagent to **persist its full result to
+ disk** (its unit file), **append its findings** to the cheatsheet, **append one
+ status line** to the digest, and **return only a tiny status** — not a wall of
+ prose (E3). You depend on that: your context stays small only because results land
+ on disk, not in returns.
- **Shrinking scope with each iteration.** The goal doesn't get smaller as you go. If the goal is "improve test coverage," iteration 10 should be as ambitious as iteration 1. Don't let the scope contract to trivial fixes.
+ Do **not** give subagents the deadline or any time awareness. They do one unit
+ and return. Time is your concern alone.
- ## Stall Recovery
+ ### 2c. Collect tiny statuses and spot-check (never ingest artifacts — E3)
- If a subagent returns with "nothing to do" or trivially small output:
+ When the batch returns, read each subagent's **tiny status line** — not its
+ artifact, not its transcript. The full result is in the unit file if anyone ever
+ needs it; you do not pull it into your context. Spot-check each claimed commit
+ with `git log` (the commit is there / it is not) — a cheap on-disk check, not a
+ read of the produced content. Subagents hallucinate deliveries; 30 seconds of
+ `git log` saves a wasted iteration. A unit that claims a commit not in `git log`
+ is re-dispatched, not recorded as done. If a subagent tries to hand you the
+ artifact itself, ignore the body and read the digest tail instead.
- 1. **Reframe the angle.** Same goal, different entry point. If you were adding tests for module A, switch to module B.
- 2. **Increase depth.** If surface-level work is done, go deeper — edge cases, error paths, integration points.
- 3. **Broaden scope.** If the narrow interpretation is exhausted, take the wider interpretation of the goal.
- 4. If after 3 consecutive reframes the subagent still returns trivial output, log it in the progress file and continue trying. Do not stop.
+ ### 2d. Consolidate (single source of truth — B4)
- ## What the Subagent Prompt Looks Like
+ Keep your own footprint minimal (E3): the subagents already appended their status
+ lines to the digest and their findings to the cheatsheet. You are confirming, not
+ re-authoring.
- ```
- Goal: <the user's goal>
+ - Own the **`done` transition** in the digest: after the success gate passes, mark
+ the finite-list item `done` and its commit — a one-cell edit, from the tiny
+ statuses you were handed, never by reading the artifacts. The digest is the ONLY
+ place volatile values live. Do not copy counts/hashes into other files (or into
+ `run-card.md`, the static run card) — that O(n) re-sync is exactly the bookkeeping
+ churn this skill forbids.
+ - Confirm each subagent's **cheatsheet append** landed (they append directly to
+ `cheatsheet.md`; parallel appends of a few lines rarely collide, but if two
+ batches raced and an entry is malformed, fix it in one edit). New environment
+ facts must survive to the next batch — that is what kills the rediscovery tax
+ (B2). Same for the one-line **digest status** appends.
+ - **Success gate, per unit — ENFORCED, not optional (B5).** If Phase 1 identified a
+ real success bar (numeric OR textual/qualitative), a unit produced against it may
+ be recorded as `done` in the digest ONLY after it has passed that real bar,
+ scoped to the new unit(s) — never a cheap pass-shaped proxy. A unit that has not
+ yet passed stays `doing`, or is re-dispatched; it is never marked `done` on a
+ proxy. **The bar is applied by a separate, freshly dispatched measurement
+ subagent that did not produce the unit** — never the producer's self-report
+ (dispatch it by passing the path `<harness>/prompts/measurement.md` plus the unit
+ delta — never re-type the template). The measurement subagent writes its full
+ evidence into the unit file and returns only `PASS|FAIL — <one line>`; you gate on
+ that one line, not on its evidence body. If the goal has **no** statable success
+ bar (pure qualitative churn, nothing identified in Phase 1), this gate does not
+ apply — ordinary scoped verification below is sufficient.
+ - **Scoped verification only (B3).** Verify what THIS batch changed — not a
+ from-scratch re-verification of the entire growing corpus. There is no
+ "re-verify everything" iteration.
- Progress file: /tmp/timeboxed-<slug>-<timestamp>.md
- Read this file first to see what was already done. Do not repeat completed work.
+ Then return to the brake check. **Do not** write a between-iteration status
+ message to the user (that is orchestrator authorship and a Red Flag). The digest
+ is the live status page.
- Your task: Do ONE meaningful unit of work toward the goal.
- - Read the progress file before starting.
- - Commit your changes before returning.
- - Do not repeat work already listed in the progress file.
- - Return a structured summary:
- 1. What you did (specific files, specific changes)
- 2. What you committed (commit hash)
- 3. What high-impact work remains for the goal
+ ---
+
+ ## The Stop Machine (closed — these are the ONLY legal stops)
+
+ The run ends when, and only when, at the brake check one of these holds:
+
+ 1. **Deadline passed.** (A batch in flight soft-stops — it finishes and
+ consolidates first.)
+ 2. **User stops.** The user is always a valid brake.
+ 3. **FINITE list exhausted.** Every item on the Phase 0 finite list is `done`
+ and no valid unit remains. Stopping here is **correct** (Iron Law 2) — do not
+ invent work to fill the remaining clock.
+ 4. **No useful unit fits the remaining time.** The smallest genuinely useful unit
+ cannot complete in the time left. Stop rather than dispatch a doomed or
+ trivial unit.
+
+ **No other stop exists.** In particular these are FORBIDDEN, not stops:
+
+ - Stopping an OPEN-ENDED run because progress "looks good" / "the user would be
+ happy" / "diminishing returns." (Iron Law 1 — the original strength, preserved.)
+ - **Idle sleeping** to burn the clock (`sleep 1000` is a firing offense).
+ - **Manufacturing work** — bookkeeping-only iterations, syncing numbers across
+ files, self-referential wrap-up docs, "recording the recording," deadline-edge
+ dispatches with seconds left — to keep the loop looking busy (B4/B6).
+
+ For an OPEN-ENDED run with time left and no obvious unit: that is a **stall**, not
+ a stop — go to Stall Recovery. For a FINITE run with the list exhausted: that is
+ a **stop** (condition 3), immediately.
+
+ ---
+
+ ## The Scaffold Command (one command builds the whole workspace — E4)
+
+ The role prompts and the workspace are NOT embedded in this skill and are NOT
+ hand-typed. They live as template files in this skill's `scaffold/` directory, and
+ ONE command materialises them into a ready-to-run workspace with the run's
+ variables substituted in. This is the concrete form of the write-once/reference-
+ by-path rule (E1): the templates are authored once in `scaffold/`, produced once
+ per run on disk, and thereafter dispatched by path — never re-typed.
+
+ ### Invocation
+
+ ```bash
+ bash <skill-dir>/scaffold/init.sh \
+ --slug <slug> \
+ --goal "<goal>" \
+ --mode <finite|open-ended> \
+ [--duration <e.g. 4h | 90m | 2h30m>] \
+ [--force]
```
- Adapt this to the specific goal and the tools available. The structure is non-negotiable: one unit, commit, summary.
+ - `--slug` — workspace name; the workspace is `~/.harness/timeboxed/<slug>/`.
+ - `--goal` — the one-line goal (substituted into every prompt + the digest header).
+ - `--mode` — `finite` or `open-ended` (Phase 0 classification; drives the stop law).
+ - `--duration` — the timebox when timed (`4h`, `90m`, `2h30m`, or a bare number =
+ hours); the script computes and records the deadline. Omit for an unbounded run.
+ - `--force` — overwrite an existing non-empty workspace. Without it, the command
+ refuses to clobber one (safe to re-run).
- ## Quick Reference
+ It prints every path it created. After it runs, fill the two placeholders it left
+ in `progress.md`: the **concurrency cap** and the **real success bar** (numeric OR
+ textual, or `none`).
- | Item | Value |
+ ### What it creates
+
+ - `prompts/initialiser.md`, `prompts/builder.md`, `prompts/sub-subagent.md`,
+ `prompts/measurement.md` — the four role prompts, `{{HARNESS}}`/`{{GOAL}}`/…
+ substituted. Dispatched BY PATH; never re-typed.
+ - `progress.md` — the digest (single source of truth; header + finite list +
+ iteration log).
+ - `run-card.md` — the static run card (identity + workspace map + resume pointer).
+ - `cheatsheet.md` — seeded with section headings, empty of findings; self-populates.
+ - `units/` — one file per unit at dispatch time.
+
+ ### The four role prompts (full text lives in `scaffold/`)
+
+ - **initialiser.md** — read FIRST by every role. Makes the subagent read the
+ cheatsheet + digest before acting, persist its result to disk, append findings to
+ the cheatsheet and a one-line status to the digest, and return only a tiny
+ status. This is the mechanism that makes shared state grow itself (D1) and keeps
+ the orchestrator's context small (E3).
+ - **builder.md** — owns one unit; may fan out sub-subagents over independent
+ sub-units; produces a committed artifact; writes full detail to its unit file;
+ returns `unit <id>: done, commit <hash>`.
+ - **sub-subagent.md** — owns one sub-unit inside a unit; same persist-and-return-
+ tiny discipline; returns a one-line sub-status.
+ - **measurement.md** — independent gate: did NOT build the unit; applies the real
+ success bar (numeric OR textual/qualitative) scoped to the unit; builds/commits
+ nothing; writes evidence to the unit file; returns `measure <id>: PASS|FAIL —
+ <one line>`.
+
+ To change a role's wording, edit the template in `scaffold/` — never re-type it
+ into a dispatch. Structure to preserve: every role reads the initialiser first;
+ builders persist to disk + return a tiny status; the measurement role judges
+ against the real bar and returns PASS/FAIL + one line, with no artifact and no
+ commit.
+
+ ---
+
+ ## Anti-Drift — the Thoughts That Sabotage a Run
+
+ Every thought on the left will occur to you. Do the right column instead.
+
+ | Thought you're having | What you must do instead |
|---|---|
- | Progress file | `/tmp/timeboxed-<slug>-<timestamp>.md` |
- | Time check | `date +%s`, compare against deadline, BEFORE every dispatch |
- | Subagent scope | ONE meaningful unit of work per dispatch |
- | Termination | Soft stop — finish current subagent, then stop |
- | Minimum iteration output | Committed code or written artifact |
- | Stall recovery | Reframe angle, increase depth, broaden scope |
+ | "These units are independent, I'll just do them one at a time" | No. Independent units go in ONE parallel batch. Serial dispatch of independent work is the dominant loss. (B1) |
+ | "I'll paste the progress so far into the prompt" | Pass the digest PATH. Subagents read it themselves. (C2) |
+ | "I'll write the builder/measurement template into each dispatch" | The scaffold wrote `prompts/` ONCE; every dispatch passes the role-prompt PATH + a short unit delta. Re-typing a template burns your context. (E1/D3) |
+ | "I'll compose this specialized prompt fresh each time I need it" | Write it to `<harness>/prompts/` ONCE, then dispatch it by path in every identical situation. (E1) |
+ | "I'll read the unit's artifact / the full return to see what it did" | No. Read the tiny status + the digest tail. Full results live in the unit file; ingesting them burns your context. (E3) |
+ | "This subagent should just return its whole write-up to me" | No. Subagents persist to disk and return a one-line status; that is what makes your context last. (E3) |
+ | "I'll hand-build the workspace / paste in a starter digest" | Run `scaffold/init.sh` — one command builds prompts/ + digest + run card + cheatsheet + units/. (E4) |
+ | "The success bar is a number, so text-only goals can't be gated" | The bar is numeric OR textual (rubric, acceptance description, judge verdict). The independent gate applies either way. (E2) |
+ | "I'll front-load every gotcha from a test run up front" | Front-load only genuine enablers + the success-bar pilot. Recipes/quirks/gotchas populate the cheatsheet DYNAMICALLY, via the initialiser every subagent reads first. (D1) |
+ | "The subagent can just figure out the environment" | Point it at the cheatsheet FIRST (the initialiser does this); it must not re-pay the discovery tax. (B2) |
+ | "Let me re-read all the ledger files to be safe" | Read the compact digest only. No re-reading the whole corpus. (B3) |
+ | "Let me sync the count/hash into these other files too" | One source of truth — the digest. Never fan volatile values out. (B4) |
+ | "I'll mass-produce now and measure at the end" | Pilot the real measurement FIRST; it gates the loop. (B5) |
+ | "The pilot already proved the measurement works, this unit can pass on a quick proxy" | No. Every unit gated by a real measurement must PASS IT — not a proxy — before being marked done. (B5) |
+ | "The subagent that built the unit can also report it passed the real measurement" | No. Dispatch a SEPARATE measurement subagent; the producer's self-report never gates `done`. (B5) |
+ | "The list is done but there's time left — find more busywork" | If FINITE and exhausted, STOP. Finishing early is correct. (Iron Law 2 / B6) |
+ | "Almost out of time, let me dispatch one more anyway" | If no useful unit fits the remaining time, STOP. No deadline-edge dispatch. (B6) |
+ | "I'll just sleep out the rest of the clock" | Never. Idle sleeping is a firing offense. (B6) |
+ | "I'll quickly run this DB query / make this PR myself" | No. Dispatch a subagent. You author nothing — even under context pressure. (B7) |
+ | "Context is tight, I'll just do it inline this once" | Especially then — inline work burns your scarcest resource. Dispatch. (B7) |
+ | "Infra/scope can wait till later" | Front-load it in the first iteration or it becomes a rework phase. (B8) |
+ | "I'll dispatch all 20 units at once" | Cap the batch at the concurrency limit or they fail silently. |
+ | "This open-ended run looks good enough" | Not your call. Check the clock; if time remains, dispatch. (Iron Law 1) |
+ | "Let me write the user a progress update" | The digest is the status page. Only the final summary goes to the user. |
+ | "I'll grab a bigger model for this hard unit" | Never above your own tier. Orchestrator-tier is the ceiling. (C3) |
+ **If you catch yourself forming any opinion about whether the work is "done" on
+ an OPEN-ENDED run — check the clock and dispatch instead.**
+
+ ## Stall Recovery (OPEN-ENDED runs with time left)
+
+ A batch returning "nothing meaningful to do" on an open-ended goal is a stall,
+ not a stop:
+
+ 1. **Reframe the angle.** Same goal, different entry point (module A exhausted →
+ module B; happy path done → error paths).
+ 2. **Increase depth.** Edge cases, integration points, adversarial inputs,
+ performance.
+ 3. **Broaden scope.** Take the wider interpretation of the goal.
+ 4. **Parallelize wider.** If units were being under-fanned, split the next angle
+ into more independent units and fan out a full batch.
+ 5. After 3 consecutive reframes still returning trivial output, log it in the
+ digest and keep trying different angles. An open-ended run does not halt on a
+ stall.
+
+ (For a FINITE run, "nothing left" is not a stall — it is the exhausted-list stop.
+ Do not reframe a finite goal into busywork.)
+
## Red Flags — STOP and Reread This Skill
- - You're about to write a final summary and there's time left
- - You dispatched a subagent more than 30 minutes ago and it hasn't returned
- - The last 3 iterations have the same summary
- - You're composing a message to the user that isn't the final summary
- - You're about to edit a file, run a test, or explore code yourself
- - You haven't run `date +%s` since the last subagent returned
+ - You're about to edit a file, run a query, or explore code yourself.
+ - You dispatched independent units serially instead of in one parallel batch.
+ - A dispatch pasted the digest or cheatsheet contents inline instead of the path.
+ - You re-typed a role template (initialiser/builder/sub-subagent/measurement) into
+ a dispatch instead of passing its `prompts/…` path plus a short unit delta.
+ - You composed a specialized prompt inline instead of writing it to `prompts/` once
+ and dispatching it by path.
+ - `prompts/` was not produced by the scaffold at setup, so dispatches carry full
+ templates (run `scaffold/init.sh`).
+ - **You read a full artifact, a full transcript, or a large subagent return into
+ your own context** — instead of the tiny status + the digest tail. This is the
+ fastest way to exhaust the one resource this skill protects. (E3)
+ - You tried to front-load every environment quirk from one test run instead of
+ letting the initialiser+cheatsheet loop populate them dynamically.
+ - You're re-reading the whole corpus / all ledgers instead of the compact digest.
+ - You're syncing a count or hash into a second file (including `run-card.md`).
+ - You mass-produced output before piloting the real success bar.
+ - A unit was marked `done` without passing the real success bar (numeric OR
+ textual) — only a cheap proxy check ran.
+ - A unit was marked `done` on the producer's own claim, with no independent
+ measurement subagent dispatched.
+ - The FINITE list is exhausted and you're inventing work to fill the clock.
+ - You ran (or are about to run) `sleep` to pass time.
+ - You're writing a final summary and it's an OPEN-ENDED run with time left.
+ - You put more subagents in a batch than the concurrency cap.
+ - You requested a model more powerful than yourself.
+ - You haven't run `date +%s` since the last batch returned.
+ - A subagent's claimed commit isn't in `git log`.
+ - Front-loading (infra/scope/measurement/sync) got deferred past iteration 1.
+
+ ## Resumption
+
+ If `~/.harness/timeboxed/<slug>/` already exists, reconcile disk against memory —
+ trust disk:
+
+ 1. Read `progress.md`. Note the classification (FINITE/OPEN-ENDED), the deadline,
+ the concurrency cap, and the finite item list if any.
+ 2. **Clock.** If the stored deadline has passed, the resume request is the new
+ mandate: take a fresh duration from it if the user gave one, else ask once.
+ Never resume straight into a summary.
+ 3. **Reconcile git against the digest.** Compare `git log` in the target repo to
+ the commits recorded in the digest. A `timeboxed(<unit-id>): …` commit not
+ recorded in the digest means the run died between the commit and the digest
+ write — record it now (that's why the prefix is mandatory).
+ 4. **Reconcile the finite list.** For a FINITE run, cross-check the item list's
+ `done` marks against actual commits. An item marked `doing` with a matching
+ commit is really `done`; an item marked `doing` with no commit is unclaimed —
+ re-dispatch it.
+ 5. **Reconcile the cheatsheet.** It is cumulative and authoritative; trust it over
+ your memory of the environment.
+ 6. **Reconcile `prompts/`.** Confirm `prompts/` holds the four role files
+ (initialiser, builder, sub-subagent, measurement). If it is missing or partial,
+ re-run the scaffold command (`scaffold/init.sh`, with `--force` if the workspace
+ exists) before dispatching — never resume by re-typing templates into dispatches.
+ 7. Resume at the brake check. The digest is the source of truth for status and
+ volatile values; git is the source of truth for what was actually built; the
+ cheatsheet is the source of truth for the environment. Trust all three over
+ your memory.
+
+ ## Quick Reference
+
+ | Item | Value |
+ |---|---|
+ | Harness dir | `~/.harness/timeboxed/<slug>/` |
+ | Scaffold | `scaffold/init.sh --slug --goal --mode <finite\|open-ended> [--duration]` — ONE command builds the whole workspace from filesystem templates; prints every path; safe to re-run (`--force` to overwrite) |
+ | Classification | FINITE (finite list = stop authority) vs OPEN-ENDED (clock = stop authority) — decided in Phase 0 |
+ | Digest | `progress.md` — compact single source of truth for volatile values; the live status page; orchestrator reads only its TAIL |
+ | Run card | `run-card.md` — static run identity + workspace map + resume pointer; holds NO volatile values |
+ | Cheatsheet | `cheatsheet.md` — populates itself: initialiser makes every subagent read it first + append findings back; grows every batch |
+ | Prompts | `prompts/` — initialiser + 3 role prompts, written ONCE by the scaffold; dispatched BY PATH, never re-typed; write any reusable specialized prompt to disk once too (E1) |
+ | Initialiser | `prompts/initialiser.md` — EVERY subagent reads it first: read shared state, persist result to disk, append findings + a one-line status, return tiny |
+ | Unit files | `units/<unit-id>.md` — one per unit; parallel subagents never share a write target; full results live here, not in the orchestrator's context |
+ | Time check | `date +%s` vs deadline, at the top of EVERY iteration, before the batch |
+ | Iteration | A BATCH: independent units dispatched in parallel (≤ concurrency cap), each sized to a model ≤ your own tier |
+ | Dispatch | A SHORT message: role-prompt PATH + unit-file path + one gap line. Never a re-typed template, digest, or cheatsheet |
+ | Return | TINY status only (`unit X: done, commit <hash>` / `measure X: PASS\|FAIL — one line`); full result is on disk. Orchestrator never ingests artifacts/transcripts (E3) |
+ | Independence rule | Separate files → parallel; shared file → serial round-robin; within a unit, subagents may fan out further |
+ | Front-loading | Scaffold `prompts/` + success-bar pilot + genuine enablers (infra, scope/validity bar IF any, repo sync) in the FIRST iteration(s); recipes/quirks discovered dynamically thereafter |
+ | Success gate | Per unit, ENFORCED: a unit gated by a real bar (NUMERIC or TEXTUAL/qualitative) is marked `done` only after a SEPARATE, independent measurement subagent (never the producer) passes the REAL bar, never a proxy or self-report; no statable bar → gate doesn't apply |
+ | Orchestrator | Pure dispatch: checks time, manages digest+cheatsheet+prompts, plans, dispatches by path, reads tiny statuses — authors NOTHING, ingests no large content, ever |
+ | Model sizing | Smallest model that does the unit well; hard cap at orchestrator's own tier |
+ | Stop (legal only) | Deadline / user / FINITE list exhausted / no useful unit fits remaining time |
+ | Never | Idle sleep, manufactured bookkeeping, deadline-edge dispatch, inline authorship, ingesting a full artifact/return, over-cap batch, up-tier model, re-typing a template into a dispatch |
+ | Soft stop | Deadline mid-batch → in-flight batch finishes and consolidates, then stop |