Skip to content

Commit bfb39b9

Browse files
committed
harness: copilot reads ~/.copilot/skills, not ~/.agents/skills
`/skills list` in Copilot CLI 0.0.417 reported "No skills found" and named the dirs it scans: ~/.copilot/skills, ~/.claude/skills, and the two project dirs. The GitHub docs list ~/.agents/skills and the binary carries the string, but the running CLI does not read it — so each CLI now gets its own link to the same skills/ tree. Devin keeps ~/.agents/skills; the two paths never collide, so no skill is registered twice. Docs record the check that settles this (an in-session `/skills list`, which prints the scanned dirs) as authoritative over both the docs and the SKILLS_INSTRUCTIONS debug-log flag, and doctor checks the new link.
1 parent 29ee084 commit bfb39b9

4 files changed

Lines changed: 24 additions & 18 deletions

File tree

CLAUDE.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ One repo for the whole machine:
88

99
- **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.
1010
- **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+
- **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 each reads the repo's `skills/` tree through its own link — `~/.agents/skills` for Devin, `~/.copilot/skills` for Copilot (`nix/home/harness.nix`).
1212
- **Claude Code** — a shared global `CLAUDE.md`, `skills/`, `commands/`, `rules/`, `scripts/`, and `agents/` are symlinked into `~/.claude-personal/` and `~/.claude-work/`.
1313

1414
There is no application to build/test/lint.
@@ -160,18 +160,19 @@ Why not let the `skills` CLI own installation directly (its `add`/`update`/`expe
160160
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/...`.
161161

162162
- **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).
163+
Each CLI gets its own link to the `skills/` tree, because they scan different paths: Devin reads `~/.agents/skills`, Copilot 0.0.417 reads `~/.copilot/skills` (plus `~/.claude/skills` and the project dirs) and ignores `~/.agents/skills`, whatever the GitHub docs say.
164+
The two links never collide, so no skill is registered twice; verify a change with `/skills list` inside a Copilot session, which prints the dirs it scanned.
164165
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.
165166
Of each CLI's own config only the user-editable file is managed: `~/.config/devin/config.json` and `~/.copilot/settings.json`.
166167
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.
167168
**Never manage** `~/.copilot/config.json` (login state) or either `herdr-agent-state.sh` (herdr-installed, its header says a reinstall overwrites it).
168169
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+
Copilot has no `skill` subcommand and no non-interactive readback, so trust `/skills list` in a session over the docs and over the `SKILLS_INSTRUCTIONS` debug-log flag (which reads `false` while `/skills` works).
170171
`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.
171172
- **`packages/pi/extensions/subagent/` is a directory extension** (listed without `.ts` suffix in `PI_EXTENSIONS`); the rest are single-file TS extensions.
172173
Adding a new upstream extension requires editing `PI_EXTENSIONS` in the Makefile.
173174
- **`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.
175+
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` and `~/.copilot/skills` link straight to `skills/` for Devin and Copilot.
175176
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.
176177
- **`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.
177178
`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/`).

README.md

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ On an existing machine, clone the repo and run `make install`.
2020

2121
- **One source of truth, many harnesses.**
2222
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+
Devin reads `~/.agents/skills` and Copilot reads `~/.copilot/skills`; both links point at the same tree, and the same `agents/*.md` files link into each CLI under the name it expects.
2424
- **Two Claude profiles via `CLAUDE_CONFIG_DIR`.**
2525
`pclaude` / `wclaude` wrappers keep personal and work accounts isolated while sharing the same skills and rules.
2626
- **Per-resource source tracking.**
@@ -181,7 +181,8 @@ the linked content stays mutable, so vendored skills materialize in place and re
181181
`~/.pi/agent`, `~/.pi/extensions`, and the Devin/Copilot agent dirs link per-file on purpose: those tools write state beside them,
182182
and a whole-dir link would let a tool write into the repo.
183183

184-
Devin CLI and Copilot CLI both read personal skills from `~/.agents/skills`, so one link serves both.
184+
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.
185+
Each CLI therefore gets its own link to the same `skills/` tree — the paths never collide, so no skill is discovered twice.
185186
The subagents in `packages/claude/agents/` link into `~/.config/devin/agents/<name>.md` and `~/.copilot/agents/<name>.agent.md` — same file, two names.
186187
Global always-on rules come from `packages/agents/AGENTS.md`, linked as `~/.config/devin/AGENTS.md` and `~/.copilot/copilot-instructions.md`.
187188
Of each CLI's own config, only the user-editable file is managed (`~/.config/devin/config.json`, `~/.copilot/settings.json`);
@@ -194,17 +195,17 @@ Of each CLI's own config, only the user-editable file is managed (`~/.config/dev
194195
| Check | Devin CLI | Copilot CLI |
195196
| --- | --- | --- |
196197
| 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+
| Skills | `devin skills list` — each skill with its `~/personal/dotfiles/skills/...` path | `/skills list` in an interactive session — it prints the dirs it scanned |
198199
| Global rules | `devin rules list``AGENTS [Standard] always-on` | `copilot -s -p '…answer from your instructions only…'` — it answers from `copilot-instructions.md` |
199200
| Own config | read at `~/.config/devin/config.json` (`--config` overrides it) | `/settings` in an interactive session |
200201

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`.
202+
Copilot has no `skill` subcommand and no non-interactive readback,
203+
so `/skills list` inside a session is the check that counts —
204+
its "No skills found" message names the dirs it scanned, which is how the `~/.copilot/skills` link was found to be necessary.
205+
Do not trust the `~/.agents/skills` path from the GitHub docs alone; the running binary is the authority.
206+
For the rest, `copilot --log-level debug --log-dir /tmp/cop -p 'hi'` is the ground truth:
207+
the log warns per agent file on an unknown frontmatter key (`effort` is Claude-only, and both CLIs ignore it),
208+
and records that `model: haiku` maps to `claude-haiku-4.5`.
208209

209210
zsh keeps its drop-in idea: `~/.zshrc` is a thin loader sourcing `~/.config/zsh/*.zsh` in `NN-` prefix order,
210211
and machine-local uncommitted overrides go in `~/.config/zsh/90-local.zsh`

nix/home/harness.nix

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,11 @@ let
4848
".pi/README.md".source = link "packages/pi/README.md";
4949
};
5050

51-
# Devin CLI and Copilot CLI both read personal skills from ~/.agents/skills,
52-
# so one link serves both — never link their per-tool skills dirs too, or a
53-
# skill is discovered twice.
51+
# Devin reads personal skills from ~/.agents/skills. Copilot 0.0.417 does not
52+
# scan that path yet (its /skills list names ~/.copilot/skills, ~/.claude/skills
53+
# and the two project dirs), so it gets its own link to the same tree. The two
54+
# links never collide: each CLI reads only its own path, so no skill is
55+
# discovered twice.
5456
agentNames = map (lib.removeSuffix ".md") (
5557
builtins.attrNames (lib.filterAttrs (n: _: lib.hasSuffix ".md" n) (
5658
builtins.readDir ../../packages/claude/agents
@@ -74,6 +76,7 @@ let
7476
# (login state), and both herdr-installed hook scripts, stay local files.
7577
cliLinks = {
7678
".agents/skills".source = link "skills";
79+
".copilot/skills".source = link "skills";
7780
".config/devin/config.json".source = link "packages/devin/config.json";
7881
".config/devin/AGENTS.md".source = link "packages/agents/AGENTS.md";
7982
".copilot/settings.json".source = link "packages/copilot/settings.json";

scripts/doctor.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,8 @@ else
153153
fi
154154
for t in "$HOME/.claude-personal/CLAUDE.md" "$HOME/.claude-work/CLAUDE.md" "$HOME/.pi/skills" \
155155
"$HOME/.agents/skills" "$HOME/.config/devin/config.json" "$HOME/.config/devin/AGENTS.md" \
156-
"$HOME/.copilot/settings.json" "$HOME/.copilot/copilot-instructions.md"; do
156+
"$HOME/.copilot/settings.json" "$HOME/.copilot/copilot-instructions.md" \
157+
"$HOME/.copilot/skills"; do
157158
r="$(resolve "$t")"
158159
case "$r" in
159160
"$REPO_DIR"/*) ok "$t -> repo" ;;

0 commit comments

Comments
 (0)