Adds an 8th guardrail and replaces §5.4 with an explicit "if you change X, update Y" mapping covering options, scripts, keybindings, structure, installer, themes, roadmap, conventions, and flake-level changes. Each row names the doc to touch. The closing line forces a one-pass check before declaring a change done — eliminates "docs catch-up" PRs and keeps the distro and its docs from drifting apart.
15 KiB
Agent Instructions for Nomarchy
You're an AI coding agent picking up the Nomarchy project. This document gives you everything you need to be useful from the first turn: what Nomarchy is, how it's organized, what the rules are, and how to actually pick up the next piece of work.
If anything below conflicts with what the user just said, the user wins. If anything below conflicts with the existing code, read the code — these notes can rot.
1. What Nomarchy is
Nomarchy is a NixOS-based distribution that ships the Omarchy Hyprland desktop on a strictly declarative, flake-based foundation. It targets power users who want the polish of Omarchy without giving up reproducibility.
Concretely:
- A flake at the repo root exposes
nixosModules.system(foundational OS modules) andnixosModules.home(apps + desktop), plus threenixosConfigurations(installerIso,installerIsoGraphical,default) and standalonehomeConfigurations. - Downstream users get the distro by importing
nomarchy.nixosModules.systemandnomarchy.nixosModules.homefrom their own/etc/nixos/flake.nix. The Nomarchy installer generates that flake for them; an existing-NixOS user can hand-write it (seedocs/MIGRATION.md). - A bash/
gumTUI installer lives ininstaller/install.sh(~1100 lines). It auto-detects hardware viainstaller/hardware-db.sh(DMI +lspci+BAT*sysfs), prompts for the rest, and generatesflake.nix,system.nix,home.nix, andhardware-selection.nixinto/mnt/etc/nixos/. - The desktop is Hyprland + waybar + walker + a curated theming engine (
themes/) with 22 palettes wired through Stylix.
Read in this order to come up to speed:
README.md— public face.docs/STRUCTURE.md— directory layout and module logic.docs/OPTIONS.md— everynomarchy.*option a downstream flake can set.docs/ROADMAP.md— what's planned. This is your work queue.docs/SCRIPTS.md— the script & menu audit table (Pillar 3 of the roadmap).docs/MIGRATION.md— how an existing NixOS install becomes Nomarchy.docs/creating-themes.md— when palette work comes up.
2. How the repo is organized
core/ Foundational OS + user defaults. Don't put apps here.
system/ NixOS modules, all imported via core/default.nix.
options.nix nomarchy.system.* options live here.
hardware.nix nomarchy.hardware.* options + module wiring.
network.nix NetworkManager, DNS, networkmanagerapplet.
impermanence.nix Erase-Your-Darlings root wipe.
scripts/ Low-level system scripts (battery, brightness, hardware).
home/ Home Manager modules.
options.nix Most home-side nomarchy.* options.
behavior.nix nomarchy.behavior.* (deploy-default-config toggles).
overrides.nix File-based overrides from ~/.config/nomarchy/overrides/.
config/ Plain dotfiles symlinked into ~/.config.
features/ Apps and desktop components. Add new apps here.
apps/ One subdir per app (alacritty, btop, kitty, vscode.nix, …).
desktop/ hyprland, waybar, idle.nix, nightlight.nix, …
scripts/ User-PATH scripts, battery-monitor user service.
utils/ ~68 nomarchy-* user scripts.
default.nix Packages them as nomarchy-system-scripts derivation.
themes/ Theme engine + 22 palettes.
engine/ Loader, Stylix glue, switcher, scripts (font, theme, wallpaper).
palettes/ One subdir per palette (summer-night, tokyo-night, …).
hosts/ ISO host configs (installerIso, installerIsoGraphical/live-iso).
installer/ The bash/gum TUI + disko configs + hardware-db.sh.
lib/ Shared Nix helpers (state schema, color resolution, paths).
docs/ All long-form documentation. README.md stays at repo root.
bin/ Convenience wrappers for testing (nomarchy-test-installer, …).
When you add a new feature:
- A new app →
features/apps/<name>/default.nix(+ optionalconfig/), import it fromfeatures/default.nix. - A new system service →
core/system/<name>.nix, import fromcore/default.nix. - A new toggle → add to
core/system/options.nixorcore/home/options.nix, wire it into the relevant module, document it indocs/OPTIONS.md.
3. Guardrails (non-negotiable unless the user overrides)
These are inherited from the established Nomarchy conventions. Violating them is a bug.
- Declarative-first. No imperative state in
core/. Mutable state goes in~/.config/nomarchy/state.jsonor in NixOS / home-manager options. - Downstream-flake friendly. Every behavior toggle is a
nomarchy.*option documented indocs/OPTIONS.md. Adding a feature without a corresponding option is a bug. - Opt-in by default. New features default off (or default to existing behavior). The installer can flip defaults for the user being installed, but the option must read sensibly when set by hand.
lib.mkDefaulteverywhere user might override. If a downstreamsystem.nixwould reasonably want to change something Nomarchy sets, set it withlib.mkDefault. If it must not be overridden, uselib.mkForceand explain why in a comment.- Reuse before invent. ~155
nomarchy-*scripts already exist acrosscore/system/scripts/,features/scripts/utils/,themes/engine/scripts/. Grep before writing a new one. - No comments that narrate. Don't write comments explaining what the code does. Only write a comment when the why is non-obvious — a hidden constraint, a subtle invariant, a workaround.
- No backwards-compat shims. If you remove a thing, remove it everywhere. No re-exports, no
// removedmarkers. - Docs ride with the change. Every change ships in the same commit as its doc updates — no follow-up "docs catch-up" PRs. The mapping is in §5.4 below; if a change touches something in that table and the matching doc didn't move with it, the change is incomplete.
4. How to find work to do
The roadmap (docs/ROADMAP.md) is the source of truth. It has three columns and seven pillars.
Default rule: prefer items in the Now column. Pick whichever matches the user's current ask, or the smallest one if no ask is in flight.
If the user asked for something not in the roadmap:
- Do the work.
- After it ships, propose a one-line addition to
docs/ROADMAP.mdso future you doesn't re-discover it.
If the user asks "what's next?", reply with the Now column items in 2–3 sentences and let them pick.
The script & menu audit (Pillar 3)
This is the largest single open work item. Phase A (inventory) hasn't run yet; docs/SCRIPTS.md is just scaffolding. The user explicitly flagged this pillar as important.
Phase A shipped. The inventory lives at docs/SCRIPTS.md and is regenerated by:
./bin/utils/nomarchy-docs-scripts --out docs/SCRIPTS.md
It tags every row with one of kept / unused? / missing. Phase B is the per-batch porting/removal: pick ~10 rows tagged missing or unused?, decide one of port-from-omarchy / delete-dead / stub-with-notify, and ship as one PR per batch on a wave/audit-<batch> branch. Each PR description should reference the rows it closes; reviewers spot-check that every caller of a removed/renamed script is updated.
5. Workflow per change
Steps you should follow for any non-trivial change:
-
Understand the current state first.
git statusandgit log -5so you know what's just landed and what's in flight.- Read the relevant files. Don't infer.
-
Plan if it's non-trivial. Tasks with three or more steps benefit from a TaskCreate list. Tasks that touch the architecture benefit from plan mode.
-
Reuse existing options and scripts. Grep
core/system/options.nix,core/home/options.nix, and the three script directories before adding anything. -
Touch the docs in the same change. Use this table — if your change matches a row, the doc edit ships in the same commit. No exceptions, no follow-ups.
If you change… Update in the same commit A nomarchy.*option (added, removed, renamed, default flipped, type changed, description changed)docs/OPTIONS.md(matching row) and any other row that mentions it (e.g.formFactoris referenced fromlaptop.enable's row)A nomarchy-*script (added, removed, renamed)docs/SCRIPTS.md— the pre-commit hook regenerates it; verify it's staged. Ifcore.hooksPathisn't set, run./bin/utils/nomarchy-docs-scripts --out docs/SCRIPTS.mdmanually.A keybinding ( bindd =/bindeld =) undercore/home/config/.../hypr/docs/KEYBINDINGS.md— regenerate via./bin/utils/nomarchy-docs-keybindings --out docs/KEYBINDINGS.md; spot-check the README highlights still holdA directory was added/removed/renamed under core/,features/,themes/,hosts/,installer/,lib/,bin/, ordocs/docs/STRUCTURE.md(tree + module logic prose) and §2 of this file (docs/AGENT.md) if the change is structural enough to affect new-agent onboardingA feature module's behavior changed in a way an existing user would notice (a default flipped, a service started/stopped, a key remapped) README.mdif it's user-visible at the marketing level; otherwise justdocs/OPTIONS.mdAn installer prompt added/removed/reordered, or generated-file shape changed docs/MIGRATION.mdif it affects hand-writtenflake.nixsetups;installer/install.shheredoc comments if a generated file's shape changedA theme palette added/removed, or the theming engine's contract changed docs/creating-themes.mdand the palette count inREADME.mdA roadmap item shipped Move the entry to the Shipped section at the bottom of docs/ROADMAP.md. Don't delete — that's our changelog.A roadmap item discovered (new scope) Add a one-line row to Now, Next, or Later in docs/ROADMAP.md. Don't tell the user verbally and forget.A workflow / convention / guardrail you'd want a future agent to follow docs/AGENT.md(this file).A new flake input, output, or major architectural decision docs/STRUCTURE.mdanddocs/AGENT.md§1.Before declaring done, do one explicit pass: did the change cross any row above? If yes, is the matching doc edit staged? If you can't answer "yes" to both, you're not done.
-
Verify the change evaluates (cheap, do this before declaring done):
nix --extra-experimental-features 'nix-command flakes' flake check --no-build bash -n installer/install.sh # if you touched itFirst clone? Enable the repo's pre-commit hook so
docs/SCRIPTS.mdregenerates whenever you add/modify/remove anomarchy-*script:git config core.hooksPath .githooksFor installer changes, also do a dry-run end-to-end:
sudo /etc/install.sh --dry-run # in the live ISO or VMFor waybar / Hyprland visual changes, the only reliable check is booting the live ISO with
nomarchy-test-live-iso. If you can't boot it, say so rather than claiming success. -
Commit narrowly. One concept per commit. The commit subject is
<type>: <imperative summary>(feat:,fix:,docs:,chore:). The body explains the why. -
Push only when the user asks. Local commits are free; pushing publishes.
6. Patterns worth knowing
Adding a new option
# core/system/options.nix (or core/home/options.nix for home-side)
mything.enable = lib.mkEnableOption ''
Concise description that reads well in `nix eval`. Mention any
pre-conditions (groups, kernel modules, hardware needed).
'';
Then wire it inside a config = lib.mkIf cfg.mything.enable { ... } block and document it in docs/OPTIONS.md.
Filtering modules conditionally
We do this for waybar (drop battery on desktop) in features/desktop/waybar/default.nix:25-39. Pattern:
let
rawSettings = builtins.fromJSON (builtins.readFile configFile);
laptopOnly = [ "battery" "custom/battery" ];
filterModules = mods:
if config.nomarchy.formFactor == "laptop" then mods
else builtins.filter (m: !(builtins.elem m laptopOnly)) mods;
settings = rawSettings // {
modules-right = filterModules (rawSettings.modules-right or []);
modules-center = filterModules (rawSettings.modules-center or []);
modules-left = filterModules (rawSettings.modules-left or []);
};
in { ... }
Form-factor (laptop vs desktop)
nomarchy.system.formFactor and nomarchy.formFactor are the two halves of the same flag (system + home). Default "laptop". The installer auto-detects via compgen -G "/sys/class/power_supply/BAT*" and writes the explicit value into both generated files. Use this option to gate any laptop-only UI / service.
State (state.json)
Theme, font, wallpaper, and a few feature toggles live in ~/.config/nomarchy/state.json so they can change without a rebuild. Schema is in lib/state-schema.nix. The Home Manager evaluator reads it via lib/default.nix. Don't add new state without justifying it — most "state" should be a NixOS option instead.
Scripts derivation
User-PATH scripts ship via nomarchy-system-scripts (core/system/scripts-derivation.nix) plus the per-category dependencies declared in features/scripts/default.nix:categoryDeps. When you add a script:
- Drop the file in
features/scripts/utils/orcore/system/scripts/. chmod +xit (it'll be wrapped with the right deps automatically).- Reference the right
categoryDepsgroup infeatures/scripts/default.nixif it needs new tools. - Test that
which <script>resolves after a rebuild.
Heredocs in installer/install.sh
The system-config generator uses unquoted heredocs (<< EOF) so $VAR expands. The home-config generator now also uses unquoted heredocs — any literal $ or backtick in the body must be escaped (see installer/install.sh:1043-1131). If you forget and the install fails with a "unbound variable" or unexpected command output, that's why.
7. Things to never do without explicit user OK
git push --force,git reset --hard,git clean -f,rm -rfoutside obvious sandbox dirs.- Touch
flake.lockunless the user asked to update inputs. - Bump
nixpkgsmajor version (e.g.25.11→26.05) — that's a release decision. - Add a new flake input. They're load-bearing across all three host configurations.
- Skip pre-commit hooks (
--no-verify). - Ship a feature without a
nomarchy.*option to gate it. - Ship a removal without updating callers (grep first).
- Mock the database / external services in tests — use the real thing.
8. Where to put your own notes
- Long-lived docs →
docs/. - Working notes / per-session plans →
~/.claude/plans/. Don't commit them. - Memory about the user, this project, or process preferences → your harness's memory directory at
/home/bernardo/.claude/projects/-home-bernardo-Projects-nomarchy/memory/. Each entry gets a frontmatter file plus a one-line index entry inMEMORY.md.
9. The shape of a good handoff
Before you stop, leave the next agent (or future you) something to land on:
- The roadmap is up to date — items you shipped are in Shipped.
git statusis clean (or has one obvious WIP commit on awave/...branch).- If you discovered new scope, you logged it as a roadmap row, not a verbal heads-up.
- Any plan file you wrote in
~/.claude/plans/is named after the task, not the date. - The user's last message has been answered concisely.
That's it. The roadmap tells you what; this file tells you how. Go pick a Now item.