Add docs/VISION.md (product themes, v1.0 bar, agent slice hints) and README maps under docs/ and agent/. Point ROADMAP, BACKLOG, LOOP, CLAUDE, HARDWARE, and the root README at the split: VISION = intent, BACKLOG = executable queue, ROADMAP = design history, .claude = harness only. Mark v1.0 track in BACKLOG PROPOSED for human triage.
7.8 KiB
The loop — autonomous iteration protocol
How an AI agent works on Nomarchy unattended. One iteration = pick one task, do it, verify it, commit it, record it. The protocol is runner-agnostic; the same iteration works under any of:
- Interactive
/loopin a Claude Code session in this repo — the agent self-paces iterations until stopped. - Headless (
claude -p, cron/systemd-timer) — one invocation runs one iteration (or a small fixed number) and exits. - A fresh manual session — a human says "do a loop iteration"; the files below carry all the state, so any session can pick up where the last left off.
All loop state lives in this directory, git-tracked. There is no state outside the checkout (the distro's own philosophy, applied to its agents).
The files
| File | Role | Who writes it |
|---|---|---|
GOALS.md |
North star + quality bars + non-goals | Human (agents propose edits) |
BACKLOG.md |
Prioritized task queue (NOW/NEXT/LATER/PROPOSED/DECISIONS) | Both — see its header rules |
JOURNAL.md |
Append-only iteration log | Agents |
MEMORY.md |
Curated durable lessons/gotchas | Agents (curated, not append-only) |
HARDWARE-QUEUE.md |
Pending on-hardware checks only Bernardo can run | Agents append, human checks off |
CONVENTIONS.md |
Repo/design conventions to follow while coding | Human (agents propose edits) |
Model & token economy
Spend expensive tokens on judgment, not mechanics.
- Plan and reason on the strong model. Orientation, task selection, design, debugging, Nix eval semantics, verification judgment, and anything that would land in a commit unreviewed stay with the top-tier model running the loop (Fable 5).
- Delegate mechanical subtasks to cheaper models. When a subtask is
fully specified and needs no design judgment — grep/audit sweeps,
README-option-table reconciliation, a repeated edit applied across
files, summarizing long logs or check output — hand it to a subagent
with a
modeloverride:haikufor search/summarize/audit,sonnetfor routine well-specified edits. The strong model writes the spec, reviews the result, and owns the commit. Only delegate when writing the spec is cheaper than doing the work — a spawned agent starts cold and must re-derive context. - Read narrowly. Step 0's list is the whole orientation read (the last 3–5 entries of the journal, never the full file). Read large files by section, don't re-read what's already in context, and tail build/check logs instead of dumping them.
- Write tersely. Journal entries follow the template and no more; commit bodies state what/why/tier, not a narrative.
- Headless runners may run whole low-stakes iterations (QA sweeps,
docs-drift passes) on a cheaper
--model; iterations touchingmodules/orpkgs/behavior keep the strong model.
One iteration, step by step
0. Orient
- Read
GOALS.md,CONVENTIONS.md,MEMORY.md, the last 3–5 entries ofJOURNAL.md, andBACKLOG.md. If the top task is product-shaped (UX, release bar, day-2 confidence), also read the matching section ofdocs/VISION.md— do not invent work from VISION; only execute BACKLOG items. Map of docs vs agent state:docs/README.md,agent/README.md. git pull --ff-only(skip silently if offline). Confirm you are onmainwith a clean tree. A dirty tree you didn't create → stop and report; never stash or discard someone else's work.- Sanity baseline: if the last journal entry reports a red
nix flake check, or you have any reason to suspect breakage, runnix flake check --no-buildfirst. A red baseline preempts the backlog — fixing it is this iteration's task.
1. Pick exactly one task
- Take the topmost actionable item: NOW before NEXT; never LATER unless NOW and NEXT are empty or all blocked.
- Actionable means: not
[blocked:hw](those wait inHARDWARE-QUEUE.md), not[human](decisions), and small enough to finish + verify in one iteration. If the top item is too big, split it in BACKLOG.md (that edit is part of the iteration) and take the first slice. - Never implement anything from PROPOSED — those await human triage.
- If nothing is actionable, do a QA sweep instead: run the full check
suite, hunt drift (README option tables vs the live
nomarchy.*surface, template drift, dead code), deepen a VM test, or research and write up a PROPOSED item. An iteration that only improves the backlog is a valid iteration. If even that yields nothing, journal it and stop — do not manufacture churn.
2. Work
- Keep the diff focused on the task. Unrelated fixes you trip over become PROPOSED/NOW entries, not scope creep.
- Mechanical, fully-specified sub-steps go to a cheaper model (see Model & token economy above); design and review stay here.
- Follow
CONVENTIONS.md. Match the surrounding hand-formatting; never run a formatter. - New gotcha discovered the hard way → one line in
MEMORY.mdnow, while it's fresh.
3. Verify — the ladder
Climb as high as the change warrants and your environment allows; record the tier reached in the commit body and journal entry.
| Tier | What | When required |
|---|---|---|
| V0 | nix flake check --no-build (+ bash -n / py_compile for scripts) |
Every change, no exceptions |
| V1 | Build the touched output: system.build.toplevel, the HM generation, the ISO, or the package |
Anything beyond docs/comments |
| V2 | VM: a checks.* runNixOSTest (add one if the change is guardable), or boot tools/test-live-iso.sh / tools/test-install.sh |
Behavioral changes — services, boot, installer, session |
| V3 | Real hardware | Cannot be done by the agent → append to HARDWARE-QUEUE.md with exact test steps |
The honesty rule governs: a visual/interactive change verified only to V1
is not done — it ships as "V1-verified, V2/V3 pending" with the pending
check queued. Prefer adding a permanent checks.* test over a one-off
manual VM poke when the behavior is testable headlessly (see MEMORY.md for
the reusable recipes).
4. Commit + push
- Style: match the log —
feat(scope): …,fix(scope): …,test(scope): …,docs(scope): …. Body explains what/why + the verification tier reached and what remains. - Include the
agent/bookkeeping updates (backlog/journal/memory/queue) in the same commit as the change they describe. - Commit directly on
mainandgit push(Bernardo's standing workflow). - Never: force-push; touch the
v1branch or any branch/tag you didn't create; commit secrets or binaries; runnix flake updateunless the task is explicitly a lock bump; delete themes, wallpapers, or user-facing assets without the backlog saying so.
5. Record
- Mark the task in
BACKLOG.md(move to its ✓ line or delete, per that file's rules). - Append a
JOURNAL.mdentry (template in that file). - Queue any V3 checks in
HARDWARE-QUEUE.md.
6. Pace (self-paced runners only)
Under /loop, continue to the next iteration while tasks remain
actionable and checks stay green. Stop the loop when: nothing is
actionable, the same task has failed twice (journal the failure analysis
and mark the item [stuck]), or a [human] decision blocks everything
remaining.
Stop-and-escalate conditions (any runner)
Write a journal entry + a BACKLOG note, then stop, when:
- A fix would require touching
v1, force-pushing, or a nixpkgs release jump. - The working tree contains uncommitted work you didn't create.
- A task turns out to need a design decision Bernardo hasn't made → move it to Decisions in BACKLOG.md with the options laid out.
- Two consecutive iterations failed on the same task (
[stuck]). - Anything would delete or rewrite user data, git history, or the state file schema in a non-backward-compatible way.