8000 GitHub - andrewgazelka/config: My Mac in one repo: nix-darwin, home-manager, and dotfiles in strata, an incremental config language · GitHub
[go: up one dir, main page]

Skip to content
andrewgazelkaPublic

About

My Mac in one repo: nix-darwin, home-manager, and dotfiles in strata, an incremental config language

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

25 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

config

My Mac in one repo: nix-darwin for the system, home-manager for packages and background agents, and every dotfile written in strata, a small config language whose engine lives here too.

flake.nix   the system (darwinConfigurations.hydra), strata, checks
darwin/     nix, users, homebrew, macOS defaults, DNS blocklist
home/       packages, shells, launchd agents, activation scripts
config/     the dotfiles: *.cfg in strata, plus plain trees (nvim, nushell, agents)
strata/     the engine: Rust, its stdlib of app modules, tests

Use

darwin-rebuild switch --flake .
nix flake check   # secret scan, clippy, tests, fmt
nix fmt

Dotfiles need no switch. A launchd agent (home/strata.nix) runs strata watch, which applies config/ at login and again on every save. By hand, from the repo root:

strata plan        # what apply would change, reading ~ only
strata apply
strata status      # the last good generation, and what the agent is stuck on
strata rollback    # back to the previous generation
strata explain 'zed.font[size]'

When the agent can't apply, it posts a notification once per distinct error and records it for strata status.

The checkout is expected at /Volumes/Projects/nix (repo in home/strata.nix; config/cursor.cfg names it for nixd). A private repo at private/ (gitignored) adds its strata files from private/config/. config/strata.cfg declares it (layer optional "../private/config"), so a hand run and the agent build the same generation, and all dirs merge as one config. Each generation records its layers; a switch that would drop one the current generation has is refused, naming the files it would remove, unless --drop-layer <dir> says it is gone on purpose.

Another flake can build on this one: darwinModules.default is the whole system (home-manager included), so darwinSystem { modules = [ config.darwinModules.default ./more.nix ]; } adds to it, and home modules join through home-manager.users.<name>.imports.

strata

Braces open a scope, a colon sets one value. name { ... } is an entity that any file may reopen, merged key by key; name: value is a component, replaced whole. App keys sit on the app entity verbatim, quoted when needed. This is Flecs script's split: name { never means name: {, which strata refuses, so record literals appear only in expressions (lists, arguments, rules). name : base { ... } builds on prefabs.

aerospace {
    config-file: "~/.aerospace.toml"
    accordion-padding: 100
    start-at-login: false
    bindings { "alt-tab": "workspace-back-and-forth" }
    window-rules { "com.linear": "tiling" }
}

zed : typography {
    font { size: 14 }
    vim_mode: true
    terminal { shell { program: "nu" } }
}

A module (strata/stdlib/<app>.cfg) renders its entity's subtree to the app's format, children as nested objects and components as keys, leaving out the fields it declares and translates itself (config-file, bindings, window-rules, font, ...). core.cfg's components (file, dirs, texts) are global; inside zed only zed's module applies. Every name strata or the stdlib defines is kebab-case, so subtraction needs spaces.

Claude Code's keys are typed key by key by stdlib/schemas/claude-settings.cfg, generated with strata schema import <url or file> --name <x> (the header names the source and its blake3). An unknown key in a closed object, or a wrong type, fails with file:line:col.

Two core rules let a second layer add to a file or directory instead of replacing it. dirs."<target>" { public: entries("dir") } links each top-level entry of dir to <target>/<name>, so the target stays a real directory an app can add its own entries to; each layer adds its own component (private: ...) and entries merge by name. texts."<target>" { "10-x": read("x.md") } joins its components in name order into one file. read() is a file's text, entries() a directory's entries as source()/tree() values, and link(path) and copy(file) make a file a symlink or a copy.

Modules in strata/stdlib turn app entities like zed into files."<target>" entities, each holding one file: JSON, TOML, INI, text, a file or tree from config/, or a link to a Nix store path. Values merge by level, and two different values at one level are an error naming both. Each file is stored by its blake3 hash under ~/.local/state/strata, a generation is the set of files, named by one hash, and apply switches ~ to it with one rename per file: a symlink into the store, or a copy. Settings an app also writes (Zed, Cursor, Claude Code) are merge(json(...)): strata owns the keys it declares and merges them into the file on disk, the app's keys stay, and an app's change to one of strata's keys is reported as drift and set back. Evaluation is incremental, so a save re-renders only what it touches.

Store paths (delta, gh, ...) come from config/nix/facts.nix, built from the system's nixpkgs by home/strata.nix into ~/.config/strata/facts/pkgs.json, which config/strata.cfg reads.

The golden tests (strata/tests/golden) compare against output recorded from the Nickel config strata replaced. The crash test kills apply at each crash point, damages what a power cut could, and checks the next run converges. cargo bench --bench latency times cold runs and edits.

First switch

Coming from a home-manager that wrote these dotfiles itself:

darwin-rebuild switch --flake .    # writes the pkgs fact table, starts the agent
strata apply --adopt               # old files go to ~/.local/state/strata/backups
strata plan                        # every target: none

About

My Mac in one repo: nix-darwin, home-manager, and dotfiles in strata, an incremental config language

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

0