You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
harness: devin + copilot CLIs share the repo's skills, agents, and rules
Devin CLI and GitHub Copilot CLI were the two harnesses still configured by
hand. Both now link out-of-store into the repo, the same way ~/.claude-* and
~/.pi do.
One skills link serves both: `~/.agents/skills` is the personal-skills path
each CLI reads, so their per-tool skills dirs stay unlinked — a second link
would register every skill twice. Every packages/claude/agents/*.md links in
per-file under the name each tool expects: `<name>.md` for Devin (it takes
the Claude agent format as-is) and `<name>.agent.md` for Copilot. Global
always-on rules come from the new, harness-neutral packages/agents/AGENTS.md;
packages/claude/CLAUDE.md stays Claude-only because of its $CLAUDE_CONFIG_DIR
paths.
Of each CLI's own config only the user-editable file is managed
(packages/devin/config.json, packages/copilot/settings.json), with the herdr
hook paths parametrized to $HOME. ~/.copilot/config.json holds login state and
the two herdr-agent-state.sh scripts are herdr-installed, so all three stay
local files; doctor now fails if the Copilot login file becomes a symlink and
checks each new link.
Verified live: `devin skills list` reads the repo tree, `devin doctor` loads
all six subagent profiles, `devin rules list` shows AGENTS always-on, and
Copilot runs `--agent bulk-mechanic` and answers from copilot-instructions.md.
Copilot's own skills dir is gated behind the account feature flag
SKILLS_INSTRUCTIONS, false today — the link is in place but idle on that side.
Copy file name to clipboardExpand all lines: CLAUDE.md
+14-4Lines changed: 14 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,6 +8,7 @@ One repo for the whole machine:
8
8
9
9
-**macOS system** — a nix-darwin + home-manager flake (`flake.nix`, `nix/`): `nix/darwin/` declares macOS defaults and every Homebrew formula/cask/mas/vscode entry, `nix/home/` declares dotfile links and CLI packages. Dotfile sources live under `packages/` (stow-style `dot-` names, linked per-file by home-manager); tool manifests under `manifests/`; `bootstrap.sh` for new Macs; `macos/defaults.sh` is Helium-browser-only.
10
10
-**pi** (the `pi-mono` coding agent) — config lives under `packages/pi/` and is linked into `~/.pi` by home-manager (`nix/home/harness.nix`).
11
+
-**Devin CLI and GitHub Copilot CLI** — each CLI's user-editable config lives under `packages/devin/` and `packages/copilot/`, its global rules in the shared `packages/agents/AGENTS.md`, and both read the repo's `skills/` tree through one `~/.agents/skills` link (`nix/home/harness.nix`).
11
12
-**Claude Code** — a shared global `CLAUDE.md`, `skills/`, `commands/`, `rules/`, `scripts/`, and `agents/` are symlinked into `~/.claude-personal/` and `~/.claude-work/`.
12
13
13
14
There is no application to build/test/lint.
@@ -158,10 +159,19 @@ Why not let the `skills` CLI own installation directly (its `add`/`update`/`expe
158
159
Entry names come from the package dirs at eval time, so a vendored addition is picked up by the next `make nix-switch`.
159
160
That means `packages/pi/agent/settings.json`, `packages/pi/extensions/*.ts`, and `packages/pi/prompts/` are the live files the agent reads — edits here take effect immediately in `~/.pi/...`.
160
161
162
+
-**Devin CLI and Copilot CLI share the repo's skills and agents** (`nix/home/harness.nix`).
163
+
`~/.agents/skills` is the one personal-skills path both CLIs read, so it links to `skills/` and their per-tool skills dirs are deliberately left unlinked (a second link would make every skill discovered twice).
164
+
Every `packages/claude/agents/*.md` links into `~/.config/devin/agents/<name>.md` (Devin takes the Claude agent format as-is) and `~/.copilot/agents/<name>.agent.md` (Copilot needs that suffix) — one source file, two names, derived from the dir at eval time like the pi links.
165
+
Of each CLI's own config only the user-editable file is managed: `~/.config/devin/config.json` and `~/.copilot/settings.json`.
166
+
Both are live out-of-store links, so a write by the tool (Devin records `shell.setup_complete`; herdr rewrites its hook block on reinstall) lands in the repo as a visible `git diff`, or replaces the link with a real file if the tool writes by temp+rename (`make doctor` flags that) — review either rather than reverting blindly.
167
+
**Never manage**`~/.copilot/config.json` (login state) or either `herdr-agent-state.sh` (herdr-installed, its header says a reinstall overwrites it).
168
+
To check what each CLI really loaded (not just that the link exists), see README.md § "Verifying what each CLI actually loaded": `devin doctor` / `devin skills list` / `devin rules list`, and for Copilot a `--log-level debug` run.
169
+
Copilot's skills dir is gated by the account feature flag `SKILLS_INSTRUCTIONS`, `false` today — the `~/.agents/skills` link is in place but idle on that side; Devin reads it now.
170
+
`packages/agents/AGENTS.md` is the shared global rules file for these two CLIs (linked as `~/.config/devin/AGENTS.md` and `~/.copilot/copilot-instructions.md`); keep it harness-neutral — `packages/claude/CLAUDE.md` stays Claude-only because it uses `$CLAUDE_CONFIG_DIR` paths.
161
171
-**`packages/pi/extensions/subagent/` is a directory extension** (listed without `.ts` suffix in `PI_EXTENSIONS`); the rest are single-file TS extensions.
162
172
Adding a new upstream extension requires editing `PI_EXTENSIONS` in the Makefile.
163
-
-**`skills/` is the single source of truth** for skills across pi and both Claude profiles.
164
-
The `claude` and `pi` packages each carry a committed `skills -> ../../skills` symlink, so the harness links expose the tree at `~/.pi/skills`, `~/.claude-personal/skills`, `~/.claude-work/skills`.
173
+
-**`skills/` is the single source of truth** for skills across pi, both Claude profiles, Devin CLI, and Copilot CLI.
174
+
The `claude` and `pi` packages each carry a committed `skills -> ../../skills` symlink, so the harness links expose the tree at `~/.pi/skills`, `~/.claude-personal/skills`, `~/.claude-work/skills`; `~/.agents/skills` links straight to `skills/` and serves Devin and Copilot.
165
175
What's *committed* under it, though, is only the authored skill dirs (their source records live in `sources.toml`); vendored skill dirs are gitignored and materialized into place (see the manifest model above), so the symlinked tree the tools read is authored-committed + vendored-materialized.
166
176
-**`packages/claude/commands/`, `packages/claude/rules/`, `packages/claude/scripts/`, and `packages/claude/agents/`** are the single source of truth for user-scoped slash commands, rules, helper scripts, and subagents across both Claude profiles.
167
177
`commands-link` / `rules-link` / `scripts-link` / `agents-link` symlink them into `~/.claude-personal/` and `~/.claude-work/` (not into `~/.pi/` — pi doesn't consume these; pi has its own vendored `packages/pi/extensions/subagent/agents/`).
@@ -208,9 +218,9 @@ Agents are single `.md` files fetched and tracked by `resource-manager.sh` (see
208
218
## Dotfiles conventions
209
219
210
220
-`$HOME` dotfiles are linked per-file by home-manager (`nix/home/*.nix` pointing at `packages/` sources) — the per-file discipline is a security invariant, explained in README.md § "The nix model"; never point `home.file` at a whole directory.
211
-
The harness links (`~/.claude-*`, `~/.pi`) are home-manager out-of-store symlinks (`nix/home/harness.nix`) so the linked content stays mutable; `~/.pi/agent` and `~/.pi/extensions`link per-file because pi writes state beside them.
221
+
The harness links (`~/.claude-*`, `~/.pi`, `~/.agents`, `~/.config/devin`, `~/.copilot`) are home-manager out-of-store symlinks (`nix/home/harness.nix`) so the linked content stays mutable; `~/.pi/agent`, `~/.pi/extensions`, and the Devin/Copilot agent dirs link per-file because those tools write state beside them.
212
222
- File names in `packages/` use the `dot-` prefix (`dot-zshrc` → `~/.zshrc`), mapped by the `home.file` entries in `nix/home/`.
213
-
- Never add packages for credential-bearing dirs: `gh/hosts.yml`, `gcloud`, `1Password`, `op`, `github-copilot`.
223
+
- Never add packages for credential-bearing dirs or files: `gh/hosts.yml`, `gcloud`, `1Password`, `op`, `github-copilot`, `~/.copilot/config.json`.
214
224
-`nix/darwin/homebrew.nix` is the curated brew list (`cleanup = "uninstall"`: an undeclared install is removed on the next switch — promote keepers first); `Brewfile.dump` (gitignored) is regenerated via `make brew-dump` for re-curation diffs only. CLI packages come from nixpkgs via `nix/home/packages.nix`.
215
225
-`bootstrap.sh` is the new-Mac entry point; keep it idempotent, check-then-act.
216
226
- To add a new tool config, follow the numbered recipe in README.md § "Adding a new tool config"; it is the canonical version.
Copy file name to clipboardExpand all lines: README.md
+35-6Lines changed: 35 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
# dotfiles
2
2
3
-
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](https://claude.com/claude-code)and[pi](https://github.com/badlogic/pi-mono) profiles.
3
+
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](https://claude.com/claude-code)profiles,[pi](https://github.com/badlogic/pi-mono), [Devin CLI](https://docs.devin.ai/cli/), and [GitHub Copilot CLI](https://docs.github.com/en/copilot/concepts/agents/about-copilot-cli).
4
4
5
5
A personal repo, published so others can borrow the architecture.
6
6
Paths are hardcoded to one machine — adapt before adopting (see [Adopt it](#adopt-it)).
@@ -19,7 +19,8 @@ On an existing machine, clone the repo and run `make install`.
19
19
## Ideas worth stealing
20
20
21
21
-**One source of truth, many harnesses.**
22
-
A single `skills/` tree feeds Claude Code *and* pi; edit once, every harness sees it immediately.
22
+
A single `skills/` tree feeds Claude Code, pi, Devin CLI, and Copilot CLI; edit once, every harness sees it immediately.
23
+
Devin and Copilot both read `~/.agents/skills`, so one link covers both; the same `agents/*.md` files link into each CLI under the name it expects.
23
24
-**Two Claude profiles via `CLAUDE_CONFIG_DIR`.**
24
25
`pclaude` / `wclaude` wrappers keep personal and work accounts isolated while sharing the same skills and rules.
`make install` links `skills/` and `claude/*` into both Claude profiles and `pi/` into `~/.pi` (home-manager out-of-store symlinks) — safe to re-run.
70
+
`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.
67
71
Because everything is symlinked, one edit here applies to every profile and both harnesses at once.
68
72
69
73
## What's inside
@@ -161,7 +165,7 @@ Dotfile sources stay in `packages/` with their `dot-` names;
161
165
home-manager links each file individually into `$HOME`,
162
166
so `~/.config/<tool>` stays a real directory and credential files written beside managed configs
163
167
(e.g. `gh`'s `hosts.yml`) can never land in the repo — the old `--no-folding` invariant, kept.
164
-
Never declare files from credential-bearing dirs (`gcloud`, `1Password`, `op`, `github-copilot`).
168
+
Never declare files from credential-bearing dirs (`gcloud`, `1Password`, `op`, `github-copilot`) or credential-bearing files (`gh/hosts.yml`, `~/.copilot/config.json`).
165
169
Every switch is a numbered generation; `make nix-rollback` returns to the previous one.
166
170
Homebrew remains for casks/taps/mas (declared in `nix/darwin/homebrew.nix`, applied by the same switch,
167
171
`cleanup = "uninstall"`: an undeclared install is removed on the next switch — promote keepers first).
@@ -172,11 +176,36 @@ and never let home-manager own a directory that holds mutable files.
172
176
173
177
### Harness links
174
178
175
-
The harness targets (`~/.claude-*`, `~/.pi`) are home-manager **out-of-store** symlinks into the repo working tree (`nix/home/harness.nix`) —
179
+
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`) —
176
180
the linked content stays mutable, so vendored skills materialize in place and repo edits apply live.
177
-
`~/.pi/agent` and `~/.pi/extensions`link per-file on purpose: pi writes state beside them,
181
+
`~/.pi/agent`, `~/.pi/extensions`, and the Devin/Copilot agent dirs link per-file on purpose: those tools write state beside them,
178
182
and a whole-dir link would let a tool write into the repo.
179
183
184
+
Devin CLI and Copilot CLI both read personal skills from `~/.agents/skills`, so one link serves both.
185
+
The subagents in `packages/claude/agents/` link into `~/.config/devin/agents/<name>.md` and `~/.copilot/agents/<name>.agent.md` — same file, two names.
186
+
Global always-on rules come from `packages/agents/AGENTS.md`, linked as `~/.config/devin/AGENTS.md` and `~/.copilot/copilot-instructions.md`.
187
+
Of each CLI's own config, only the user-editable file is managed (`~/.config/devin/config.json`, `~/.copilot/settings.json`);
188
+
`~/.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.
189
+
190
+
#### Verifying what each CLI actually loaded
191
+
192
+
`make doctor` checks that the links resolve into the repo; these commands check that the tools *use* them.
193
+
194
+
| Check | Devin CLI | Copilot CLI |
195
+
| --- | --- | --- |
196
+
| 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 |
197
+
| Skills |`devin skills list` — each skill with its `~/personal/dotfiles/skills/...` path | not yet active on this account (see below) |
198
+
| Global rules |`devin rules list` — `AGENTS [Standard] always-on`|`copilot -s -p '…answer from your instructions only…'` — it answers from `copilot-instructions.md`|
199
+
| Own config | read at `~/.config/devin/config.json` (`--config` overrides it) |`/settings` in an interactive session |
200
+
201
+
Copilot loads its skills dir behind an account feature flag.
202
+
To read the flag: `copilot --log-level debug --log-dir /tmp/cop -p 'hi'`, then `grep SKILLS_INSTRUCTIONS /tmp/cop/*.log`.
203
+
On this account it is `false` today, so the `~/.agents/skills` link is in place but idle;
204
+
the 0.0.417 binary already carries the path, and Devin reads the same link now.
205
+
The same debug log is the ground truth for the other two:
206
+
it warns per agent file on an unknown frontmatter key (`effort` is Claude-only, and both CLIs ignore it),
207
+
and Copilot maps `model: haiku` to `claude-haiku-4.5`.
208
+
180
209
zsh keeps its drop-in idea: `~/.zshrc` is a thin loader sourcing `~/.config/zsh/*.zsh` in `NN-` prefix order,
181
210
and machine-local uncommitted overrides go in `~/.config/zsh/90-local.zsh`
182
211
(a plain untracked file; see `90-local.zsh.example`).
0 commit comments