# 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 a highly curated Hyprland desktop on a strictly declarative, flake-based foundation. It targets power users who want a polished, reproducible desktop environment.

Concretely:

- A flake at the repo root exposes `nixosModules.system` (foundational OS modules) and `nixosModules.home` (apps + desktop), plus three `nixosConfigurations` (`nomarchy-installer`, `nomarchy-live`, `default`) and standalone `homeConfigurations`.
- Downstream users get the distro by importing `nomarchy.nixosModules.system` and `nomarchy.nixosModules.home` from their own `/etc/nixos/flake.nix`. The Nomarchy installer generates that flake for them; an existing-NixOS user can hand-write it (see `docs/MIGRATION.md`).
- A bash/`gum` TUI installer lives in `installer/install.sh` (~1100 lines). It auto-detects hardware via `installer/hardware-db.sh` (DMI + `lspci` + `BAT*` sysfs), prompts for the rest, and generates `flake.nix`, `system.nix`, `home.nix`, and `hardware-selection.nix` into `/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:

1. `README.md` — public face.
2. `docs/STRUCTURE.md` — directory layout and module logic.
3. `docs/OPTIONS.md` — every `nomarchy.*` option a downstream flake can set.
4. `docs/ROADMAP.md` — what's planned. **This is your work queue.**
5. `docs/SCRIPTS.md` — the script & menu audit table (Pillar 3 of the roadmap).
6. `docs/MIGRATION.md` — how an existing NixOS install becomes Nomarchy.
7. `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.
    overrides.nix     nomarchy.overrides.* (reserved; currently no-op — see ROADMAP).
    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 (nomarchy-installer, nomarchy-live/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` (+ optional `config/`), import it from `features/default.nix`.
- A new system service → `core/system/<name>.nix`, import from `core/default.nix`.
- A new toggle → add to `core/system/options.nix` or `core/home/options.nix`, wire it into the relevant module, document it in `docs/OPTIONS.md`.

---

## 3. Guardrails (non-negotiable unless the user overrides)

These are inherited from the established Nomarchy conventions. Violating them is a bug.

1. **Declarative-first.** No imperative state in `core/`. Mutable state goes in `~/.config/nomarchy/state.json` or in NixOS / home-manager options.
2. **Downstream-flake friendly.** Every behavior toggle is a `nomarchy.*` option documented in `docs/OPTIONS.md`. Adding a feature without a corresponding option is a bug.
3. **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.
4. **`lib.mkDefault` everywhere user might override.** If a downstream `system.nix` would reasonably want to change something Nomarchy sets, set it with `lib.mkDefault`. If it must not be overridden, use `lib.mkForce` and explain why in a comment.
5. **Reuse before invent.** ~155 `nomarchy-*` scripts already exist across `core/system/scripts/`, `features/scripts/utils/`, `themes/engine/scripts/`. Grep before writing a new one.
6. **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.
7. **No backwards-compat shims.** If you remove a thing, remove it everywhere. No re-exports, no `// removed` markers.
8. **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.md` so 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`](SCRIPTS.md) and is regenerated by:

```bash
./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:

1. **Understand the current state first.**
   - `git status` and `git log -5` so you know what's just landed and what's in flight.
   - Read the relevant files. Don't infer.
2. **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.
3. **Reuse existing options and scripts.** Grep `core/system/options.nix`, `core/home/options.nix`, and the three script directories before adding anything.
4. **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. `formFactor` is referenced from `laptop.enable`'s row) |
   | A `nomarchy-*` script (added, removed, renamed) | `docs/SCRIPTS.md` — the pre-commit hook regenerates it; verify it's staged. If `core.hooksPath` isn't set, run `./bin/utils/nomarchy-docs-scripts --out docs/SCRIPTS.md` manually. |
   | A keybinding (`bindd =` / `bindeld =`) under `core/home/config/.../hypr/` | `docs/KEYBINDINGS.md` — regenerate via `./bin/utils/nomarchy-docs-keybindings --out docs/KEYBINDINGS.md`; spot-check the README highlights still hold |
   | A directory was added/removed/renamed under `core/`, `features/`, `themes/`, `hosts/`, `installer/`, `lib/`, `bin/`, or `docs/` | `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 onboarding |
   | A feature module's behavior changed in a way an existing user would notice (a default flipped, a service started/stopped, a key remapped) | `README.md` if it's user-visible at the marketing level; otherwise just `docs/OPTIONS.md` |
   | An installer prompt added/removed/reordered, or generated-file shape changed | `docs/MIGRATION.md` if it affects hand-written `flake.nix` setups; `installer/install.sh` heredoc comments if a generated file's shape changed |
   | A theme palette added/removed, or the theming engine's contract changed | `docs/creating-themes.md` and the palette count in `README.md` |
   | A 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.md` and `docs/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.
5. **Verify the change evaluates** (cheap, do this before declaring done):
   ```bash
   nix --extra-experimental-features 'nix-command flakes' flake check --no-build
   bash -n installer/install.sh   # if you touched it
   ```
   `flake check` only evaluates the four *default* configs — it never flips a `nomarchy.*` toggle. If you touched anything that only fires when a toggle is enabled (impermanence, a preset, an opt-in feature, the per-palette system theme), also run the toggle matrix, which layers each opt-in scenario onto the default config and forces it:
   ```bash
   ./bin/utils/nomarchy-eval-matrix
   ```
   When you **add or rename an opt-in `nomarchy.*` option**, fold it into the relevant combined scenario in the `scenarios` attrset in that script (the scenarios bundle many compatible toggles per eval to stay fast on the CI runner) — otherwise the new surface is unverified and the next eval-time bug in it ships silently (this is exactly how the impermanence assertion and the vscode option rename reached `main`). The matrix also runs in CI (`.gitea/workflows/check.yml`).
   First clone? Enable the repo's pre-commit hook so `docs/SCRIPTS.md` regenerates whenever you add/modify/remove a `nomarchy-*` script:
   ```bash
   git config core.hooksPath .githooks
   ```
   For installer changes, also do a dry-run end-to-end:
   ```bash
   sudo /etc/install.sh --dry-run    # in the live ISO or VM
   ```
   For 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.
6. **Commit narrowly.** One concept per commit. The commit subject is `<type>: <imperative summary>` (`feat:`, `fix:`, `docs:`, `chore:`). The body explains the why.
7. **Push only when the user asks.** Local commits are free; pushing publishes.

---

## 6. Patterns worth knowing

### Adding a new option

```nix
# 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:

```nix
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:

1. Drop the file in `features/scripts/utils/` or `core/system/scripts/`.
2. `chmod +x` it (it'll be wrapped with the right deps automatically).
3. Reference the right `categoryDeps` group in `features/scripts/default.nix` if it needs new tools.
4. 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 -rf` outside obvious sandbox dirs.
- Touch `flake.lock` unless the user asked to update inputs.
- Bump `nixpkgs` major 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 in `MEMORY.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 status` is clean (or has one obvious WIP commit on a `wave/...` 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.
