These are my dotfiles. Take anything you want, but at your own risk.
They are used for configuring several of my environments:
- MacBook with nix-darwin,
- NixOS VM running via UTM on the MacBook,
- user account on a shared company NixOS server.
~/work/dotfiles/
├── flake.nix # Define all machines
├── flake.lock # Lock all dependencies
│
├── common/ # Shared modules across all systems
│ ├── ai.nix
│ ├── codex-config-merge.py # keeps codex's config.toml writable
│ ├── direnv.nix
│ ├── files.nix
│ ├── gitconfig.nix
│ ├── tools.nix
│ ├── vim.nix
│ └── zsh.nix
│
├── darwin/
│ ├── zbook.nix # nix-darwin for my MacBook
│ └── home.nix # Home Manager for my MacBook
│
├── nixos/
│ └── utm/ # UTM VM
│ ├── configuration.nix
│ ├── hardware-configuration.nix
│ └── home.nix
│
├── .secrets.env # Environment variables for secrets (git-ignored)
├── mkcert/ # development certificates
└── vscode/ # VS Code settings
- Common modules go in
common/, system-specific overrides indarwin/ornixos/ - Packages from unstable nixpkgs use
pkgsUnstable(passed viaextraSpecialArgs) - Claude Code config is shared from
teamniteo/agentsrepo via theniteo-agentsflake input; personal overrides go incommon/ai.nix - Codex is configured alongside Claude Code in
common/ai.nix: it gets the same personal context (asAGENTS.md) and the same MCP servers, translated into codex'sconfig.tomlkeys - Codex needs a writable
config.toml(directory trust,features enable,/model), so Nix generates it and an activation script installs a real file instead of a store symlink, carrying codex's own[projects]trust entries across rebuilds - No imperative changes — everything is declarative through Nix
TODO...
-
Use the official Nix installer for macOS: https://nixos.org/download.html#nix-install-macos
-
Follow
Flakesinstall steps for nix-darwin: https://github.com/LnL7/nix-darwin -
Another great resource is: https://nixcademy.com/2024/01/15/nix-on-macos/
-
Get my dotfiles and link them to places where they are used:
$ git clone https://github.com/zupo/dotfiles.git ~/work/dotfiles
$ ln -sv ~/work/dotfiles/vscode ~/Library/Application\ Support/Code/User
$ echo 'machine niteo.cachix.org password <CACHIX AUTH TOKEN>' >> ~/.config/nix/netrc
-
Create secret files in the
dotfilesdirectory:.secrets.envfor environment variables:export OPENAI_API_KEY="sk-proj-..." export CACHIX_AUTH_TOKEN="..."
-
nix-channels are implicit and bad, so I remove them and instead use flakes to pin to exact nixpkgs commit hashes:
$ rm ~/.nix-channels
$ rm ~/.nix-defexpr/channels
$ rm ~/.nixpkgs/
- The Nix installer also puts
nss-cacertinto the default profile. Nothing reads its CA bundle, since nix-darwin provides/etc/ssl/certs/ca-certificates.crt(honouringsecurity.pki.caCertificateBlacklist), but it never gets updated, so it keeps trusting distrusted CAs and fails the Pareto Security compromised CA check. Remove it:
$ sudo nix-env -p /nix/var/nix/profiles/default -e nss-cacert
- What to do with
/etc/zshrcand/etc/zprofile?
MacOS comes with the following:
/etc/zprofile/etc/zshrc/etc/zshrc_Apple_Terminal
I don't use it because it only provides load /usr/libexec/path_helper which is slow and not needed.
Also, nix-darwin/nix-darwin#532.
I don't use it because it only provides two features I don't need:
- emacs support,
- automatic history save/restore -> I prefer to use a shared history.
I override this one with my personal settings using flake.nix
In the end, the /etc folder should be like this:
/etc ➜ ls -l z*
lrwxr-xr-x 1 root wheel 20 Sep 14 18:17 zprofile -> /etc/static/zprofile
lrwxr-xr-x 1 root wheel 18 Apr 7 2020 zshenv -> /etc/static/zshenv
lrwxr-xr-x 1 root wheel 17 Sep 20 11:30 zshrc -> /etc/static/zshrc
Related: nix-darwin/nix-darwin#193
Claude Code and Codex receive the same personal instructions, RTK guidance, speed preference, and general team rules from one shared context. Home Manager writes it to their required global files, ~/.claude/CLAUDE.md and ~/.codex/AGENTS.md. Both use the same plugin source declarations and RTK hook definition. MCP servers share one source with a Codex format adapter; Slack remains Claude-only because its OAuth client uses Claude’s callback.
Nix pins the plugin code in flake.lock. Claude Code loads Passlet and Hakuto directly from the Nix store through Home Manager's plugins option. The built-in Claude plugin follows the pinned Claude package. Claude-only example skills use Claude’s native plugin manager, with their marketplace and enabled state declared in Nix. Their code is not pinned in flake.lock.
Codex's Passlet and Hakuto marketplaces point to the same pinned Nix sources as Claude. Home Manager installs their versioned Codex cache entries as links to the Nix store, so installation, source, and enabled state are all declared in Nix. ChatGPT's account-managed plugins are separate from these repository plugins.
Update with nix flake update hakuto passlet, then run nixre and start new agent sessions. No plugin install or upgrade commands are needed for these shared plugins. Update Claude-only example skills through Claude’s plugin manager. Passlet's pin controls both the app package and its plugin source.
The Mac's Home Manager configuration installs Passlet and enables programs.passlet.service.tailscale. When the Approver starts, it checks Tailscale Serve and configures missing HTTPS forwarding on port 17400 to its private Unix socket. Tailscale 1.104.4 or newer must already be running and signed in. Conflicting forwarding is rejected, and other Tailscale Serve ports are left unchanged.
The forwarding persists across restarts. Inspect it with tailscale serve status and check service health with passlet approver doctor. To disable remote access, set programs.passlet.service.tailscale = false, apply the configuration with nixre, and remove the persistent HTTPS forwarding with tailscale serve --https=17400 off.
To update to the latest release in the currently used channel, run
nix flake update followed by nixre.
When a new nixpkgs channel is released, do the following:
- update the
nixpkgs.urlinput inflake.nixto the new channel - run
nixre
MCP server logs are at ~/Library/Caches/claude-cli-nodejs/<project-path>/mcp-logs-<server-name>/ where <project-path> is the working directory with slashes replaced by dashes (e.g., -Users-zupo--dotfiles). Each directory contains .jsonl files with timestamped entries. Session debug logs are at ~/.claude/debug/ with a latest symlink.
If you see this error when trying to reinstall, follow https://discourse.nixos.org/t/ssl-ca-cert-error-on-macos/31171/5.
If you see an error like this:
> mkdir: cannot create directory '/nix/store/31k835115bylz5qb3k7vhcvfgrl4cwpl-nixos-disk-image/nix-support': No space left on deviceThe problem might not be with your macOS disk space, but with the nix-darwin's linux-builder disk space. Fix it like this:
$ sudo ssh linux-builder
[builder@nixos:~]$ nix-collect-garbage