Parametric Forge owns the machine: one flake owns the macOS workstation — system defaults, GUI apps, CLI tools, fonts, overlays, secrets rails, SSH client config, and cache policy. Consumer repos assume the machine's tools on PATH and never import Forge; when shell, toolchain, credential, or wrapper behavior fails in a consumer, the fix lands here. Nothing in this repo couples to a specific project — Forge aligns with consumers, never binds to them.
This regenerable topology maps the repository's owning entry points.
Parametric_Forge/
├── Casks/ # Vendor GUI packages absent from Homebrew's catalog
├── flake.nix # Flake inputs, systems, outputs
├── flake.lock
├── flake-modules/ # nixpkgs instance, host factory, outputs, checks, formatter
├── hosts/
│ └── context.nix # Host-context row registry
├── modules/
│ ├── common/ # Shared Nix settings and toolchain environment
│ ├── darwin/
│ │ ├── settings/ # Root-scope macOS defaults, security, launchd environment
│ │ └── homebrew/ # Homebrew bridge
│ └── home/
│ ├── aliases/ # Shell alias registry
│ ├── assets/
│ │ └── ascii/ # Fetch banner assets
│ ├── environments/ # Cross-tool environment projections
│ ├── programs/
│ │ ├── apps/
│ │ │ ├── karabiner/ # Leader-chord keyboard layer
│ │ │ ├── linearmouse/ # External-mouse schemes
│ │ │ ├── nvim/ # Editor
│ │ │ ├── wezterm/ # Terminal host
│ │ │ ├── yazi/ # File manager
│ │ │ └── zellij/ # Multiplexer layouts and themes
│ │ ├── container-tools/
│ │ ├── git-tools/
│ │ ├── languages/ # Language toolchains
│ │ ├── mac-tools/ # Application rows and default handlers
│ │ │ └── defaults/ # User-scope macOS defaults
│ │ ├── media-tools/
│ │ ├── nix-tools/
│ │ ├── shell-tools/ # CLI kernels, SSH, secrets
│ │ └── zsh/
│ └── scripts/ # Integration and analysis kernels
├── overlays/ # Manifest-folded package admissions
├── services/ # Doppler and GitHub IaC rows
└── .claude/ # Harness commands and skills
hosts/context.nix registers macbook (aarch64-darwin). Its row carries identity, platform, state versions, and SSH facts; flake-modules/hosts.nix projects it into darwinSystem on the one perSystem nixpkgs instance (flake-modules/nixpkgs.nix, overlay and unfree included) and derives the flake's systems from the rows, and the home graph reads the same row.
Rulings derive from principles, not precedent lists. These axes resolve each new situation:
| [INDEX] | [AXIS] | [LAW] |
|---|---|---|
| [01] | Greenfield-only | Every touched surface rebuilds to the best current shape; no compatibility layer of any kind survives. |
| [02] | One owner per axis | One declaring file per concern; a second copy of any fact is a fork — extend the owner, never add files. |
| [03] | Rows over hardcodes | Capability lands as a parameterized row on the owning table; a new host, package, or service is one row. |
| [04] | Polymorphic collapse | Density rises inside the owning file — merged types, dispatch tables, folds — never by extraction. |
| [05] | IaC over YAML | Pulumi rows in services/ own Forge's repo and shared Doppler projects; each repo owns its GitHub settings. |
| [06] | Currency as review | Newest stable everything; a pin exists only with a named incompatibility and dies when compatibility lands. |
| [07] | No LFS | Repo media ships as plain git blobs kept preview-small; a project using LFS pins git-lfs in its mise.toml. |
| [08] | Aesthetics first-class | Visual surfaces (theme, prompt, TUI, fonts) are designed systems with single palette ownership. |
This machine runs Determinate Nix, not vanilla: Determinate owns the daemon and /etc/nix/nix.conf (eval-cores, lazy-trees, experimental-features, its caches). modules/common/nix.nix declares only determinateNix.customSettings (written to /etc/nix/nix.custom.conf), the flake registry, and determinateNixd rows; the module rejects bash-prompt-prefix, external-builders, extra-nix-path, netrc-file, ssl-cert-file, and upgrade-nix-store-path-url in custom settings. The registry pins every flake input at its locked revision, so nix run nixpkgs#x and <nixpkgs> resolve to the nixpkgs the system was built from; ids outside the inputs are spelled as full refs. Every new store path is hard-linked on arrival (auto-optimise-store); determinate-nixd's automatic GC frees dead paths in the background, and generation retention runs on demand: nh clean all --keep 1.
modules/common/carries Nix settings and the toolchain env vocabulary: one PATH vector and one cross-surface row set, which nix-darwin'sset-environmentwrites for every zsh and bash,launchctl config user pathand thegui-envagent replay into the GUI launchd domain, and.zshenvasserts as a never-clobber floor. Interactive-only rows stay Home Manager session variables. The shell is Apple's/bin/zsh(forge.shell); Nix supplies its configuration, not the binary. The time zone is macOS's automatic zone, never aTZrow.modules/darwin/carries system-scope macOS state: defaults, security, and the Homebrew bridge. Homebrew carries GUI/proprietary bundles nixpkgs cannot ship; activation updates Homebrew, installs missing roster entries, and upgrades outdated ones, while cleanup stays with the manual Homebrew pass so operator installs survive.Casks/owns vendor GUI packages absent from Homebrew's main catalog; Homebrew taps this checkout asbsamiee/forge(modules/darwin/homebrew/), so a committed cask reaches the next activation without a push.- Adobe applications remain Creative Cloud-owned; Typeface uses its native vendor updater.
mac-tools/default-applications.nixowns the application rows (bundle id, handled extensions and schemes, path where a consumer opens the bundle) that the Dock, LinearMouse, and the utiluti handler reconcile read.mac-tools/defaults/owns user-scope macOS defaults as Home Managertargets.darwin.defaultsrows, imported every switch.home/fonts.nixinstalls the curated catalog through Home Manager's native user font projection and projects its roles into fontconfig's generic families. modules/home/carries user-scope state under Home Manager: XDG hygiene, session environments, program owners, scripts. System and home scopes never mix in one module.overlays/is the admission gate for upstream packages nixpkgs lacks or pins wrongly:manifest.nixowns admission and recipes consume nvfetcher-generated versions and hashes. Admission requires a real consumer now — never anticipatory packaging.services/owns live service state as code under the TypeScript quality bar.package.jsonandpnpm-workspace.yamlbind the repo-root workspace without per-folder manifests. Existing service domains extend their rows; new domains get one organized owner.services/workspace commands:node services/driver.ts preview|up|refresh [--adopt] [--target=<p>/<c>/<token>]converges the topology;outputs [--reveal]prints stack outputs;scopesapplies the directory-scope rows.services/driver.tsbrokers Pulumi and Doppler credentials from 1Password and resolvesGITHUB_TOKENfrom the agent environment or Doppler.
Doppler owns project and service configuration; 1Password owns local operator and session custody. Home Manager resolves the mode-600 session cache during activation. Process-specific Doppler consumers invoke doppler run or doppler secrets download explicitly. Read names with doppler secrets --project <p> --config <c> --only-names; add a key in its owning config and wire its process consumer. Topology mutates only through services/topology.ts rows. secrets owns the custody law.
One ed25519 key serves everything: custodied in the 1Password Personal vault, served through its agent socket, registered on GitHub for authentication and signing. No private key lands on disk: vault sync is the recovery, and a local copy shadows a dead agent. Commit signing uses SSH format and generated allowed signers. ssh.nix projects client config alone: the agent socket, signing, and OpenSSH client defaults. Bounded forwarding uses OpenSSH's own -L, -R, or -D flags instead of a resident service.
redeploy build|switch [nh args] is the only sanctioned activation path: nh darwin builds the host toplevel with nom progress, prints a dix diff against the live system, and on switch sets the system profile and activates through the primary user's passwordless sudo. It runs under cachix watch-exec, so every locally built path is pushed to Cachix as it lands and a failed build retries from the cache; the push reads the ambient CACHIX_AUTH_TOKEN and fails loudly without it.
Probe a machine that misbehaves after a switch before theorizing about it: which -a <bin> classifies PATH owners and cross-owner shadows, launchctl list | grep dev.bsamiee reconciles the declared agent set against the live table, and readlink /run/current-system reads the live generation against $HOME. Every probe is read-only, so it opens the investigation rather than closing it.
Recurring machine work is launchd-owned under the dev.bsamiee.<name> label grammar, each agent declared beside the surface it serves: launchctl list | grep dev.bsamiee is the live census of Forge agents (project tools such as Rasm's pitchfork register their own dev.mise.* labels outside it), launchctl print gui/$UID/dev.bsamiee.<name> the per-agent probe. Each new recurring job lands as one agent declaration.
gui-setenv (environments/shell.nix) owns every write into the GUI launchd domain: a replay unsets each name its writer's previous replay set and this one drops, and a replay that changes a value restarts each running KeepAlive agent in ~/Library/LaunchAgents, so a resident process that spawned before the replay, a project tool's included, inherits the replayed rows.
- [PYTHON]: no machine interpreter or tool; a project's
mise.tomlanduv.lockownpython,uv,ruff,ty, andmypyinside its tree, and none resolves outside one.languages/scientific-tools.nixinstalls the native command-line roster; a project's Pixi environment owns the native libraries its source builds and ctypes consumers read. - [NODE_LUA_DB]: Node, pnpm, and TypeScript are each project's
mise.tomlandpackage.jsonrows; Lua with LSP tooling; the SQLite extension libraries (sqlean, spatialite, vec) behind thesqlite-extendedkernel, while thesqlite3andduckdbclients are project rows; PostgreSQL client tools are Home Manager-owned. - [DOTNET_AEC]: No machine .NET SDK and no machine .NET tool; each repo's mise install owns the SDK its
global.jsonpins and runs its tools throughdotnet dnx <id>. Every SDK installs into one shared root (misedotnet.dotnet_root, the root/etc/dotnet/install_location_arm64names), so a process that capturedDOTNET_ROOTor the root's PATH segment reaches each SDK a laterglobal.jsonnames. Thatdotnetreaches PATH through the mise shim segmenttoolchain-env.nixputs first on the one PATH vector every session and launchd surface projects, so a login shell, a launchd agent, and a GUI app resolve the pinned SDK without the interactivemise activatehook;roslyn-ls, the editor's C# server, is the one machine-wide .NET consumer.energyplusandopenstudioare Forge-owned machine runtimes with disjoint ambient identities.
modules/home/theme.nix owns the palette and serializes it into every visual consumer. modules/home/programs/apps/chords.nix owns the chord vocabulary and projects each row into Karabiner, Zellij, and hint content. modules/home/scripts/terminal.nix binds the mesh: WezTerm attaches Zellij, Yazi opens as a floating popup, and edits route into the tab's Neovim RPC socket, one editor per tab named by the tab id, through blocking Zellij and Neovim primitives rather than retries. A delta file://<path>:<line> link and a quick-select file:line span both open Neovim at the line in a WezTerm utility float.
| [INDEX] | [SURFACE] | [STANDARD] |
|---|---|---|
| [01] | Nix | alejandra/deadnix/statix/nixf-diagnose gate via treefmt, statix check via nix flake check. |
| [02] | Shell source | .sh extension; set -euo pipefail; ShellCheck passes. |
| [03] | Shell packaging | writeShellApplication for any body with a runtime closure; writeShellScriptBin for closure-free one-liners. |
| [04] | TypeScript | Effect rails, tagged faults, redacted config, schema decodes at boundaries, pnpm-only. |
| [05] | Python | uv-managed, ruff + ty. |
| [06] | launchd | Declared agent rows under the label, log, and lifecycle law, each beside the surface it serves. |
services/topology.ts holds Forge's own GitHub repository settings (merge hygiene, rulesets, feature booleans) as @pulumi/github rows, and each other repository owns its own; node driver.ts preview is the verification surface — repo state is never enumerated in prose or edited in the GitHub UI. Rows in the same file own the shared Doppler projects, environments, branch configs, and service tokens.
Everything lands declaratively with the first switch; only these steps are manual, each with its proof:
-
Install Determinate Nix via the macOS package — the
curl | shinstaller can die creating the encrypted APFS volume and strand fstab/synthetic.conf residue.- Command:
curl -sSfL https://install.determinate.systems/determinate-pkg/stable/Universal -o determinate.pkg && sudo installer -pkg determinate.pkg -target / - Verify:
nix --versionreports Determinate
- Command:
-
Install the Xcode Command Line Tools and Homebrew via its macOS package — activation's
brew bundlerequiresbrew, the tap and clone below needgit, and Homebrew's ownbrew updatekeeps it on the newest stable tag from then on.- Command:
xcode-select --install, thencurl -sSfL https://github.com/Homebrew/brew/releases/latest/download/Homebrew.pkg -o Homebrew.pkg && sudo installer -pkg Homebrew.pkg -target / - Verify:
/opt/homebrew/bin/brew --versionreports the latest release
- Command:
-
Sign into the 1Password app; enable Settings → Developer → SSH agent + CLI integration. GUI-only by vendor design; key custody syncs from the cloud — zero key handling.
- Verify:
SSH_AUTH_SOCK=~/Library/Group\ Containers/2BUA8C4S2C.com.1password/t/agent.sock ssh-add -Llists the key
- Verify:
-
Clone to the path the deploy rail resolves; the agent socket is explicit until the first switch projects
~/.ssh/config.- Command:
SSH_AUTH_SOCK=~/Library/Group\ Containers/2BUA8C4S2C.com.1password/t/agent.sock git clone git@github.com:bsamiee/Parametric_Forge.git ~/Developer/Parametric_Forge - Verify: repo present at
~/Developer/Parametric_Forge
- Command:
-
Grant the bootstrap terminal Full Disk Access (System Settings → Privacy & Security) —
universalaccessdefaults writes abort activation without it; move the grant to WezTerm after the first switch.- Verify: from the granted terminal (WezTerm after the move),
sqlite3 -readonly ~/Library/Application\ Support/com.apple.TCC/TCC.db 'select count(*) from access'prints a count
- Verify: from the granted terminal (WezTerm after the move),
-
First switch — installs the passwordless sudo row every later
redeploy switchrides. Installer-written real files at/etc/pam.d/sudo_localor/etc/nix/nix.custom.conftrip the /etc collision guard: move each aside (.before-nix-darwin) and rerun.- Command:
sudo nix run nix-darwin/master#darwin-rebuild -- switch --flake .#macbook - Verify:
redeploy build
- Command:
-
Authenticate Doppler from the checkout.
- Command:
mise install, thenmise exec -- doppler login - Verify:
mise exec -- doppler me
- Command:
-
Grant the manual permission set. Each row is a TCC or system-extension decision with no declarative path on an unmanaged Mac (System Settings → Privacy & Security unless noted):
[APP_OR_SERVICE] [GRANT] [WHEN] Terminal Full Disk Access Bootstrap only (step 5); remove after WezTerm holds it WezTerm Full Disk Access, Accessibility, Input Monitoring, Screen & System Audio Recording, Developer Tools, App Management After the first switch: the responsible process for zsh, zellij, agents, and redeploy; App Management letscopyAppswrite~/Applications/Home Manager AppsKarabiner-Elements General → Login Items & Extensions → Allow in the Background → the Karabiner-Elements background services on; Driver Extensions → Karabiner-DriverKit-VirtualHIDDevice on; Accessibility → Karabiner-Core-Service (normally also grants Input Monitoring) First launch LinearMouse Accessibility First launch 1Password Accessibility; AutoFill & Passwords → 1Password on, Passwords off; app Settings → Developer → SSH agent + CLI Step 2 and first launch Raycast Accessibility First launch CleanShot X Screen & System Audio Recording, Accessibility First launch Claude (desktop) Accessibility, Input Monitoring, Developer Tools First launch Codex + Codex Computer Use Codex: Accessibility, Screen & System Audio Recording, Input Monitoring, Developer Tools, Full Disk Access; Codex Computer Use: Accessibility, Screen & System Audio Recording, Full Disk Access First launch Visual Studio Code Developer Tools, Full Disk Access First launch (integrated terminal parity with WezTerm) Atelier (Rasm) Accessibility, Screen & System Audio Recording; Automation → Atelier → each Adobe app it drives First run of each target Arc, Blender, Rhino, Adobe Screen & System Audio Recording First capture prompt; the user-defaults owner keeps the periodic screen-capture hint away afterwards calibre, Discord, new casks Open once, then Privacy & Security → Open Anyway (or the Anywhere confirm, step 9) First launch; Homebrew carries the approval across upgrades Arc as default browser Confirm the "change default browser" dialog First switch whose handler reconcile changes http- Verify:
systemextensionsctl listshows Karabiner[activated enabled]; affected agents run without prompting
- Verify:
-
Confirm the two root settings activation cannot write: Privacy & Security → Allow applications from → Anywhere (
sudo spctl --global-disablereveals it and exits 1 until confirmed; the choice lands in a SIP-protected file), and Users & Groups → Automatically log in as → the primary user (writes/etc/kcpassword, whichautoLoginUsercannot).- Verify:
spctl --statusreportsassessments disabled;sysadminctl -autologin statusnames the primary user
- Verify:
Day-2 rebuilds: redeploy switch.
- Format:
nix fmt -- --ci— full proof:nix flake check. - Inputs, in one pass on a clean tree:
sudo determinate-nixd upgrade, thennix flake updateandnix shell .#nvfetcher -c nvfetcher -o overlays/_sources -k =(printf '[keys]\ngithub = "%s"\n' "$(gh auth token)")together (zsh=()hands nvchecker a keyfile every check reads), prune each overlay row nixpkgs caught up to and advance the rest,biome migrate --writeafter a biome bump, oneredeploy switch, the Homebrew pass, thennh clean all --keep 1.
Every family moves through the ordered update sequence on demand; Homebrew currency runs brew update && brew upgrade && brew cleanup.