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.mdisn’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 readAGENTS.md, all sevenagents/skills/*.mdfiles, all fiveplans/*.mddesign docs, anddefault/agents/skills/omarchy/SKILL.mdon thequattrobranch 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$HOMEwork tree is a home-directory-eraser;git add -Acan ingest~/.sshand 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
sudofor privileged work… Usepkexeconly 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.