- Rename installerIso and installerIsoGraphical to nomarchy-installer and nomarchy-live. - Update host configurations with proper Nomarchy branding and volume IDs. - Fix nomarchy-test-live-iso QEMU launch by using -drive if=pflash for UEFI firmware. - Add nomarchy-build-live-iso utility script. - Scrub remaining Omarchy references in Plymouth, installer messages, and docs. - Regenerate docs/SCRIPTS.md to reflect new and renamed utilities.
249 lines
15 KiB
Markdown
249 lines
15 KiB
Markdown
# 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.
|
||
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 (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
|
||
```
|
||
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.
|