macOS system configuration managed with nix-darwin and Nix flakes (Determinate Nix). Orchestrates system packages, networking, security, and home-manager via three companion repos (nix-ai, nix-home, nix-devenv).
- Flakes-only: Never use
nix-env,nix-channels, or imperative commands - Determinate Nix: Use
determinateNix.enable = truevia the official module (modules/darwin/nix-storage.nix) — do not manually setnix.enable = false, the module handles this automatically; usenix(Determinate), notnix-envornix-channel - Nixpkgs first: Use homebrew only when nixpkgs unavailable; prefer
pkgs.*over overlays or custom derivations - Worktrees required: Run
/init-worktreebefore any work - No direct main commits: Always use feature branches via PRs
Build validation is enforced by GitHub Actions CI (ci-gate.yml) on every PR — not by a local pre-push hook.
Local quick checks (formatting, linting, dead code) run automatically on every commit via pre-commit hooks:
nix flake check # full flake check (run in CI)
nix fmt # format all Nix files (nixfmt-tree)
statix check # static analysis
deadnix # dead code detectionA full nix flake check && sudo darwin-rebuild switch --flake . is run by CI on macOS runners and must
pass before merge. You may run it locally to verify before pushing, but it is not required locally.
.nixfiles: Nix expression language only- Modules follow
{ config, pkgs, lib, ... }:function pattern - Use
lib.mkOptionfor configurable options - Attribute sets use
{}not record syntax
# Module definition
{ config, pkgs, lib, ... }: {
options.my.option = lib.mkEnableOption "description";
config = lib.mkIf config.my.option { ... };
}cd $GIT_HOME_PUBLIC/nix-darwin
git fetch origin
git worktree add <branch> -b <branch> origin/main
cd <branch>- Rules:
agentsmd/rules/(worktrees, version-validation, skill-namespace-resolution, security-alert-triage) - Security: See SECURITY.md and
agentsmd/rules/security-alert-triage.mdfor alert policies - Inventory:
MANIFEST.md— update when adding/removing packages
- macOS system defaults (Dock, Finder, keyboard, trackpad, energy)
- Homebrew configuration (casks and brews not in nixpkgs)
- System-level packages (
environment.systemPackages): core bootstrapping (git, gnupg, vim), macOS-only tools (e.g. mas), audio libs, GUI apps - Security settings (firewall, Gatekeeper)
- LaunchDaemons (system-level services)
- Activation scripts and boot recovery
- Networking configuration
- User dev tools (bat, ripgrep, jq, etc.) -> nix-home (
home.packages) - Shell config (zsh, git aliases) -> nix-home
- Editor settings -> nix-home
- Linters and formatters -> nix-home
- AI tools (Claude, Gemini, Copilot, MCP) -> nix-ai
- User-level LaunchAgents -> nix-home
See the nix-package-placement rule — lives in
ai-assistant-instructions and auto-loads via
path-scoping when .nix / flake.* files are in context.
Contains the full decision matrix for the nix repos including homebrew constraints and on-demand patterns.
| Repo | Scope | Used via |
|---|---|---|
| nix-darwin (this repo) | macOS system config (Dock, Finder, Homebrew, security) | nix-darwin |
| nix-ai | AI CLI ecosystem (Claude, Gemini, Copilot, MCP) | home-manager |
| nix-devenv | Reusable dev shells (Terraform, Ansible, K8s, AI/ML) | nix develop |
| nix-home | User environment (dotfiles, dev tools, LaunchAgents) | home-manager |
- Never auto-merge without explicit user approval
- 50-comment limit per PR
- Batch commits locally, push once
- Markdown lint:
markdownlint-cli2with the canonical.markdownlint-cli2.yamlsynced fromdryvist/.github.MD013 line_length: 160; no 80-char heading/code restrictions.CHANGELOG.mdandworktrees/**are ignored.MD024strict-by-default everywhere actually linted — never disabled across the board. - Pre-commit hooks: see
.pre-commit-config.yaml. Stack:pre-commit/pre-commit-hooks@v6.0.0meta-pack,DavidAnson/markdownlint-cli2@v0.22.1,gitleaks/gitleaks@v8.30.1,zizmorcore/zizmor-pre-commit,semgrep/pre-commit, plus localnixfmt,statix,deadnix,lychee, and repo-specific validators. - Out of scope for the current canonical-alignment PR: adopting the
nix-devenvflakeModules.dev-hygienemodule requires migrating this flake from traditional outputs toflake-parts— a larger architectural change tracked separately. Same with switchingnixpkgs.urltonixos-unstable(high-risk runtime change for the user's primary machine config).
Do NOT commit local copies of .markdownlint-cli2.{jsonc,yaml} that
drift from the dryvist canonical, and do NOT re-introduce leniency
rules to work around stale tooling.
OpenBao is the general replacement for SOPS. Shared homelab values belong there. SaaS/external credentials must use OpenBao or their designated runtime credential provider, never SOPS.
sops-nix is being retired. New SOPS entries are allowed only for trivial sensitive values owned exclusively by this repository and never used by another repository. Existing external entries are migration debt and must not be copied as precedent.