Files
Nomarchy/agent/LOOP.md
Bernardo Magri 6d70bba8e6 feat(agent): autonomous-loop infrastructure + roadmap rework
A git-tracked agent/ directory so AI agents can iterate on the distro
unattended (runner-agnostic: /loop, headless claude -p, or a fresh
manual session — all state lives in the checkout, per the distro's own
philosophy):

- LOOP.md — the iteration protocol: orient → pick one BACKLOG task →
  verify up the V0–V3 ladder → commit+push main → record. Safety rails
  (v1 untouchable, no force-push, no surprise lock bumps) and
  stop-and-escalate conditions.
- BACKLOG.md — the forward half of docs/ROADMAP.md reworked into a
  prioritized queue (5 NOW / 6 NEXT / LATER / PROPOSED / Decisions);
  ROADMAP.md stays the design/decision record + shipped log.
- GOALS.md — the four pillars (stable > reproducible/zero-hidden-state >
  effortless config > beautiful), quality bars, non-goals.
- CONVENTIONS.md — coding/design rules (in-flake state, menu placement,
  Waybar whole-swap parity, toggle-vs-package, no formatter).
- MEMORY.md — curated hard-won lessons (VM recipes, btrfs-assistant
  segfault watch, rofi/WirePlumber/hyprlock gotchas).
- HARDWARE-QUEUE.md — every pending V3 on-hardware check collected from
  the ROADMAP, with exact steps, split by machine.
- JOURNAL.md — append-only iteration log, seeded with this bootstrap.

Plus a root CLAUDE.md entry point and README/ROADMAP pointers.

Verified: V0 — docs-only; nix flake check --no-build green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 08:51:11 +01:00

6.0 KiB
Raw Blame History

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 /loop in 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)

One iteration, step by step

0. Orient

  1. Read GOALS.md, CONVENTIONS.md, MEMORY.md, the last 35 entries of JOURNAL.md, and BACKLOG.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.
  • 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.