One repo for the whole machine: a Nix-declared macOS setup (nix-darwin + home-manager flake, Homebrew for casks, a one-shot bootstrap) and portable AI coding-harness configs — shared skills, commands, rules, agents, and settings — provisioned from one source of truth across multiple Claude Code profiles, pi, Devin CLI, and GitHub Copilot CLI.
A personal repo, published so others can borrow the architecture. Paths are hardcoded to one machine — adapt before adopting (see Adopt it).
curl -fsSL https://raw.githubusercontent.com/sanketsudake/dotfiles/main/bootstrap.sh -o /tmp/bootstrap.sh
bash /tmp/bootstrap.shThe script is idempotent: Xcode CLT, Homebrew, and Determinate Nix if missing, clone to ~/personal/dotfiles, one darwin-rebuild switch (packages, dotfile links, macOS defaults; pre-existing files are moved to a timestamped ~/.dotfiles-backup-* dir), harness links, tools, and make doctor.
Afterwards run the printed manual steps (gh auth login, atuin login, git lfs install) and open a new terminal.
On an existing machine, clone the repo and run make install.
- One source of truth, many harnesses.
A single
skills/tree feeds Claude Code, pi, Devin CLI, and Copilot CLI; edit once, every harness sees it immediately. Devin reads~/.agents/skillsand Copilot reads~/.copilot/skills; both links point at the same tree, and the sameagents/*.mdfiles link into each CLI under the name it expects. - Two Claude profiles via
CLAUDE_CONFIG_DIR.pclaude/wclaudewrappers keep personal and work accounts isolated while sharing the same skills and rules. - Per-resource source tracking.
Every skill and agent source lives in one
sources.tomlmanifest; vendored skills are pinned there (repo, subpath, commit) and materialized on install — so an upstream update is one command and a bare clone stays reproducible. - Generated catalog, enforced by a doctor.
skills/README.mdis generated from that metadata;make skills-doctorfails when anything drifts. - Guardrails as code, not hope.
Extensions for pi confirm before destructive actions, block dirty-repo commits, and protect paths;
a
PreToolUsesafety hook does the same for Claude Code (deny/ask on dangerous shell, secrets, and VCS internals);plugins.txtdeclares the plugin set andmake plugins-checkreports drift per profile. - Skills are scanned before they land.
make skills-scanruns NVIDIA SkillSpector over every skill,skills-fetch/skills-updaterefuse a skill that fails, and accepted findings carry a reason inskills/.security/skillspector/. - Measured, not assumed.
make context-budgetreports the always-loaded context per session (capped by the doctor), and aSubagentStop/Stoptelemetry hook plusmake usage-reportshow spend by agent type × model and cache-hit ratio. CI runs the doctor, catalog, script tests, and the security scan on every push.
dotfiles/
├── Makefile # primary interface — every <resource>-<action> target
├── CLAUDE.md # guide for agents working IN this repo (full Makefile reference)
├── bootstrap.sh # new-Mac entry point
├── flake.nix # nix entry point; flake.lock pins nixpkgs/nix-darwin/home-manager
├── nix/ # darwin/ system config (defaults, homebrew) + home/ user env
├── manifests/ # non-brew tools: go-tools.txt, npm-globals.txt, pipx-tools.txt
├── macos/ # deliberately-changed macOS defaults (make macos-apply)
├── packages/ # dotfile sources for $HOME (zsh, git, atuin, btop, gh, bin), linked by home-manager
│ ├── agents/ # AGENTS.md — global rules shared by Devin CLI + Copilot CLI
│ ├── devin/ # Devin CLI config.json
│ └── copilot/ # Copilot CLI settings.json
├── claude/ # Claude Code config, symlinked into both profiles
│ ├── CLAUDE.md # shared global user instructions
│ ├── commands/ # slash commands
│ ├── agents/ # subagents
│ ├── rules/ # model routing, git hygiene, delegation
│ ├── scripts/ # hooks (routing, safety guard, usage telemetry) + statusline
│ └── plugins.txt # desired-state plugin list
├── skills/ # shared skills for Claude + pi — the source of truth
│ ├── README.md # generated catalog — start here
│ └── .security/ # SkillSpector baselines (accepted findings, with reasons)
├── suites/ # curated skill-suite landing pages
├── pi/ # pi agent config, linked into ~/.pi
└── scripts/ # repo tooling (doctor, drift, resource manager — not symlinked)
make install links skills/ and claude/* into both Claude profiles, pi/ into ~/.pi, and the shared skills, agents, and configs into Devin CLI and Copilot CLI (home-manager out-of-store symlinks) — safe to re-run.
Because everything is symlinked, one edit here applies to every profile and both harnesses at once.
Skills — browse the catalog (grouped by category, generated from each skill's metadata). Most are authored here; the rest are vendored from pi-skills, cursor-team-kit, anthropics/skills, and the skills.sh ecosystem — each linked to its upstream source at a pinned commit.
Suites — curated skill sets with their own landing pages:
- Go CI Health — Keep a Go repo’s CI green, fast, and secure
- Agent-Maintained Hugo Site — Write, illustrate, verify, optimize, and measure a Hugo blog with an agent
- OSS Maintainer Copilot — Backlog triage, CodeQL remediation, and security advisories for repos you maintain
- PR Shepherding — Get a pull request from pushed to merged: clean diff, green CI, resolved reviews
- Second Brain — An Obsidian knowledge base your agent maintains for you
Agents
| Agent | Purpose |
|---|---|
plan-reviewer |
Pre-execution plan review against the actual codebase; APPROVE/REVISE with evidence. |
bulk-mechanic |
Haiku executor for mechanical, judgment-free batches. |
pr-shepherd |
Drives the push → CI → bot-review loop to green. |
skill-auditor |
Audits a skill directory against this repo's conventions. |
Rules
| Rule | Governs |
|---|---|
model-routing.md |
Cheapest reliable model tier per task, and effort calibration. |
git-hygiene.md |
Staging, commit, and push discipline. |
delegation.md |
When to hand work to the agents above instead of doing it inline. |
Plus the shared CLAUDE.md (secrets hygiene, semantic-line-break markdown per sembr.org), the /history command, helper scripts, and pi guardrail extensions vendored from pi-mono.
Prerequisites: git, jq (plus gh / python3 / npx for the skills that use them).
git clone https://github.com/sanketsudake/dotfiles.git
cd dotfiles
# Before installing:
# 1. Edit CLAUDE_CONFIG_DIRS in the Makefile (your profiles)
# 2. Copy the pclaude/wclaude snippets from scripts/claude-multi-account.sh into your shell profile
# 3. Make claude/CLAUDE.md yours — it's opinionated
# 4. Review nix/, manifests/, and packages/ — they describe one person's machine
make install # nix-switch (packages + dotfiles + defaults + harness links) + skills-materialize + tools
make skills-list # see each skill's source and statusmake uninstall reverses it.
Everyday targets — CLAUDE.md carries the full <resource>-<action> reference, and every skills-* target has an agents-* twin.
| Target | Does |
|---|---|
install / uninstall |
Apply the declared system and links, or reverse it. |
skills-find / skills-add |
Discover skills on skills.sh and vendor them. |
skills-catalog / skills-doctor |
Regenerate the catalog / validate every skill and its freshness. |
skills-update[-all] |
Re-fetch vendored skills whose upstream moved. |
plugins-check / plugins-sync |
Report plugin drift per profile / emit the /plugin install lines. |
Two gotchas: vendored skills/ and pi/extensions/ are overwritten on re-sync — diverge intentionally and note it durably; and use SUBPATH=, never PATH=, on fetch targets (the latter clobbers the shell PATH).
Plugin installation stays manual per profile — Claude Code has no headless /plugin install.
| Target | Does |
|---|---|
install |
nix-switch + harness links + tools-install |
nix-switch / nix-build |
Apply the whole declared system / build-only preview |
nix-check / nix-fmt |
Flake check + statix lint / format the nix files |
nix-update |
Bump flake.lock; review the diff like a Brewfile re-curation |
nix-rollback |
Switch back to the previous system generation |
tools-install |
go-install + npm-install + pipx-install from manifests/ |
brew-check |
Verify installed brew state against the nix-generated brewfile |
brew-dump |
Regenerate gitignored Brewfile.dump to diff against nix/darwin/homebrew.nix |
cask-adopt |
Take over apps installed outside brew (pkg casks prompt for sudo) |
macos-apply |
Run macos/defaults.sh (Helium-only; system defaults live in nix) |
doctor |
Run all health checks |
drift |
Report divergence between recorded config and the live system, both directions |
raycast-export |
Open Raycast's encrypted settings export; save the file privately (never committed) |
The machine is declared once and applied with make nix-switch:
flake.nix pins nixpkgs, nix-darwin, and home-manager in flake.lock,
nix/darwin/ declares the system (macOS defaults, and every brew/cask/mas/vscode entry via the homebrew module),
and nix/home/ declares the user environment (dotfile links and CLI packages).
Dotfile sources stay in packages/ with their dot- names;
home-manager links each file individually into $HOME,
so ~/.config/<tool> stays a real directory and credential files written beside managed configs
(e.g. gh's hosts.yml) can never land in the repo — the old --no-folding invariant, kept.
Never declare files from credential-bearing dirs (gcloud, 1Password, op, github-copilot) or credential-bearing files (gh/hosts.yml, ~/.copilot/config.json).
Every switch is a numbered generation; make nix-rollback returns to the previous one.
Homebrew remains for casks/taps/mas (declared in nix/darwin/homebrew.nix, applied by the same switch,
cleanup = "uninstall": an undeclared install is removed on the next switch — promote keepers first).
Two rules with no exceptions:
flakes only see git-tracked files, so git add new .nix files before building;
and never let home-manager own a directory that holds mutable files.
The harness targets (~/.claude-*, ~/.pi, ~/.agents, ~/.config/devin, ~/.copilot) are home-manager out-of-store symlinks into the repo working tree (nix/home/harness.nix) —
the linked content stays mutable, so vendored skills materialize in place and repo edits apply live.
~/.pi/agent, ~/.pi/extensions, and the Devin/Copilot agent dirs link per-file on purpose: those tools write state beside them,
and a whole-dir link would let a tool write into the repo.
Devin CLI reads personal skills from ~/.agents/skills; Copilot CLI 0.0.417 scans ~/.copilot/skills (plus ~/.claude/skills and the project dirs) and does not look at ~/.agents/skills yet.
Each CLI therefore gets its own link to the same skills/ tree — the paths never collide, so no skill is discovered twice.
The subagents in packages/claude/agents/ link into ~/.config/devin/agents/<name>.md and ~/.copilot/agents/<name>.agent.md — same file, two names.
Global always-on rules come from packages/agents/AGENTS.md, linked as ~/.config/devin/AGENTS.md and ~/.copilot/copilot-instructions.md.
Of each CLI's own config, only the user-editable file is managed (~/.config/devin/config.json, ~/.copilot/settings.json);
~/.copilot/config.json holds login state and the two herdr-agent-state.sh hook scripts are installed by herdr, so all three stay local files.
make doctor checks that the links resolve into the repo; these commands check that the tools use them.
| Check | Devin CLI | Copilot CLI |
|---|---|---|
| Subagents | devin doctor — lists the loaded profiles and warns on unknown frontmatter keys |
copilot --agent <name> -p 'reply OK' — the run header names the agent |
| Skills | devin skills list — each skill with its ~/personal/dotfiles/skills/... path |
/skills list in an interactive session — it prints the dirs it scanned |
| Global rules | devin rules list — AGENTS [Standard] always-on |
copilot -s -p '…answer from your instructions only…' — it answers from copilot-instructions.md |
| Own config | read at ~/.config/devin/config.json (--config overrides it) |
/settings in an interactive session |
Copilot has no skill subcommand and no non-interactive readback,
so /skills list inside a session is the check that counts —
its "No skills found" message names the dirs it scanned, which is how the ~/.copilot/skills link was found to be necessary.
Do not trust the ~/.agents/skills path from the GitHub docs alone; the running binary is the authority.
For the rest, copilot --log-level debug --log-dir /tmp/cop -p 'hi' is the ground truth:
the log warns per agent file on an unknown frontmatter key (effort is Claude-only, and both CLIs ignore it),
and records that model: haiku maps to claude-haiku-4.5.
zsh keeps its drop-in idea: ~/.zshrc is a thin loader sourcing ~/.config/zsh/*.zsh in NN- prefix order,
and machine-local uncommitted overrides go in ~/.config/zsh/90-local.zsh
(a plain untracked file; see 90-local.zsh.example).
mkdir -p packages/<tool>/dot-config/<tool>and copy the non-secret config file(s) in, usingdot-names for anything dotted.- Add a
home.fileentry for each file in a newnix/home/<tool>.nix, import it fromnix/home/default.nix, and add<tool>toHM_PACKAGESin the Makefile (drives doctor's link checks). git addthe new files,make nix-switch, review, then commit.
Nothing outside packages/ is ever linked into $HOME, and no package references a credential-bearing file.
.gitignore blocks secret-like filenames as a second layer, and make doctor fails on secret-pattern filenames, credential-looking content in tracked files, or a ~/.config dir that has become a symlink.
Nothing imports live machine files automatically any more; copy configs into packages/ by hand and review git diff before committing.
Apache-2.0. Vendored skills and extensions remain under their upstream licenses; see each resource's source metadata.