diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..0a6c9f6 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,51 @@ +# Rigging + +Multi-repo NixOS + Nomad infrastructure management CLI and flake-parts module. + +## What this is + +Three components: + +1. **Flake-parts module** (`flake-module.nix`) — repos import this to declare what they provide and expose a `bosun-manifest` package (JSON derivation) +2. **Nushell CLI** (`cli/rigging.nu`) — reads `~/.config/bosun/config.toml`, builds each repo's manifest via `nix build`, aggregates, dispatches commands +3. **Bash CLI** (`cli/default.nix`) — repo-local Nomad job operations with runtime variable support + +## File layout + +``` +flake.nix # exports flakeModules.default + lib +flake-module.nix # the flake-parts module (top-level bosun.{meta,hosts} + perSystem bosun.{enable,jobsDir,...}) +cli/ + default.nix # bash bosun CLI (repo-local Nomad ops) + rigging.nix # nix wrapper for the nushell CLI + rigging.nu # nushell CLI source +lib/ + default.nix # bosun library (discoverJobs, evalJob, compileJobs, etc.) + nomad.nix # nomad helpers (traefikTags, pinToHost, resources, etc.) + nushell.nix # writeNushellApplication (bundled, no overlay needed) +``` + +## How consumers use it + +Consumers add this as a flake input and import `flakeModules.default`. This gives them: +- `bosun.meta.name` / `bosun.hosts` — top-level options for repo identity + host declarations +- `perSystem.bosun.{enable,jobsDir,nomadAddress,...}` — Nomad job management +- `packages.bosun-manifest` — always generated JSON manifest +- `packages.rigging` — the multi-repo CLI +- `packages.bosun` — repo-local Nomad CLI (only when `bosun.enable = true`) + +The manifest is the key integration point: `rigging` builds each repo's manifest via `nix build #bosun-manifest`, reads the JSON, and knows what hosts/jobs each repo provides. + +## Key design decisions + +- **No legacyPackages for vars**: Runtime job evaluation with variables uses `nix eval --expr` inline (same pattern as the bash CLI). The `legacyPackages.bosun.evalJobWithVars` exists for backward compat but the CLI constructs the eval expression directly. +- **Rigging delegates Nomad ops**: The nushell CLI is a thin orchestration layer. For actual Nomad operations (run, plan, stop, etc.), it delegates to the repo-local bash CLI via `nix run #bosun -- `. +- **writeNushellApplication bundled**: `lib/nushell.nix` is a self-contained copy so consumers don't need an overlay. +- **Top-level + perSystem split**: `bosun.meta`/`bosun.hosts` are flake-level options (shared across systems). Nomad job config is perSystem (needs `pkgs`). The manifest bridges both by reading top-level config from within perSystem via closure over `topArgs.config.bosun`. +- **`mkMerge`/`mkIf` for config**: The perSystem config uses `mkMerge` + `mkIf` (not `//` + `lib.optionalAttrs`) to avoid infinite recursion when the module system evaluates packages. + +## Vision + +The end state: `rigging` is installed globally (via home-manager or devShell) and manages all infrastructure repos. Each repo is self-describing — `rigging repo add ` discovers everything. Commands like `rigging host deploy alvin` or `rigging job run forgejo` Just Work regardless of which repo owns the resource. + +Phase 4 (pending): wire up dotfiles repo as a second consumer. Phase 5: drop the bash CLI once rigging fully replaces it. diff --git a/README.md b/README.md new file mode 100644 index 0000000..7f18f57 --- /dev/null +++ b/README.md @@ -0,0 +1,54 @@ +# Rigging + +Opinionated multi-repo NixOS + Nomad infrastructure management. One CLI to rule all your flakes. + +Rigging follows a **dendritic pattern**: each repo self-describes what it provides (hosts, Nomad jobs, secrets) via a flake-parts module. The `rigging` CLI aggregates any number of repos and gives you a single interface for deployments, job management, and secret rekeying — no more bouncing between `nixos-rebuild`, `nix run .#bosun`, and per-repo Justfiles. + +## Quick start + +Add rigging to your flake: + +```nix +# flake.nix +{ + inputs.rigging.url = "git+ssh://git@git.toph.so/toph/rigging.git"; + + outputs = inputs: inputs.flake-parts.lib.mkFlake { inherit inputs; } { + imports = [ inputs.rigging.flakeModules.default ]; + + bosun = { + meta.name = "myinfra"; + hosts = { + webserver = { + targetHost = "webserver.example.com"; + tags = [ "production" "web" ]; + }; + }; + }; + + perSystem = { ... }: { + bosun = { + enable = true; # only if you have Nomad jobs + jobsDir = ./jobs; + nomadAddress = "http://nomad:4646"; + }; + }; + }; +} +``` + +Then register and go: + +```sh +rigging repo add /path/to/myinfra +rigging status # see everything +rigging host deploy webserver # nixos-rebuild switch +rigging job run forgejo # compile + nomad job run +rigging secret rekey # agenix rekey across all repos +``` + +## Architecture + +- **Flake-parts module** (`flake-module.nix`) — repos import this to declare hosts/jobs/secrets and expose a `bosun-manifest` JSON derivation +- **Nushell CLI** (`rigging`) — reads `~/.config/bosun/config.toml`, builds each repo's manifest, aggregates, dispatches +- **Bash CLI** (`bosun`) — repo-local Nomad operations (compile, run, plan, stop, logs) with runtime variable support