Files
Nomarchy/agent/LOOP.md
Bernardo Magri 4c656b1e73
All checks were successful
Check / eval (push) Successful in 4m45s
chore(agent): sync-sweep rule on task completion + apply it; zram user docs
New standing rule (LOOP.md §5 step 4, echoed in AGENTS.md): when a task
ships, grep its number/feature name across agent/ and docs/ and update
or delete every cross-reference it made stale, in the same commit —
including pruning checked-off [x] HARDWARE-QUEUE entries whose outcome
is recorded (journal/ROADMAP; git history is the archive).

First application: BACKLOG PROPOSED groomed (the auto time-of-day theme
pitch was stale — shipped as #79; shipped/promoted placeholder lines
removed; v1.0 pointer rewritten; FUTURE promoted-stub dropped);
HARDWARE-QUEUE pruned of 29 checked entries (363→253 lines) with
dangling references reworded and the prune rule documented in its
header.

Also closes the zram user-doc gap: README §3 now documents the zram
default (zstd/50%/prio 100), hibernation working out of the box on new
installs, and the MIGRATION.md runbook for existing machines.

Verification: V0 (docs/meta only).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 09:20:54 +01:00

8.4 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 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 35 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 35 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.
  4. Sync sweep. Grep the item's number and feature name across agent/ and docs/ and update or delete every cross-reference the ship made stale: the PROPOSED pitch that spawned it (and BACKLOG's v1.0 pointer), HARDWARE-QUEUE entries it supersedes, ROADMAP/README/ docs mentions of the old behavior. While there, prune checked-off [x] HARDWARE-QUEUE entries whose outcome is already recorded (journal/ROADMAP — git history is the archive). A shipped item must leave no stale pointer behind; the sweep rides in the same commit.

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.