Framework skills are vendor-neutral content: every supported
agent reads the same SKILL.md (the open Agent Skills format —
plain Markdown + a small YAML frontmatter). The skill body is
byte-identical no matter which agent loads it; there is no
per-agent compile, adapter, or content transform. The only thing
that genuinely differs between agents is where on disk each one
looks for skills. This file is the registry of those locations —
the single source of truth adopt, upgrade, verify,
unadopt, and worktree-init consult to decide which directories
to wire, refresh, health-check, and tear down.
It is the magpie analogue of a package manager's per-agent path table: keep all vendor-specific knowledge here as "where files go", never as "what files contain".
| Target id | Project skills dir | Kind | Reads it |
|---|---|---|---|
universal |
.agents/skills/ |
universal (canonical) | Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode, Cline, Zed, Warp, Amp, and the rest of the cluster that converged on the shared path |
claude-code |
.claude/skills/ |
native (relay) | Claude Code |
github |
.github/skills/ |
native (relay) | GitHub's skill loader |
windsurf |
.windsurf/skills/ |
native (relay) | Windsurf |
goose |
.goose/skills/ |
native (relay) | Goose |
kiro |
.kiro/skills/ |
native (relay) | Kiro CLI |
The table is extensible: a new agent that wants framework
skills is one new row (id, project dir, kind), nothing else —
the same way a path-registry-driven installer adds an agent. Do
not invent per-agent content; if an agent needs a different
directory, add a row, never a forked skill.
.agents/skills/ is the one canonical home for every framework
skill. Its magpie-<skill> entries are the links that resolve to
the actual skill source — the gitignored snapshot
(.apache-magpie/skills/<skill>/) for a normal adopter, or the
in-repo ../../skills/<skill>/ source for the framework's own
local self-adoption.
This is the load-bearing move for neutrality on two fronts:
-
One placement covers the whole shared-path cluster. A large set of agents (Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode, Cline, Zed, Warp, …) all read
.agents/skills/as their project-scope skills path, so a single.agents/skills/magpie-<skill>link is seen by all of them:.agents/skills/magpie-pr-management-triage → the canonical link ├─ Codex picks it up ├─ Cursor picks it up ├─ Gemini CLI picks it up └─ Copilot … picks it up -
Every other target is a thin relay into it. Agents with a bespoke folder (
claude-code→.claude/skills/,github→.github/skills/,windsurf,goose, …) do not link into the snapshot independently. Each one gets a per-skill relay symlink that points back at the canonical entry:.claude/skills/magpie-<skill> → ../../.agents/skills/magpie-<skill> .github/skills/magpie-<skill> → ../../.agents/skills/magpie-<skill>The snapshot path appears exactly once — in
.agents/skills/. Re-pointing the framework at a new snapshot, or repairing a broken link, is a single-source operation; the relays follow automatically. Adopters keep their own native (non-magpie-) skills in.claude/skills//.github/skills/untouched — only themagpie-*entries are relayed.
(Global / per-user skill paths diverge across agents — e.g.
~/.cursor/skills/, ~/.codex/skills/, ~/.gemini/skills/. The
framework's adoption is project-scope — it writes inside the
adopter repo — so it only ever cares about the project columns
above. Global installs are the operator's concern, out of scope
for setup.)
On every adopt / upgrade / worktree-init, the active
target set is computed as the union of:
- The always-on neutral targets —
universal(.agents/skills/, canonical) plus theclaude-code+githubrelay pair. These three are wired unconditionally; the relays are cheap relative symlinks, harmless to an agent that never reads them, and dropping them is not a supported configuration. - Any other registry target already present in the repo —
if
.windsurf/skills/or.goose/skills/(etc.) already exists as a real directory, it is added to the active set so that agent sees the framework skills too (as a relay). - Explicit opt-in via the
agents:<list>flag (seeSKILL.mdInputs) — a comma-separated list of registry ids. When passed it replaces the auto-detected set (1)+(2) for that run;universalis always retained even if omitted, because it is the canonical home every relay points at — dropping it would leave the relays dangling.
The flow never removes or rewrites an adopter's own
non-magpie- skill content in any target dir. It only adds /
repairs magpie-* symlinks. Whatever layout an adopter's
.claude/ / .github/ directories were in before, the framework
always wires the magpie-* set the same way: canonical in
.agents/skills/, relayed everywhere else.
Every adoption rule is "canonical link, then relays", not "per-target independent link":
magpie-prefix (SKILL.mdGolden rule 6) — unchanged. Every framework skill ismagpie-<skill>in every active target dir, so it never collides with an adopter's own skills regardless of agent..gitignore— one uniform block per active target dir, with no per-layout variation:/<dir>/magpie-*ignored plus!/<dir>/magpie-setupun-ignored. The negation keeps the one committed bootstrap (magpie-setup) tracked; the glob ignores the rest (the canonical links target the gitignored snapshot, so the relays that follow them dangle on a fresh clone). Seeadopt.mdStep 7.- Symlink wiring — the canonical
magpie-<n>→ snapshot/source link is created once in.agents/skills/; every other active target (claude-code,github,windsurf,goose, …) gets a per-skill relaymagpie-<n>→../../.agents/skills/magpie-<n>. Seeadopt.mdStep 8. - Committed bootstrap (
SKILL.mdGolden rule 6) — the one committed framework artefact,magpie-setup, lives at the canonical.agents/skills/magpie-setup/(a committed copy for adopters; a committed symlink under self-adoption)..claude/.githubcarry a committed relay symlink to it. - Local self-adoption (framework checkout) — canonical
committed symlinks into
../../skills/<skill>/in.agents/skills/, plus committed relays into../../.agents/skills/magpie-<skill>in every other active target. Seeadopt.md→ Local self-adoption. unadopt/worktree-init— every active target dir is torn down / propagated uniformly. Removing only.claude+.githubwould orphan the canonical.agents/skills/magpie-*links; removing only.agentswould leave every relay dangling.
The same SKILL.md is valid in every target with no
per-agent edit:
| Frontmatter field | Cross-agent behaviour |
|---|---|
name, description |
Universal — discovery works everywhere. |
when_to_use |
Claude-family routing hint; other agents may ignore it → discovery still works off description, only routing precision degrades. |
argument-hint, capability |
magpie / Claude extensions; non-supporting agents silently ignore them. |
license |
Inert metadata. |
Unknown frontmatter is ignored by each agent (graceful
degradation), so there is no compile step and no per-agent
file. The gitignored snapshot stays the single source of truth;
.agents/skills/ links into it, and every other target dir
resolves into it through the .agents/skills/ relay.
Some of what adopt installs is genuinely Claude-Code-specific
and is wired only when the claude-code target is active:
.claude/settings.json— the sandbox (network.allowedDomainsallowlist,filesystem.denyRead), the MCP-tool permission allowlist, and the hooks. Schema:claude-code-settings.json..claude/settings.local.json— per-machine sandbox-allowlist entries.- The
setup-isolated-setup-*skill family — sandbox / pinned- tools / hooks installer.
Other agents adopt the skills (the neutral content) without this layer.
Security caveat — this layer is a control, not cosmetics. For a security framework the sandbox is a confidentiality control (it blocks exfiltration of non-public vulnerability data and reading
~/). Running a security-class skill on an agent that lacks an equivalent control is a policy decision, not graceful degradation. Adopting the skills onto a non-Claude agent is supported; executing confidential workflows there requires the project to either declare that agent unsupported for those workflows or provide an equivalent control.adoptitself only places files — it does not grant that approval.