All checks were successful
Check / eval (push) Successful in 4m28s
The repo is maintained by agents from multiple vendors, so agent instructions move out of vendor-specific locations into shared, git-tracked markdown: - AGENTS.md is the new entry point for any harness; CLAUDE.md becomes a symlink to it (Claude Code keeps working unchanged). - Skill bodies relocate to agent/: VERIFICATION.md (the enforcement rules, ex .claude/skills/nomarchy), DELEGATION.md (capability tiers light/standard/frontier, scout/runner role contracts, token economy, parallel fan-out — consolidates the CLAUDE.md model table, LOOP.md's economy section, and skill §6.5 into one place; vendor model names survive only in the per-harness mapping table), THEME-DESIGN.md (ex .claude/skills/theme, which previously lacked frontmatter). - .claude/ shrinks to a thin Claude Code adapter: settings, subagent defs, and skill shims that route into agent/. - Maps updated: agent/README.md (instructions vs state vs adapters), docs/README.md, README.md layout tree. Cleanup: stale old_distro .gitignore entry dropped (dir long gone); local result*/__pycache__ artifacts removed; JOURNAL.md rotated (29 recent entries kept, 120 older moved to agent/JOURNAL-ARCHIVE.md, rotation rule documented in the header). Verification: V0 (docs/meta only) — nix flake check --no-build exit 0 with the tracked symlink; grep sweep confirms no vendor model names outside DELEGATION.md's mapping table. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
154 lines
7.9 KiB
Markdown
154 lines
7.9 KiB
Markdown
# 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
|
||
harness- and vendor-agnostic; the same iteration works under any of:
|
||
|
||
- **An interactive self-paced loop** in any agent harness (e.g. `/loop`
|
||
in Claude Code) — the agent iterates until stopped.
|
||
- **Headless** (a one-shot CLI invocation, 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) |
|
||
|
||
Instructions live next to the state: `VERIFICATION.md` (enforcement),
|
||
`DELEGATION.md` (tiers/roles/economy), `GOALS.md`, `THEME-DESIGN.md`.
|
||
|
||
## Model & token economy
|
||
|
||
Spend expensive tokens on judgment, not mechanics. Tiers, roles, and the
|
||
full delegation rules are in **`DELEGATION.md`**; the loop-specific
|
||
habits:
|
||
|
||
- **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
|
||
frontier-tier model running the loop.
|
||
- **Delegate mechanical subtasks down.** 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
|
||
light/standard-tier subagent per `DELEGATION.md`. The strong model
|
||
writes the spec, reviews the result, and owns the commit.
|
||
- **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 touching
|
||
`modules/` or `pkgs/` behavior keep the strong model.
|
||
|
||
## One iteration, step by step
|
||
|
||
### 0. Orient
|
||
1. Read `GOALS.md`, `CONVENTIONS.md`, `MEMORY.md`, the **last 3–5 entries**
|
||
of `JOURNAL.md`, and `BACKLOG.md`. If the top task is product-shaped
|
||
(UX, release bar, day-2 confidence), also read the matching section of
|
||
**`docs/VISION.md`** — do not invent work from VISION; only execute
|
||
BACKLOG items. Map of docs vs agent state: `docs/README.md`,
|
||
`agent/README.md`.
|
||
2. `git pull --ff-only` (skip silently if offline). Confirm you are on
|
||
`main` with a clean tree. **A dirty tree you didn't create → stop and
|
||
report; never stash or discard someone else's work.**
|
||
3. Sanity baseline: if the last journal entry reports a red
|
||
`nix flake check`, or you have any reason to suspect breakage, run
|
||
`nix flake check --no-build` first. **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 in
|
||
`HARDWARE-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.md` now, 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 `main` and `git push` (Bernardo's standing workflow).
|
||
- **Never:** force-push; touch the `v1` branch or any branch/tag you
|
||
didn't create; commit secrets or binaries; run `nix flake update`
|
||
unless the task is explicitly a lock bump; delete themes, wallpapers,
|
||
or user-facing assets without the backlog saying so.
|
||
|
||
### 5. Record
|
||
1. Mark the task in `BACKLOG.md` (move to its ✓ line or delete, per that
|
||
file's rules).
|
||
2. Append a `JOURNAL.md` entry (template in that file).
|
||
3. 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.
|