AI engineering

I Read Omarchy's AGENTS.md So You Don't Have To

Omarchy's own AGENTS.md, skills, and a design doc reviewed by two other vendors' agents — read from the quattro branch, not the README.

TL;DR: Omarchy is a Linux distribution — shell scripts, Lua config, a QML desktop shell — and its AGENTS.md isn’t a “please write clean code” note. It’s a 133-line index into a three-genre docs split, a set of task guides that force agents to screenshot their own UI changes before finishing, and a design doc (plans/dots.md) that shipped after adversarial review from two other vendors’ coding agents. I read AGENTS.md, all seven agents/skills/*.md files, all five plans/*.md design docs, and default/agents/skills/omarchy/SKILL.md on the quattro branch to write this. Every quote below has a blob URL next to it; nothing here is paraphrased from a README.

This is the second one of these

I read Oban’s source code so you don’t have to a week ago — a web-framework-adjacent library, the usual habitat for this series. Omarchy is not: a desktop Linux distribution, shell scripts under bin/, Lua configs, a Quickshell/QML desktop shell, package manifests — no request/response cycle, no obvious slot for an LLM agent. I wanted to know what an agent-first AGENTS.md looks like off the web-app path, on a repo I’ve been daily-driving on an M1 MacBook for the past few days. I’ve also written about what survives in a CLAUDE.md after fifty commits and how to onboard a repo’s first CLAUDE.md; Omarchy’s file is the same genre, at a different scale, on a codebase where “verification” can’t just mean “run the test suite” — some of what it builds only exists once you look at a screen.

What AGENTS.md actually says

AGENTS.md is 133 lines, and it opens by refusing to be the whole document. The first section, “Task Guides,” points anywhere but at itself:

“Deeper instructions for specific kinds of work live in agents/skills/. Read the matching guide before starting”

Seven guides are linked from there — command metadata, install scripts, shell dev, icon fonts, acceptance tests, visual verification, migrations. AGENTS.md is the router, not the manual.

The “Documentation Layout” section explains why the split exists at all, and it’s worth quoting verbatim because it’s the cleanest three-line taxonomy I’ve seen for this problem:

agents/skills/ - task procedure (”do this when doing X”), for anyone working on the codebase” “docs/ - reference on how the system is shaped (file layout, update pipeline, theming, shell architecture), for anyone working on the codebase; skills link here for depth” “manual/ - end-user documentation for using Omarchy, published; never codebase internals”

That’s genre within audience — two trees for people working on the codebase, one wall for everyone else. A skill tells you what to do; a doc tells you how the system is shaped; the manual is a wall nothing internal crosses. Most repos I’ve onboarded conflate the first two — a CONTRIBUTING.md that’s half procedure, half architecture, and stale in both directions within a year. Splitting procedure from reference means the procedure file can stay short and get read every time, while the reference file can be as long as the system actually requires without anyone skipping it out of fatigue.

The rest of AGENTS.md is unglamorous and load-bearing: a Style section pinning bash 5 conditional syntax ([[ ]] for strings, (( )) for numbers) and unquoted variables inside [[ ]]; a Command Naming section that lists twelve common prefixes but explicitly refuses to let a second copy of that list drift out of sync — it tells you to consult GROUP_DESCRIPTIONS in bin/omarchy instead and forbids maintaining “a second exhaustive prefix list” here; a Git section that’s two sentences — atomic commits, succinct messages — and stops.

The skills: seven files, one clearly the largest

agents/skills/ holds seven files: acceptance-tests.md, command-metadata.md, icon-font.md, install-scripts.md, migrations.md, shell-dev.md, visual-verification.md. migrations.md is the longest at 172 lines — more on that below, because it’s the one with the most editorial opinion baked in.

visual-verification.md is the file that made me stop and reread it, because it names a failure mode I’ve watched agents (and juniors) hit repeatedly — treating an artifact as proof of a fix:

“Visual changes must be verified in the running UI in addition to automated tests. Creating an artifact is not sufficient: inspect it for clipping, overlap, incorrect spacing, stale state, focus problems, and visual regressions before finishing.”

The mechanism isn’t a suggestion to “check your work” — it’s a specific command the agent is told to run against its own running desktop: omarchy capture screenshot fullscreen save, or omarchy screenrecord --fullscreen for anything with timing or animation. The agent takes the screenshot, then has to look at it. That’s a meaningfully different instruction than “test your change” — it closes the gap between “the build succeeded” and “the thing on screen is actually right,” which is exactly the gap a diff can’t see.

acceptance-tests.md pushes the graphical suite even further from the coding session: it runs “in a disposable VM through the sibling omarchy-iso repository, not in the active development session.” It also draws a specific line around wtype — the same tool visual-verification.md tells the agent to use for typing into focused controls, and fine for that: an in-guest wtype “is suitable for typing into focused controls,” but it “does not reliably prove that a global Hyprland keybinding works.” Keybindings get exercised with “QMP virtual keyboard input” instead — good for a text field, not proof for a compositor-level shortcut.

How does an agent-maintained repo review its own design docs?

It writes the review into the document, in public, before the code exists. plans/dots.md is a 206-line design doc for a feature that lets Omarchy track and sync a user’s dotfiles, and its opening line is the whole story:

“Revision 3. Rev 2 incorporated adversarial review by codex (xhigh) and grok; rev 3 names the feature dots (omarchy dots ...) and adds the multi-machine sync design.”

Codex and Grok reviewed the plan before it reached revision 3; neither built the agent doing the writing. The repo’s own CLAUDE.md is one line — @AGENTS.md — pointing Claude at the same file the other two agents reviewed against. The doc has a “Rejected approaches” section, and one entry is marked, in the file itself, (rejected in review):

Raw git passthrough / lazygit over $HOME (rejected in review): git clean -fd, reset --hard, or”stage all” against a $HOME work tree is a home-directory-eraser; git add -A can ingest ~/.ssh and the object store into itself… Experts can construct the raw invocation themselves; Omarchy will not bless it.”

That’s not a one-off. plans/ holds five design docs — dots, backup, nix, remote, and server — and I opened all five to check. Every plan that reached a second revision names an adversarial codex review in its first three lines: nix.md and backup.md are both “Revision 2,” both “incorporates adversarial review by codex (xhigh).” remote.md and server.md are both still “Revision 1,” and neither carries a review line at all. That’s a repo convention, not a one-time flex, and nix.md’s summary shows the review had teeth:

“Revision 2. Rev 2 incorporates adversarial review by codex (xhigh): atomicity restated as atomic selection rather than transactional activation, staged switches for major updates, password hashes kept out of the store, a legal-redistribution gate for unfree packages, precise sovereignty boundaries (mise, fwupd, Steam, Cloudflare), a signed release manifest with anti-rollback, source-rebuild proof in the continuity gate, garbage-collection policy, and a substantially hardened migration…”

That’s not a rubber stamp. It’s a list of specific things the plan got wrong before another vendor’s agent read it: passwords sitting somewhere they shouldn’t have, an atomicity claim that didn’t hold, a legal gate that was missing.

The migrations sidebar: what a desktop OS knows that Ecto doesn’t have to

agents/skills/migrations.md describes one-time repair scripts under migrations/*.sh, run by omarchy-migrate — normally during omarchy update — with per-user completion state at ~/.local/state/omarchy/migrations/<filename>. If you’ve run Ecto migrations, the shape is instantly familiar: sequential, timestamp-named files, a ledger that tracks what’s already run. But the file states a rule Ecto’s docs never have to say out loud: “Migrations must be idempotent.”

The reason is structural, not stylistic. Ecto’s ledger is per-database: schema_migrations tracks what’s run against that one database, and a migration only reruns if ecto.rollback deletes its row and down/0 reverses it, or a fresh database applies the whole set from zero. Omarchy’s ledger is per-user, not per-machine: completion state lives under each user’s own ~/.local/state, so the same machine-wide repair can legitimately need to run again for a second account on the same box, because that account’s ledger has never seen it. The file walks through exactly this case: someone who “bypassed the pacman guard” and updated without triggering the migration path, or a second user whose “migration markers are per-user and therefore still missing after another user updated.” A migration that isn’t idempotent silently corrupts one user’s config while an identical account on the same machine stays fine. Ecto assumes one shared source of truth per database; Omarchy assumes as many as it has user accounts per machine.

The privilege line is drawn once, and both audiences read it from the same file

AGENTS.md’s Privileged Commands section doesn’t restate the sudo/pkexec rule — it points at the shipped end-user skill, default/agents/skills/omarchy/SKILL.md, for it. The repo’s own dev guidance and the skill Omarchy ships to end users draw the line from the same source, once:

“For an interactive script or command run in a visible terminal, use sudo for privileged work… Use pkexec only when the caller cannot interact with a terminal or cannot enter a password there, such as a command launched by an agent or a graphical background process.”

The line right after it matters as much as the quote: “Do not replace sudo with pkexec merely because a command changes system state.” The rule isn’t about how much an agent should be trusted; it’s about where a password prompt can physically land. An agent launched in the background has no TTY to type a password into, the same as a systemd unit or a cron job, and pkexec exists for exactly that gap. Omarchy treats “this caller is an agent” as a runtime-environment fact, similar to “no compositor available” in the test suite, not as a lower trust tier needing its own carve-out.

That same instinct for a constrained command surface shows up in plans/dots.md’s bare-repo design too. It runs git “hermetically” against $HOME: synthetic identity, hooks disabled, GIT_CONFIG_GLOBAL=/dev/null so a user’s own git config can’t intercept an automatic commit. It’s the same reasoning that killed the raw-git alternative in review, quoted above, applied to the design that shipped instead.

It’s also what keeps omarchy update self-repairing instead of rotting the way internal developer-platform tooling usually does once the team that built it moves on: a pending migration gets picked up automatically at the next login via a notifier, not silently in the background.

What the numbers say about who’s actually committing

I pulled the 30 most recent commits on quattro via the GitHub API on 2026-09-07. Five people show up in that window, one of them writing two-thirds of it: Ryan Hughes had 20, Spencer Bull had 6, David Heinemeier Hansson had 2, and two others had 1 each. Six of those thirty — exactly a fifth — carried an agent co-author trailer or named an agent in the commit message. I’d be careful extrapolating that ratio backward across the project’s whole history — a snapshot, not a trend line.

What I’d steal for my own AGENTS.md

Ranked by how much I’ll actually use it. First, the docs-by-genre split — procedure in one tree, reference in another, end-user documentation walled off completely. My own CLAUDE.md mixes procedure and reference in one file today; the steal here is splitting it the way Omarchy does, not writing more of it. Second, naming the failure mode instead of the instruction: “creating an artifact is not sufficient” tells an agent why to look at the screenshot, not just that a screenshot is required — that’s the difference between a rule that gets followed and one that gets checked off. Third, writing rejected approaches into the design doc itself, with the reason each one died, so the next agent — or the next engineer — doesn’t waste a cycle re-proposing git add -A over $HOME.

If you’re deciding what your own AGENTS.md should carry before your team’s agents start making the same mistake twice, that’s the kind of scoping conversation I have with clients before they write the first line of it.