This is an automated email from the ASF dual-hosted git repository.

potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow-steward.git


The following commit(s) were added to refs/heads/main by this push:
     new 544e8f9  feat(setup): self-adopt framework skills into .agents/skills/ 
(#458)
544e8f9 is described below

commit 544e8f9f97caa40d6314f0ee04bb47492799dc3a
Author: Yeonguk Choo <[email protected]>
AuthorDate: Sat Jun 6 01:27:05 2026 +0900

    feat(setup): self-adopt framework skills into .agents/skills/ (#458)
    
    * feat(setup): make adopt vendor-neutral across agents
    
    * feat(setup): self-adopt framework skills into .agents/skills/
---
 .agents/skills/magpie-audit-finding-fix            |   1 +
 .agents/skills/magpie-ci-runner-audit              |   1 +
 .agents/skills/magpie-committer-onboarding         |   1 +
 .agents/skills/magpie-contributor-activity-sweep   |   1 +
 .agents/skills/magpie-contributor-nomination       |   1 +
 .agents/skills/magpie-good-first-issue-author      |   1 +
 .agents/skills/magpie-issue-fix-workflow           |   1 +
 .agents/skills/magpie-issue-reassess               |   1 +
 .agents/skills/magpie-issue-reassess-stats         |   1 +
 .agents/skills/magpie-issue-reproducer             |   1 +
 .agents/skills/magpie-issue-triage                 |   1 +
 .agents/skills/magpie-list-skills                  |   1 +
 .agents/skills/magpie-optimize-skill               |   1 +
 .agents/skills/magpie-pairing-multi-agent-review   |   1 +
 .agents/skills/magpie-pairing-self-review          |   1 +
 .agents/skills/magpie-pr-management-code-review    |   1 +
 .agents/skills/magpie-pr-management-mentor         |   1 +
 .agents/skills/magpie-pr-management-quick-merge    |   1 +
 .agents/skills/magpie-pr-management-stats          |   1 +
 .agents/skills/magpie-pr-management-triage         |   1 +
 .agents/skills/magpie-security-cve-allocate        |   1 +
 .agents/skills/magpie-security-issue-deduplicate   |   1 +
 .agents/skills/magpie-security-issue-fix           |   1 +
 .agents/skills/magpie-security-issue-import        |   1 +
 .../skills/magpie-security-issue-import-from-md    |   1 +
 .../skills/magpie-security-issue-import-from-pr    |   1 +
 .../magpie-security-issue-import-via-forwarder     |   1 +
 .agents/skills/magpie-security-issue-invalidate    |   1 +
 .agents/skills/magpie-security-issue-sync          |   1 +
 .agents/skills/magpie-security-issue-triage        |   1 +
 .../skills/magpie-security-tracker-stats-dashboard |   1 +
 .agents/skills/magpie-setup                        |   1 +
 .agents/skills/magpie-setup-isolated-setup-doctor  |   1 +
 .agents/skills/magpie-setup-isolated-setup-install |   1 +
 .agents/skills/magpie-setup-isolated-setup-update  |   1 +
 .agents/skills/magpie-setup-isolated-setup-verify  |   1 +
 .agents/skills/magpie-setup-override-upstream      |   1 +
 .agents/skills/magpie-setup-shared-config-sync     |   1 +
 .agents/skills/magpie-write-skill                  |   1 +
 .gitignore                                         |   9 +-
 skills/setup/SKILL.md                              |  12 +-
 skills/setup/adopt.md                              |  84 +++++++---
 skills/setup/agents.md                             | 179 +++++++++++++++++++++
 skills/setup/conventions.md                        |  10 ++
 skills/setup/unadopt.md                            |  63 +++++---
 skills/setup/upgrade.md                            | 143 ++++++++++------
 skills/setup/verify.md                             |  94 ++++++-----
 skills/setup/worktree-init.md                      |  64 +++++---
 48 files changed, 537 insertions(+), 160 deletions(-)

diff --git a/.agents/skills/magpie-audit-finding-fix 
b/.agents/skills/magpie-audit-finding-fix
new file mode 120000
index 0000000..c32be1b
--- /dev/null
+++ b/.agents/skills/magpie-audit-finding-fix
@@ -0,0 +1 @@
+../../skills/audit-finding-fix
\ No newline at end of file
diff --git a/.agents/skills/magpie-ci-runner-audit 
b/.agents/skills/magpie-ci-runner-audit
new file mode 120000
index 0000000..d964738
--- /dev/null
+++ b/.agents/skills/magpie-ci-runner-audit
@@ -0,0 +1 @@
+../../skills/ci-runner-audit
\ No newline at end of file
diff --git a/.agents/skills/magpie-committer-onboarding 
b/.agents/skills/magpie-committer-onboarding
new file mode 120000
index 0000000..9f421b7
--- /dev/null
+++ b/.agents/skills/magpie-committer-onboarding
@@ -0,0 +1 @@
+../../skills/committer-onboarding
\ No newline at end of file
diff --git a/.agents/skills/magpie-contributor-activity-sweep 
b/.agents/skills/magpie-contributor-activity-sweep
new file mode 120000
index 0000000..4c4ad61
--- /dev/null
+++ b/.agents/skills/magpie-contributor-activity-sweep
@@ -0,0 +1 @@
+../../skills/contributor-activity-sweep
\ No newline at end of file
diff --git a/.agents/skills/magpie-contributor-nomination 
b/.agents/skills/magpie-contributor-nomination
new file mode 120000
index 0000000..84b98fd
--- /dev/null
+++ b/.agents/skills/magpie-contributor-nomination
@@ -0,0 +1 @@
+../../skills/contributor-nomination
\ No newline at end of file
diff --git a/.agents/skills/magpie-good-first-issue-author 
b/.agents/skills/magpie-good-first-issue-author
new file mode 120000
index 0000000..360135b
--- /dev/null
+++ b/.agents/skills/magpie-good-first-issue-author
@@ -0,0 +1 @@
+../../skills/good-first-issue-author
\ No newline at end of file
diff --git a/.agents/skills/magpie-issue-fix-workflow 
b/.agents/skills/magpie-issue-fix-workflow
new file mode 120000
index 0000000..7bb0e8d
--- /dev/null
+++ b/.agents/skills/magpie-issue-fix-workflow
@@ -0,0 +1 @@
+../../skills/issue-fix-workflow
\ No newline at end of file
diff --git a/.agents/skills/magpie-issue-reassess 
b/.agents/skills/magpie-issue-reassess
new file mode 120000
index 0000000..8e91821
--- /dev/null
+++ b/.agents/skills/magpie-issue-reassess
@@ -0,0 +1 @@
+../../skills/issue-reassess
\ No newline at end of file
diff --git a/.agents/skills/magpie-issue-reassess-stats 
b/.agents/skills/magpie-issue-reassess-stats
new file mode 120000
index 0000000..a5b2632
--- /dev/null
+++ b/.agents/skills/magpie-issue-reassess-stats
@@ -0,0 +1 @@
+../../skills/issue-reassess-stats
\ No newline at end of file
diff --git a/.agents/skills/magpie-issue-reproducer 
b/.agents/skills/magpie-issue-reproducer
new file mode 120000
index 0000000..c8cdab9
--- /dev/null
+++ b/.agents/skills/magpie-issue-reproducer
@@ -0,0 +1 @@
+../../skills/issue-reproducer
\ No newline at end of file
diff --git a/.agents/skills/magpie-issue-triage 
b/.agents/skills/magpie-issue-triage
new file mode 120000
index 0000000..a32c627
--- /dev/null
+++ b/.agents/skills/magpie-issue-triage
@@ -0,0 +1 @@
+../../skills/issue-triage
\ No newline at end of file
diff --git a/.agents/skills/magpie-list-skills 
b/.agents/skills/magpie-list-skills
new file mode 120000
index 0000000..a6c207d
--- /dev/null
+++ b/.agents/skills/magpie-list-skills
@@ -0,0 +1 @@
+../../skills/list-skills
\ No newline at end of file
diff --git a/.agents/skills/magpie-optimize-skill 
b/.agents/skills/magpie-optimize-skill
new file mode 120000
index 0000000..8cddd77
--- /dev/null
+++ b/.agents/skills/magpie-optimize-skill
@@ -0,0 +1 @@
+../../skills/optimize-skill
\ No newline at end of file
diff --git a/.agents/skills/magpie-pairing-multi-agent-review 
b/.agents/skills/magpie-pairing-multi-agent-review
new file mode 120000
index 0000000..ddb431c
--- /dev/null
+++ b/.agents/skills/magpie-pairing-multi-agent-review
@@ -0,0 +1 @@
+../../skills/pairing-multi-agent-review
\ No newline at end of file
diff --git a/.agents/skills/magpie-pairing-self-review 
b/.agents/skills/magpie-pairing-self-review
new file mode 120000
index 0000000..b2fccf7
--- /dev/null
+++ b/.agents/skills/magpie-pairing-self-review
@@ -0,0 +1 @@
+../../skills/pairing-self-review
\ No newline at end of file
diff --git a/.agents/skills/magpie-pr-management-code-review 
b/.agents/skills/magpie-pr-management-code-review
new file mode 120000
index 0000000..4b543a0
--- /dev/null
+++ b/.agents/skills/magpie-pr-management-code-review
@@ -0,0 +1 @@
+../../skills/pr-management-code-review
\ No newline at end of file
diff --git a/.agents/skills/magpie-pr-management-mentor 
b/.agents/skills/magpie-pr-management-mentor
new file mode 120000
index 0000000..02c3493
--- /dev/null
+++ b/.agents/skills/magpie-pr-management-mentor
@@ -0,0 +1 @@
+../../skills/pr-management-mentor
\ No newline at end of file
diff --git a/.agents/skills/magpie-pr-management-quick-merge 
b/.agents/skills/magpie-pr-management-quick-merge
new file mode 120000
index 0000000..a504c5a
--- /dev/null
+++ b/.agents/skills/magpie-pr-management-quick-merge
@@ -0,0 +1 @@
+../../skills/pr-management-quick-merge
\ No newline at end of file
diff --git a/.agents/skills/magpie-pr-management-stats 
b/.agents/skills/magpie-pr-management-stats
new file mode 120000
index 0000000..b1a1338
--- /dev/null
+++ b/.agents/skills/magpie-pr-management-stats
@@ -0,0 +1 @@
+../../skills/pr-management-stats
\ No newline at end of file
diff --git a/.agents/skills/magpie-pr-management-triage 
b/.agents/skills/magpie-pr-management-triage
new file mode 120000
index 0000000..4ae07e2
--- /dev/null
+++ b/.agents/skills/magpie-pr-management-triage
@@ -0,0 +1 @@
+../../skills/pr-management-triage
\ No newline at end of file
diff --git a/.agents/skills/magpie-security-cve-allocate 
b/.agents/skills/magpie-security-cve-allocate
new file mode 120000
index 0000000..6cc475b
--- /dev/null
+++ b/.agents/skills/magpie-security-cve-allocate
@@ -0,0 +1 @@
+../../skills/security-cve-allocate
\ No newline at end of file
diff --git a/.agents/skills/magpie-security-issue-deduplicate 
b/.agents/skills/magpie-security-issue-deduplicate
new file mode 120000
index 0000000..63f6e88
--- /dev/null
+++ b/.agents/skills/magpie-security-issue-deduplicate
@@ -0,0 +1 @@
+../../skills/security-issue-deduplicate
\ No newline at end of file
diff --git a/.agents/skills/magpie-security-issue-fix 
b/.agents/skills/magpie-security-issue-fix
new file mode 120000
index 0000000..40c0839
--- /dev/null
+++ b/.agents/skills/magpie-security-issue-fix
@@ -0,0 +1 @@
+../../skills/security-issue-fix
\ No newline at end of file
diff --git a/.agents/skills/magpie-security-issue-import 
b/.agents/skills/magpie-security-issue-import
new file mode 120000
index 0000000..d80190b
--- /dev/null
+++ b/.agents/skills/magpie-security-issue-import
@@ -0,0 +1 @@
+../../skills/security-issue-import
\ No newline at end of file
diff --git a/.agents/skills/magpie-security-issue-import-from-md 
b/.agents/skills/magpie-security-issue-import-from-md
new file mode 120000
index 0000000..3c96cda
--- /dev/null
+++ b/.agents/skills/magpie-security-issue-import-from-md
@@ -0,0 +1 @@
+../../skills/security-issue-import-from-md
\ No newline at end of file
diff --git a/.agents/skills/magpie-security-issue-import-from-pr 
b/.agents/skills/magpie-security-issue-import-from-pr
new file mode 120000
index 0000000..41c4085
--- /dev/null
+++ b/.agents/skills/magpie-security-issue-import-from-pr
@@ -0,0 +1 @@
+../../skills/security-issue-import-from-pr
\ No newline at end of file
diff --git a/.agents/skills/magpie-security-issue-import-via-forwarder 
b/.agents/skills/magpie-security-issue-import-via-forwarder
new file mode 120000
index 0000000..213f546
--- /dev/null
+++ b/.agents/skills/magpie-security-issue-import-via-forwarder
@@ -0,0 +1 @@
+../../skills/security-issue-import-via-forwarder
\ No newline at end of file
diff --git a/.agents/skills/magpie-security-issue-invalidate 
b/.agents/skills/magpie-security-issue-invalidate
new file mode 120000
index 0000000..7b07030
--- /dev/null
+++ b/.agents/skills/magpie-security-issue-invalidate
@@ -0,0 +1 @@
+../../skills/security-issue-invalidate
\ No newline at end of file
diff --git a/.agents/skills/magpie-security-issue-sync 
b/.agents/skills/magpie-security-issue-sync
new file mode 120000
index 0000000..b4f409e
--- /dev/null
+++ b/.agents/skills/magpie-security-issue-sync
@@ -0,0 +1 @@
+../../skills/security-issue-sync
\ No newline at end of file
diff --git a/.agents/skills/magpie-security-issue-triage 
b/.agents/skills/magpie-security-issue-triage
new file mode 120000
index 0000000..162016a
--- /dev/null
+++ b/.agents/skills/magpie-security-issue-triage
@@ -0,0 +1 @@
+../../skills/security-issue-triage
\ No newline at end of file
diff --git a/.agents/skills/magpie-security-tracker-stats-dashboard 
b/.agents/skills/magpie-security-tracker-stats-dashboard
new file mode 120000
index 0000000..ea7df87
--- /dev/null
+++ b/.agents/skills/magpie-security-tracker-stats-dashboard
@@ -0,0 +1 @@
+../../skills/security-tracker-stats-dashboard
\ No newline at end of file
diff --git a/.agents/skills/magpie-setup b/.agents/skills/magpie-setup
new file mode 120000
index 0000000..8f69d9c
--- /dev/null
+++ b/.agents/skills/magpie-setup
@@ -0,0 +1 @@
+../../skills/setup
\ No newline at end of file
diff --git a/.agents/skills/magpie-setup-isolated-setup-doctor 
b/.agents/skills/magpie-setup-isolated-setup-doctor
new file mode 120000
index 0000000..44f2819
--- /dev/null
+++ b/.agents/skills/magpie-setup-isolated-setup-doctor
@@ -0,0 +1 @@
+../../skills/setup-isolated-setup-doctor
\ No newline at end of file
diff --git a/.agents/skills/magpie-setup-isolated-setup-install 
b/.agents/skills/magpie-setup-isolated-setup-install
new file mode 120000
index 0000000..794d890
--- /dev/null
+++ b/.agents/skills/magpie-setup-isolated-setup-install
@@ -0,0 +1 @@
+../../skills/setup-isolated-setup-install
\ No newline at end of file
diff --git a/.agents/skills/magpie-setup-isolated-setup-update 
b/.agents/skills/magpie-setup-isolated-setup-update
new file mode 120000
index 0000000..fabb0d7
--- /dev/null
+++ b/.agents/skills/magpie-setup-isolated-setup-update
@@ -0,0 +1 @@
+../../skills/setup-isolated-setup-update
\ No newline at end of file
diff --git a/.agents/skills/magpie-setup-isolated-setup-verify 
b/.agents/skills/magpie-setup-isolated-setup-verify
new file mode 120000
index 0000000..d76e89a
--- /dev/null
+++ b/.agents/skills/magpie-setup-isolated-setup-verify
@@ -0,0 +1 @@
+../../skills/setup-isolated-setup-verify
\ No newline at end of file
diff --git a/.agents/skills/magpie-setup-override-upstream 
b/.agents/skills/magpie-setup-override-upstream
new file mode 120000
index 0000000..a9cee55
--- /dev/null
+++ b/.agents/skills/magpie-setup-override-upstream
@@ -0,0 +1 @@
+../../skills/setup-override-upstream
\ No newline at end of file
diff --git a/.agents/skills/magpie-setup-shared-config-sync 
b/.agents/skills/magpie-setup-shared-config-sync
new file mode 120000
index 0000000..f850cf0
--- /dev/null
+++ b/.agents/skills/magpie-setup-shared-config-sync
@@ -0,0 +1 @@
+../../skills/setup-shared-config-sync
\ No newline at end of file
diff --git a/.agents/skills/magpie-write-skill 
b/.agents/skills/magpie-write-skill
new file mode 120000
index 0000000..f512e9d
--- /dev/null
+++ b/.agents/skills/magpie-write-skill
@@ -0,0 +1 @@
+../../skills/write-skill
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 1f5f751..2e03f05 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,11 +8,14 @@ logs
 # Skill source lives in skills/. The framework self-adopts by
 # committing magpie-<skill> symlinks that point into ../../skills/<skill>/
 # (see skills/setup/adopt.md → "Local self-adoption"). They live under
-# BOTH .claude/skills/ (Claude Code) and .github/skills/ (GitHub's skill
-# loader). Those symlinks ARE committed — their targets are in-repo and
-# always resolve on a fresh clone, so every contributor gets the skills
+# the universal .agents/skills/ path (Codex, Cursor, Gemini CLI, Copilot,
+# …) plus BOTH .claude/skills/ (Claude Code) and .github/skills/ (GitHub's
+# skill loader). Those symlinks ARE committed — their targets are in-repo
+# and always resolve on a fresh clone, so every contributor gets the skills
 # active with no setup step. Everything else dropped into these dirs
 # stays local.
+.agents/skills/*
+!/.agents/skills/magpie-*
 .claude/skills/*
 !/.claude/skills/magpie-*
 .github/skills/*
diff --git a/skills/setup/SKILL.md b/skills/setup/SKILL.md
index d671d9c..10c1953 100644
--- a/skills/setup/SKILL.md
+++ b/skills/setup/SKILL.md
@@ -100,9 +100,11 @@ Apache Magpie framework checkout itself — a remote 
snapshot of the
 framework into itself would be circular. Instead it **self-adopts**
 with `method:local`: each `magpie-<skill>` is a **committed**
 symlink into the in-repo `../../skills/<skill>/` source — written
-under both `.claude/skills/` (Claude Code) and `.github/skills/`
-(GitHub's skill loader) — with no snapshot, no remote fetch, and
-no copy. This makes
+under **every active agent target** ([`agents.md`](agents.md)):
+`.agents/skills/` (the universal path shared by Codex, Cursor,
+Gemini CLI, Copilot, …), `.claude/skills/` (Claude Code), and
+`.github/skills/` (GitHub's skill loader) — with no snapshot, no
+remote fetch, and no copy. This makes
 the framework's own skills callable while developing the framework,
 and every contributor gets them active on a fresh clone with no
 setup step. `adopt` detects the framework checkout structurally and
@@ -170,7 +172,8 @@ proposed `/magpie-setup upgrade`.
 | [`adopt.md`](adopt.md) | First-time adoption walk-through — recognise 
existing-snapshot vs needs-bootstrap, write the two lock files, ask the user 
which skill families to wire up, create the gitignored symlinks, scaffold 
`.apache-magpie-overrides/`, install the post-checkout hook, update project 
docs. The default sub-action. |
 | [`upgrade.md`](upgrade.md) | Refresh the gitignored snapshot per the 
committed lock, reconcile any agentic overrides + symlinks against the new 
framework structure, surface conflicts. Drives the on-drift remediation flow. |
 | [`verify.md`](verify.md) | Read-only health check — snapshot present + 
intact, both lock files in sync, symlinks point at live targets, `.gitignore` 
correct, `.apache-magpie-overrides/` exists, drift status (committed vs local), 
the `setup` skill itself is current. |
-| [`conventions.md`](conventions.md) | Adopter skills-dir convention 
auto-detection — four patterns: A (flat `.claude/skills/<n>/`), B (per-skill 
`.claude/skills/<n>` → `.github/skills/<n>/` double-symlink), C (none yet), D 
(single directory symlink where one of `.claude/skills` / `.github/skills` is 
itself a symlink to the other; two orientations). |
+| [`agents.md`](agents.md) | The agent-target registry — *which* directories 
framework-skill symlinks land in across vendors. Defines the universal 
`.agents/skills/` path (shared by Codex, Cursor, Gemini CLI, Copilot, OpenCode, 
…), the `claude-code` + `github` pair, holdout natives (Windsurf, Goose), 
active-target selection, SKILL.md format portability, and the Claude-Code-only 
layer (sandbox/hooks). The source of truth every sub-action consults for the 
target set. |
+| [`conventions.md`](conventions.md) | Adopter skills-dir convention 
auto-detection for the **`.claude/` ↔ `.github/` pair** — four patterns: A 
(flat `.claude/skills/<n>/`), B (per-skill `.claude/skills/<n>` → 
`.github/skills/<n>/` double-symlink), C (none yet), D (single directory 
symlink where one of `.claude/skills` / `.github/skills` is itself a symlink to 
the other; two orientations). Describes the *layout of that one coupled pair*; 
[`agents.md`](agents.md) is the wider which-target [...]
 | [`overrides.md`](overrides.md) | Agentic-override file management — open / 
scaffold an override for a framework skill, list existing overrides, help 
reconcile when the framework changes the underlying skill's structure on 
upgrade. |
 | [`unadopt.md`](unadopt.md) | Reverse the adoption — remove snapshot, locks, 
symlinks, post-checkout hook, `.gitignore` entries, the adoption sections in 
`README.md` / `AGENTS.md` / `CONTRIBUTING.md`, and the committed `setup` skill 
itself. Preserves `.apache-magpie-overrides/` by default; `--purge-overrides` 
removes it too. Surfaces the full removal plan before any write. |
 
@@ -358,6 +361,7 @@ first, then continue.
 |---|---|
 | `from:<git-ref>` / `from:<version>` | Adopt or upgrade from a specific 
framework ref or version. Used during `adopt` (overrides the user prompt) and 
`upgrade` (overrides the committed lock for *this run only* — does NOT update 
the committed lock). |
 | `method:<git-branch\|git-tag\|svn-zip\|local>` | Pick the install method 
explicitly. Default during `adopt`: prompt the user. **`local`** is 
**framework-checkout only** — it self-adopts by linking the in-repo `skills/` 
source directly instead of fetching a snapshot (see [`adopt.md` → Local 
self-adoption](adopt.md#local-self-adoption-methodlocal)). |
+| `agents:<list>` | Comma-separated **agent targets** to wire symlinks into 
([`agents.md`](agents.md) registry ids: `universal`, `claude-code`, `github`, 
`windsurf`, `goose`, …). Default on `adopt`/`upgrade`: auto — the always-on 
neutral set (`universal` + `claude-code` + `github`) plus any other registry 
dir already present in the repo. When passed, **replaces** the auto-detected 
set for that run, except `universal` (`.agents/skills/`) which is always 
retained because dropping it defeat [...]
 | `skill-families:<list>` | Comma-separated **opt-in** families to symlink 
(`security`, `pr-management`, `issue`). Default on `adopt`: prompt. Default on 
`upgrade`: read the families list from `<committed-lock>` / `<local-lock>`, 
**auto-include any opt-in family the framework has introduced since the lock 
was written** (recorded back into the lock), and **ensure every framework skill 
in the effective family set has a valid symlink** — create or repair missing / 
broken symlinks, not just  [...]
 | `--purge-overrides` | *(unadopt only)* Also `git rm -r` 
`.apache-magpie-overrides/`. Default: preserve. |
 | `dry-run` | Show what the skill would do without writing anything. |
diff --git a/skills/setup/adopt.md b/skills/setup/adopt.md
index f515201..5caaeba 100644
--- a/skills/setup/adopt.md
+++ b/skills/setup/adopt.md
@@ -149,12 +149,14 @@ How it differs from a remote adoption:
 - **Symlinks are committed, not gitignored.** Each
   `magpie-<skill>` symlink targets `../../skills/<skill>/` — an
   in-repo path that always resolves on a fresh clone — so the
-  links are committed. They are written under **both**
-  `.claude/skills/` (Claude Code) and `.github/skills/` (GitHub's
-  skill loader), so the framework's own skills are discoverable
-  by either harness; `.gitignore` un-ignores `magpie-*` in both
-  dirs. Every contributor gets the skills active with no setup
-  step.
+  links are committed. They are written under **every active
+  target dir** ([`agents.md`](agents.md)) — `.agents/skills/`
+  (the universal path shared by Codex, Cursor, Gemini CLI,
+  Copilot, …), `.claude/skills/` (Claude Code), and
+  `.github/skills/` (GitHub's skill loader) — so the framework's
+  own skills are discoverable by any harness; `.gitignore`
+  un-ignores `magpie-*` in each. Every contributor gets the
+  skills active with no setup step, whatever agent they use.
 - **All skills, no family prompt.** Self-adoption links *every*
   skill under `skills/`, so the opt-in family prompt of
   [Step 5](#step-5--pick-the-skill-families) is skipped.
@@ -192,25 +194,37 @@ How it differs from a remote adoption:
    ```
 
 5. **`.gitignore`.** Ensure each skills dir glob is ignored with
-   the `magpie-*` set un-ignored, in **both** locations
-   (idempotent — add any missing line):
+   the `magpie-*` set un-ignored, in **every active target
+   location** ([`agents.md`](agents.md) — the always-on neutral
+   targets `.agents/skills/`, `.claude/skills/`, `.github/skills/`
+   plus any other registry dir already present). Idempotent — add
+   any missing line. For the default set:
 
    ```text
+   .agents/skills/*
+   !/.agents/skills/magpie-*
    .claude/skills/*
    !/.claude/skills/magpie-*
    .github/skills/*
    !/.github/skills/magpie-*
    ```
 
+   (Self-adoption symlinks are *committed*, not gitignored — see
+   the next step — so the `!…/magpie-*` negation here un-ignores
+   the whole set, not just `magpie-setup`.)
+
 6. **Create the symlinks.** For each enumerated skill `<n>`,
    create the relative symlink `magpie-<n>` → `../../skills/<n>`
-   under **both** `<repo-root>/.claude/skills/` and
-   `<repo-root>/.github/skills/`. Idempotent: re-point a
-   pre-existing `magpie-<n>` symlink only if it targets something
-   else; never overwrite a non-symlink (surface the conflict and
-   stop). Show the full list and confirm before writing.
+   under **every active target dir** from
+   [`agents.md`](agents.md) (`.agents/skills/`, `.claude/skills/`,
+   `.github/skills/`, plus any present holdout). Idempotent:
+   re-point a pre-existing `magpie-<n>` symlink only if it targets
+   something else; never overwrite a non-symlink (surface the
+   conflict and stop). Show the full list and confirm before
+   writing.
 7. **Verify + stage.** Confirm every `magpie-<n>` symlink (in
-   both dirs) resolves to a directory containing `SKILL.md`, then
+   every target dir) resolves to a directory containing
+   `SKILL.md`, then
    suggest the user `git add` the symlinks, `.apache-magpie.lock`,
    and `.gitignore`.
 
@@ -508,13 +522,26 @@ idempotent — re-add them if they're missing.
 /.claude/settings.local.json
 ```
 
-**Symlink-pattern entries — vary by adopter
-[skills-dir convention](conventions.md)**:
+**Symlink-pattern entries — one block per active target
+([`agents.md`](agents.md)).** Every framework skill is symlinked
+under the `magpie-` prefix (see
+[`SKILL.md` Golden rule 6](SKILL.md#golden-rules)), so a single
+`magpie-*` glob covers them all in each target dir — no per-family
+lines.
+
+**Universal target — always emitted** (the `.agents/skills/`
+path shared by Codex, Cursor, Gemini CLI, Copilot, OpenCode, …):
+
+  ```text
+  /.agents/skills/magpie-*
+  !/.agents/skills/magpie-setup
+  ```
+
+**Any present holdout** (`.windsurf/skills/`, `.goose/skills/`,
+…) gets the same flat two-line block keyed on its own dir.
 
-  Every framework skill is symlinked under the `magpie-`
-  prefix (see [`SKILL.md` Golden rule 6](SKILL.md#golden-rules)),
-  so a single `magpie-*` glob covers them all — no per-family
-  lines.
+**Claude Code + GitHub pair — varies by adopter
+[skills-dir convention](conventions.md):**
 
 - **Pattern A (flat)** — only the `.claude/skills/...` lines:
 
@@ -601,12 +628,25 @@ adoption path where the committed lock only records the
 opt-in pick. Compute the family glob fresh from the snapshot
 contents on disk — do not hard-code skill names.
 
-Per-pattern symlink wiring (see
+Per-target symlink wiring (targets from
+[`agents.md`](agents.md); the Claude+GitHub layout from
 [`conventions.md`](conventions.md)):
 
 Every symlink is named `magpie-<n>` (the `magpie-` prefix
 namespaces framework skills); its target keeps the snapshot's
-clean source name `skills/<n>/`.
+clean source name `skills/<n>/`. Wire the **same set of skills**
+into **every active target dir**.
+
+- **Universal target (`.agents/skills/`)** — one flat symlink
+  per skill at `.agents/skills/magpie-<n>` → snapshot. Gitignored.
+  This single placement is what makes the framework discoverable
+  to Codex, Cursor, Gemini CLI, Copilot, OpenCode, and the rest
+  of the shared-path cluster. Any present holdout
+  (`.windsurf/skills/`, `.goose/skills/`, …) is wired the same
+  flat way.
+
+- **Claude Code + GitHub pair** — wired per the detected
+  convention pattern below:
 
 - **Pattern A (flat)** — one symlink per skill at
   `.claude/skills/magpie-<n>` → snapshot. Gitignored.
diff --git a/skills/setup/agents.md b/skills/setup/agents.md
new file mode 100644
index 0000000..b2a6358
--- /dev/null
+++ b/skills/setup/agents.md
@@ -0,0 +1,179 @@
+<!-- SPDX-License-Identifier: Apache-2.0
+     https://www.apache.org/legal/release-policy.html -->
+
+# agents — the agent-target registry (where framework-skill symlinks land)
+
+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"*.
+
+## The registry
+
+| Target id | Project skills dir | Kind | Reads it |
+|---|---|---|---|
+| `universal` | `.agents/skills/` | universal | 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 | Claude Code (layout variants 
A/B/C/D — see [`conventions.md`](conventions.md)) |
+| `github` | `.github/skills/` | native | GitHub's skill loader (paired with 
`claude-code` under conventions Pattern B / D) |
+| `windsurf` | `.windsurf/skills/` | native | Windsurf |
+| `goose` | `.goose/skills/` | native | Goose |
+
+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.
+
+## The universal directory — `.agents/skills/`
+
+The load-bearing move for neutrality is that a large cluster of
+agents (Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode,
+Cline, Zed, Warp, …) all read **`.agents/skills/`** as their
+project-scope skills path. Wiring `magpie-<skill>` once into
+`.agents/skills/` covers that whole cluster in a **single
+placement**:
+
+```text
+.agents/skills/magpie-pr-management-triage   →  one symlink
+   ├─ Codex      picks it up
+   ├─ Cursor     picks it up
+   ├─ Gemini CLI picks it up
+   └─ Copilot …  picks it up
+```
+
+Only agents with a **bespoke** folder (`claude-code` →
+`.claude/skills/`, `github` → `.github/skills/`, `windsurf`,
+`goose`, …) need their own symlink in addition. This pushes the
+adopter repo toward de facto convergence on one neutral location
+while still bridging the holdouts.
+
+(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`.)
+
+## Active-target selection — which dirs `adopt` wires
+
+On every `adopt` / `upgrade` / `worktree-init`, the **active
+target set** is computed as the union of:
+
+1. **The always-on neutral targets** — `universal`
+   (`.agents/skills/`) **plus** the `claude-code` + `github`
+   pair, wired per the adopter's detected
+   [skills-dir convention](conventions.md) (A/B/C/D). These three
+   are wired unconditionally; they are cheap relative symlinks
+   into the gitignored snapshot, harmless to an agent that never
+   reads them, and dropping them is not a supported configuration.
+2. **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.
+3. **Explicit opt-in** via the `agents:<list>` flag (see
+   [`SKILL.md` Inputs](SKILL.md#inputs)) — a comma-separated list
+   of registry ids. When passed it **replaces** the auto-detected
+   set (1)+(2) for that run; `universal` is always retained even
+   if omitted, because dropping it defeats neutrality.
+
+The flow **never** removes or rewrites an adopter's own
+non-`magpie-` skill content in any target dir. It only adds /
+repairs `magpie-*` symlinks.
+
+## How the framework's rules generalise across targets
+
+Every existing adoption rule is "per active target", not
+"for `.claude` and `.github`":
+
+- **`magpie-` prefix** ([`SKILL.md` Golden rule 6](SKILL.md#golden-rules))
+  — unchanged. Every framework skill is `magpie-<skill>` in
+  *every* active target dir, so it never collides with an
+  adopter's own skills regardless of agent.
+- **`.gitignore`** — one block per active target dir:
+  `/<dir>/magpie-*` plus `!/<dir>/magpie-setup`. The negation
+  keeps the one committed bootstrap (`magpie-setup`) tracked; the
+  glob ignores the rest (their targets are the gitignored
+  snapshot, so they would dangle on a fresh clone). See
+  [`adopt.md` Step 7](adopt.md#step-7--gitignore-entries-fresh-only).
+- **Symlink wiring** — flat (one `magpie-<n>` → snapshot per
+  skill), exactly like conventions Pattern A, for `universal`,
+  `windsurf`, `goose`, and any other native dir. The
+  `claude-code` + `github` pair is the **one** special case: its
+  inter-directory relationship (double-symlink B, single-dir
+  symlink D, flat A) is described in [`conventions.md`](conventions.md)
+  and detected per repo. See
+  [`adopt.md` Step 8](adopt.md#step-8--wire-up-the-framework-skill-symlinks).
+- **Local self-adoption** (framework checkout) — committed
+  symlinks into `../../skills/<skill>/` in *every* active target
+  dir, not just two. See
+  [`adopt.md` → Local self-adoption](adopt.md#local-self-adoption-methodlocal).
+- **`unadopt` / `worktree-init`** — every active target dir is
+  torn down / propagated uniformly. Removing only `.claude` +
+  `.github` would orphan the `.agents/skills/magpie-*` links.
+
+## SKILL.md format portability
+
+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;
+every target dir is a symlink into it.
+
+## The Claude-Code-only layer (not wired for other targets)
+
+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.allowedDomains`
+  allowlist, `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. `adopt`
+> itself only places files — it does not grant that approval.
+
+## Relationship to `conventions.md`
+
+[`conventions.md`](conventions.md) describes the **`.claude/` ↔
+`.github/` layout** (patterns A/B/C/D) — i.e. the internal shape
+of the `claude-code` + `github` rows of this registry, which are
+coupled because some adopters mirror one into the other. This file
+is the **wider** picture: the full set of agent targets, of which
+that pair is one coupled entry and `universal` (`.agents/skills/`)
+is another. When `adopt` wires symlinks it consults **both**: this
+file for *which targets*, `conventions.md` for *how the
+`.claude/`/`.github/` pair is laid out* in this particular repo.
diff --git a/skills/setup/conventions.md b/skills/setup/conventions.md
index 896e397..7173dd4 100644
--- a/skills/setup/conventions.md
+++ b/skills/setup/conventions.md
@@ -3,6 +3,16 @@
 
 # conventions — auto-detect the adopter's skills-dir layout
 
+> **Scope.** This file covers the **`.claude/` ↔ `.github/` pair**
+> — the one coupled entry of the agent-target registry in
+> [`agents.md`](agents.md), where some adopters mirror one
+> directory into the other. The *wider* question of **which**
+> agent targets `adopt` wires (the universal `.agents/skills/`
+> path, plus holdout natives like Windsurf / Goose) lives in
+> [`agents.md`](agents.md). The universal and holdout targets are
+> always wired **flat** (like Pattern A below); only this
+> `.claude/`/`.github/` pair has the A/B/C/D layout variants.
+
 Different ASF projects already organise their `.claude/skills/`
 differently. Before `setup adopt` creates symlinks
 into the snapshot, it detects which pattern is in place and
diff --git a/skills/setup/unadopt.md b/skills/setup/unadopt.md
index ba9ef92..fd2b454 100644
--- a/skills/setup/unadopt.md
+++ b/skills/setup/unadopt.md
@@ -6,10 +6,19 @@
 The reverse of [`adopt.md`](adopt.md). Removes the framework
 artefacts the adopt flow installed — gitignored snapshot,
 committed lock, gitignored local lock, framework-skill
-symlinks, `.gitignore` entries, post-checkout hook, the
-adoption sections in `README.md` / `AGENTS.md` /
-`CONTRIBUTING.md`, and the committed `setup` skill
-itself.
+symlinks **in every active target dir** ([`agents.md`](agents.md)
+— `.agents/skills/`, `.claude/skills/`, `.github/skills/`, plus
+any present holdout), the matching `.gitignore` blocks,
+post-checkout hook, the adoption sections in `README.md` /
+`AGENTS.md` / `CONTRIBUTING.md`, and the committed `setup`
+skill itself.
+
+> **Critical — tear down *all* target dirs.** Removing only the
+> `.claude/skills/` + `.github/skills/` pair would **orphan** the
+> `.agents/skills/magpie-*` links (and any holdout's) — dangling
+> symlinks into a snapshot that no longer exists, plus stale
+> `.gitignore` blocks. The removal must cover every active target
+> dir per [`agents.md`](agents.md).
 
 By default the adopter-authored `.apache-magpie-overrides/`
 directory is **preserved** — it contains hand-written
@@ -88,7 +97,7 @@ every artefact).
 | Local lock | `<local-lock>` | exists |
 | Committed lock | `<committed-lock>` | exists |
 | `.gitignore` entries | `<repo-root>/.gitignore` | which of the entries from 
[`adopt.md` Step 7](adopt.md) are present |
-| Framework-skill symlinks | `<adopter-skills-dir>/` — both layers under 
Pattern B; canonical side only under Pattern D (D.1: `.github/skills/`; D.2: 
`.claude/skills/`); single layer under Pattern A | each symlink whose target 
resolves into `<snapshot-dir>/skills/` |
+| Framework-skill symlinks | **Every active target dir** 
([`agents.md`](agents.md)): `.agents/skills/` (universal — always present), any 
present holdout (`.windsurf/skills/`, `.goose/skills/`), plus the 
`.claude/`/`.github/` pair — both layers under Pattern B; canonical side only 
under Pattern D (D.1: `.github/skills/`; D.2: `.claude/skills/`); single layer 
under Pattern A | each `magpie-*` symlink whose target resolves into 
`<snapshot-dir>/skills/`, in **each** target dir |
 | Post-checkout hook | `<repo-root>/.git/hooks/post-checkout` | exists + 
invokes `~/.claude/scripts/sandbox-add-project-root.sh` |
 | Doc section: `README.md` | `<repo-root>/README.md` | contains the `## 
Agent-assisted contribution (apache-steward)` heading |
 | Doc section: `AGENTS.md` | `<repo-root>/AGENTS.md` | contains the `## 
apache-steward framework` heading |
@@ -115,10 +124,15 @@ The following will be REMOVED:
   Gitignored (no commit needed):
     .apache-magpie/                      (snapshot, ~N MB)
     .apache-magpie.local.lock
-    <adopter-skills-dir>/<symlink-1>     → .apache-magpie/skills/<skill-1>/
-    <adopter-skills-dir>/<symlink-2>     → ...
-    .github/skills/<symlink-1>           (Pattern B only — second physical 
layer)
+    .agents/skills/magpie-<skill-1>      → .apache-magpie/skills/<skill-1>/   
(universal target)
+    .agents/skills/magpie-<skill-2>      → ...
+    <holdout>/skills/magpie-<skill-1>    → ...   (e.g. .windsurf/skills/, 
.goose/skills/ — only if present)
+    <adopter-skills-dir>/magpie-<skill-1> → .apache-magpie/skills/<skill-1>/   
(claude-code/github pair)
+    <adopter-skills-dir>/magpie-<skill-2> → ...
+    .github/skills/magpie-<skill-1>      (Pattern B only — second physical 
layer of the pair)
     .git/hooks/post-checkout              (if it contains the steward recipe)
+    # Target dirs (per agents.md): always .agents/skills/ (universal),
+    #   any present holdout, plus the claude-code/github pair below.
     # Pattern A:  <adopter-skills-dir> = .claude/skills/
     # Pattern B:  <adopter-skills-dir> spans .claude/skills/ AND 
.github/skills/
     # Pattern D:  <adopter-skills-dir> = canonical side only
@@ -163,8 +177,9 @@ uncommitted edits, prepend a **warning** above the table:
   Commit, stash, or copy them out before continuing.
 ```
 
-If any framework-skill symlink under `<adopter-skills-dir>/`
-resolves to a path **outside** `<snapshot-dir>/` — i.e. an
+If any `magpie-*` symlink in **any active target dir**
+(`.agents/skills/`, a holdout, or the `.claude/`/`.github/`
+pair) resolves to a path **outside** `<snapshot-dir>/` — i.e. an
 adopter committed a real skill at the same name post-
 adoption, or a symlink points elsewhere — list it under a
 separate **Preserved (not framework-owned)** subsection. The
@@ -191,9 +206,17 @@ artefacts that *depend* on others come out first, so a
 half-completed unadopt never leaves a dangling symlink
 pointing at a deleted snapshot.
 
-1. **Framework-skill symlinks.** For each entry in the
-   inventory, `rm` the symlink. Per-pattern:
-
+1. **Framework-skill symlinks — in every active target dir.**
+   For each entry in the inventory, `rm` the `magpie-*` symlink.
+   Cover **every active target dir** ([`agents.md`](agents.md)),
+   not just the `.claude/`/`.github/` pair — skipping
+   `.agents/skills/` or a holdout would orphan its `magpie-*`
+   links once the snapshot is removed in step 3.
+
+   - **Universal target (`.agents/skills/`)** — one flat layer;
+     remove each `.agents/skills/magpie-<n>`. Any present holdout
+     (`.windsurf/skills/`, `.goose/skills/`, …) is torn down the
+     same flat way.
    - **Pattern A** — one layer; just remove
      `.claude/skills/magpie-<n>`.
    - **Pattern B** — two layers; remove both
@@ -203,7 +226,10 @@ pointing at a deleted snapshot.
      The directory symlink itself (`.claude/skills` or
      `.github/skills`) is **adopter-owned** and **not
      removed by unadopt** — it predates framework adoption
-     and serves the adopter's own native skills too.
+     and serves the adopter's own native skills too. The same
+     adopter-owned rule applies to the target dirs themselves
+     (`.agents/skills/`, a holdout): only the `magpie-*` entries
+     come out, never the directory.
 
    Never touch a non-symlink at the same path.
 2. **Post-checkout hook.** Remove only if its content matches
@@ -257,9 +283,10 @@ After the deletions, verify the post-state:
 
 - `<snapshot-dir>/` does not exist.
 - `<committed-lock>` and `<local-lock>` do not exist.
-- No symlinks under `<adopter-skills-dir>/` resolve into
-  `<snapshot-dir>/` (the path is gone, so dangling symlinks
-  would surface here).
+- No `magpie-*` symlinks in **any active target dir**
+  (`.agents/skills/`, any holdout, or the `.claude/`/`.github/`
+  pair) resolve into `<snapshot-dir>/` (the path is gone, so
+  any orphaned dangling symlink would surface here).
 - `.gitignore` no longer contains the steward entries.
 - The doc sections are gone from the affected files.
 - `<adopter-skills-dir>/magpie-setup/` does not exist.
@@ -277,7 +304,7 @@ A summary of what was removed + what remains:
 ```text
 ✓ Snapshot removed:        .apache-magpie/
 ✓ Locks removed:           .apache-magpie.lock, .apache-magpie.local.lock
-✓ Symlinks removed:        <count> (per-pattern — A: under .claude/skills/; B: 
under both .claude/skills/ AND .github/skills/; D: under the canonical side 
only)
+✓ Symlinks removed:        <count> across every active target dir — 
.agents/skills/ (universal) + any present holdout + the claude-code/github pair 
(A: under .claude/skills/; B: under both .claude/skills/ AND .github/skills/; 
D: under the canonical side only)
 ✓ Post-checkout hook:      removed (or: preserved — contained extra adopter 
logic)
 ✓ Doc sections removed:    README.md[, AGENTS.md][, CONTRIBUTING.md]
 ✓ .gitignore cleaned:      <N> entries removed
diff --git a/skills/setup/upgrade.md b/skills/setup/upgrade.md
index 517e6be..d95b3e3 100644
--- a/skills/setup/upgrade.md
+++ b/skills/setup/upgrade.md
@@ -111,7 +111,7 @@ For each kind of drift, present:
   `git-branch` and `git-tag` methods, list the commit log
   (`git log --oneline <local-commit>..<committed-commit>`)
   via the GitHub API or by re-cloning to a temp dir.
-- **Files touched in the framework's `.claude/skills/`** —
+- **Files touched in the framework's skill set** —
   grouped by skill family. Call out any change to a skill
   the adopter has an override for (the override will need
   reconciliation in Step 5).
@@ -258,6 +258,23 @@ pattern-matching.
 
 ## Step 6 — Refresh framework-skill symlinks
 
+This step refreshes symlinks for **every active target dir**
+([`agents.md`](agents.md)), not just the `.claude/`/`.github/`
+pair. Compute the **active target set** the same way `adopt`
+does: the always-on neutral targets `.agents/skills/`
+(`universal` — the path shared by Codex, Cursor, Gemini CLI,
+Copilot, OpenCode, …), `.claude/skills/` (`claude-code`), and
+`.github/skills/` (`github`), **plus any registry holdout
+already present in the repo** (`.windsurf/skills/`,
+`.goose/skills/`, …). When the framework has added a new
+always-on target since the last run, it joins the active set and
+gets its symlinks created on this upgrade — the same way the
+effective family set below picks up newly-introduced families.
+The `.agents/skills/` target and every holdout are wired **flat**
+(one `magpie-<n>` → snapshot per skill, like conventions
+Pattern A); only the `.claude/`/`.github/` pair follows the
+A/B/C/D layout from [`conventions.md`](conventions.md).
+
 Read the opt-in skill families from `<committed-lock>`
 (falling back to `<local-lock>` if the committed lock is
 silent on families). Compose the **effective family set**
@@ -293,40 +310,58 @@ a new `setup-*` or `list-*` skill in a release, and
 contracts on a rename / removal without code changes here.
 
 Before creating symlinks for a newly-introduced opt-in
-family, reconcile the adopter's `.gitignore` so the new
-family's snapshot symlinks are gitignored. Append the
-`.gitignore` lines from
+family — or for a newly-present active target dir — reconcile
+the adopter's `.gitignore` so the new snapshot symlinks are
+gitignored. Append the `.gitignore` lines from
 [`adopt.md` Step 7](adopt.md#step-7--gitignore-entries-fresh-only)
-for the new family's prefix, matching the adopter's
-[skills-dir convention](conventions.md):
-
-- Pattern A — `/.claude/skills/<prefix>-*` only.
-- Pattern B — both `/.claude/skills/<prefix>-*` and
-  `/.github/skills/<prefix>-*` (two physical symlinks per
-  skill).
-- Pattern D — only the *canonical-side* `<canonical>/<prefix>-*`
-  ignore line. D.1 → `/.github/skills/<prefix>-*`; D.2 →
-  `/.claude/skills/<prefix>-*`. The symlinked side's
-  directory symlink does not need its own ignore line — git
-  does not descend into it.
+for **each active target dir** ([`agents.md`](agents.md)). Every
+framework skill is symlinked under the `magpie-` prefix, so a
+single `magpie-*` glob (plus the `!…/magpie-setup` negation that
+keeps the committed bootstrap tracked) covers them all per
+target — no per-family lines:
+
+- **Universal target (`.agents/skills/`)** — always present:
+
+  ```text
+  /.agents/skills/magpie-*
+  !/.agents/skills/magpie-setup
+  ```
+
+- **Any present holdout** (`.windsurf/skills/`,
+  `.goose/skills/`, …) — the same flat two-line block keyed on
+  its own dir.
+
+- **Claude Code + GitHub pair**, per the adopter's
+  [skills-dir convention](conventions.md):
+  - Pattern A — `/.claude/skills/magpie-*` (plus
+    `!/.claude/skills/magpie-setup`) only.
+  - Pattern B — both `/.claude/skills/magpie-*` and
+    `/.github/skills/magpie-*` (two physical symlinks per
+    skill), each with its `!…/magpie-setup` negation.
+  - Pattern D — only the *canonical-side* `<canonical>/magpie-*`
+    ignore line. D.1 → `/.github/skills/magpie-*`; D.2 →
+    `/.claude/skills/magpie-*`. The symlinked side's
+    directory symlink does not need its own ignore line — git
+    does not descend into it.
 
 The append is idempotent — skip lines that already exist.
 The same idempotence covers adopters whose `.gitignore`
 already had the entries (e.g. from a manually-edited block
 or a previous adopt run).
 
-The post-upgrade state must be: *every framework skill in
-the new snapshot that belongs to the effective family set
-has a valid symlink in `<adopter-skills-dir>`*, and *no
-symlink points at a framework skill that no longer exists
-in the snapshot*.
+The post-upgrade state must be: *in every active target dir,
+every framework skill in the new snapshot that belongs to the
+effective family set has a valid symlink*, and *no symlink (in
+any target dir) points at a framework skill that no longer
+exists in the snapshot*.
 
-Run two passes:
+Run two passes **per active target dir** ([`agents.md`](agents.md)):
 
 1. **Ensure every family-member skill is linked.** For each
    framework skill in the new snapshot that belongs to the
-   effective family set, check
-   `<adopter-skills-dir>/magpie-<skill>`:
+   effective family set, check `<target>/magpie-<skill>` in each
+   active target dir (`.agents/skills/`, `.claude/skills/`,
+   `.github/skills/`, plus any present holdout):
    - If the symlink exists and points at the matching
      snapshot path, leave it alone.
    - If it's missing, create it.
@@ -335,34 +370,41 @@ Run two passes:
 
    Do this unconditionally — do not skip skills whose
    symlinks "should" already be there. A contributor who
-   ran `git clean -fdx`, blew away `<adopter-skills-dir>` by
+   ran `git clean -fdx`, blew away a target dir by
    accident, or merged a branch that removed the symlinks
-   gets the full set restored without per-symlink re-
-   prompting. The aggregated list of created / repaired
-   links is reported in the upgrade summary (Step 8 output
-   block, under the `+` and `↻` rows).
-
-2. **Reconcile stale symlinks.** Walk
-   `<adopter-skills-dir>` looking for symlinks that point
-   at framework skills no longer in the new snapshot
-   (rename, removal). For each:
+   gets the full set restored in **every** target without
+   per-symlink re-prompting. The aggregated list of created /
+   repaired links is reported in the upgrade summary (Step 8
+   output block, under the `+` and `↻` rows). A newly-present
+   target dir (a holdout that just appeared, or a new always-on
+   target the framework added) gets its full set created here.
+
+2. **Reconcile stale symlinks.** Walk **each active target
+   dir** looking for symlinks that point at framework skills no
+   longer in the new snapshot (rename, removal). For each:
    - If renamed (the framework documented a rename in its
      release notes), offer to re-symlink to the new name.
    - If removed, offer to remove the stale symlink.
 
-Per-pattern symlink layers to refresh:
-
-- **Pattern A (flat)** — refresh the single layer at
-  `.claude/skills/magpie-<n>`.
-- **Pattern B (double-symlinked)** — refresh both layers
-  (inner at `.github/skills/magpie-<n>`, outer at
-  `.claude/skills/magpie-<n>` → inner).
-- **Pattern D (single directory symlink)** — refresh only
-  the *canonical-side* layer at
-  `<canonical-side>/magpie-<n>` (D.1 → `.github/skills/magpie-<n>`;
-  D.2 → `.claude/skills/magpie-<n>`). The symlinked-side path
-  resolves through the directory symlink and needs no
-  per-skill plumbing.
+Per-target symlink layers to refresh:
+
+- **Universal target (`.agents/skills/`)** — refresh the single
+  flat layer at `.agents/skills/magpie-<n>`. Any present holdout
+  (`.windsurf/skills/`, `.goose/skills/`, …) is refreshed the
+  same flat way.
+- **Claude Code + GitHub pair**, per the detected
+  [convention](conventions.md):
+  - **Pattern A (flat)** — refresh the single layer at
+    `.claude/skills/magpie-<n>`.
+  - **Pattern B (double-symlinked)** — refresh both layers
+    (inner at `.github/skills/magpie-<n>`, outer at
+    `.claude/skills/magpie-<n>` → inner).
+  - **Pattern D (single directory symlink)** — refresh only
+    the *canonical-side* layer at
+    `<canonical-side>/magpie-<n>` (D.1 → `.github/skills/magpie-<n>`;
+    D.2 → `.claude/skills/magpie-<n>`). The symlinked-side path
+    resolves through the directory symlink and needs no
+    per-skill plumbing.
 
 ## Step 6b — Sync locally-installed hooks and configuration
 
@@ -641,9 +683,10 @@ Symlinks (main checkout):
   - <list of removed stale symlinks>
 
 .gitignore reconcile:
-  ✓ all opt-in family prefixes already gitignored   OR
-  + <list of /.claude/skills/<prefix>-* and /.github/skills/<prefix>-*
-     lines appended for newly-introduced opt-in families>
+  ✓ all active-target magpie-* globs already gitignored   OR
+  + <list of /.agents/skills/magpie-*, /.claude/skills/magpie-*,
+     /.github/skills/magpie-* (+ any holdout) lines appended for
+     newly-introduced families or newly-present target dirs>
 
 Hooks + local config:
   ✓ <list of files in sync>
diff --git a/skills/setup/verify.md b/skills/setup/verify.md
index 35764da..60192a2 100644
--- a/skills/setup/verify.md
+++ b/skills/setup/verify.md
@@ -12,8 +12,11 @@ default — surfaces gaps and remediation commands.
 ## Inputs
 
 - `--auto-fix-symlinks` — *exception to read-only*. If the
-  snapshot is present but symlinks are missing or dangling,
-  recreate them. Used by the post-checkout hook
+  snapshot is present but symlinks are missing or dangling
+  in **any active target dir** ([`agents.md`](agents.md) —
+  `.agents/skills/`, `.claude/skills/`, `.github/skills/`, plus
+  any present holdout), recreate them across all of them. Used
+  by the post-checkout hook
   ([`adopt.md` Step 10](adopt.md)) on a fresh worktree
   where the gitignored symlinks didn't follow the
   checkout.
@@ -46,21 +49,24 @@ adoption state.
 1. **Marker lock.** `.apache-magpie.lock` parses and records
    `method: local`. ✓ when present; ✗ with a pointer at
    `/magpie-setup` otherwise.
-2. **Symlinks resolve into `skills/`.** In **both**
-   `.claude/skills/` and `.github/skills/`, every `magpie-<n>` is
-   a symlink whose target (`../../skills/<n>/`) resolves to a
-   directory containing `SKILL.md`. ✗ list any dangling or
-   non-symlink entry; remediation: re-run `/magpie-setup`
+2. **Symlinks resolve into `skills/`.** In **every active target
+   dir** ([`agents.md`](agents.md) — `.agents/skills/`,
+   `.claude/skills/`, `.github/skills/`, plus any present
+   holdout), every `magpie-<n>` is a symlink whose target
+   (`../../skills/<n>/`) resolves to a directory containing
+   `SKILL.md`. ✗ list any dangling or non-symlink entry, naming
+   the target dir; remediation: re-run `/magpie-setup`
    (idempotent).
 3. **Coverage.** Every `skills/<n>/` with a `SKILL.md` has a
-   matching `magpie-<n>` symlink in **both** dirs (unless a
-   `skill-families:` filter was deliberately applied). ⚠ list any
-   source skill with no link; remediation: `/magpie-setup`.
-4. **`.gitignore`.** `.claude/skills/*` and `.github/skills/*` are
-   ignored, with `!/.claude/skills/magpie-*` and
-   `!/.github/skills/magpie-*` un-ignoring the committed symlinks.
-   ✗ if either un-ignore line is missing (those symlinks would not
-   be tracked).
+   matching `magpie-<n>` symlink in **every active target dir**
+   (unless a `skill-families:` filter was deliberately applied).
+   ⚠ list any source skill with no link, per target; remediation:
+   `/magpie-setup`.
+4. **`.gitignore`.** Each active target dir's `<dir>/*` is
+   ignored, with `!/<dir>/magpie-*` un-ignoring the committed
+   symlinks — `.agents/skills/`, `.claude/skills/`,
+   `.github/skills/`, and any present holdout. ✗ if any un-ignore
+   line is missing (those symlinks would not be tracked).
 5. **No remote leftovers.** No `.apache-magpie/` snapshot dir and
    no `.apache-magpie.local.lock` — local self-adoption uses
    neither. ⚠ surface either if found (a stale remote adoption was
@@ -150,21 +156,26 @@ Check that the entries from
   must never be committed since the content is machine-specific
   absolute paths)
 
-Recommended (the family patterns the adopter's
-[skills-dir convention](conventions.md) requires):
-
-- **Pattern A** — framework-skill symlink patterns
-  (`security-*`, `pr-management-*`, `issue-*`,
-  `setup-isolated-setup-*`, `setup-shared-config-sync`,
-  `list-*`) under `.claude/skills/` only.
-- **Pattern B** — same patterns under **both**
-  `.claude/skills/` and `.github/skills/` (one ignore line
-  per physical symlink).
-- **Pattern D** — same patterns under the **canonical side
-  only** (`.github/skills/` for D.1; `.claude/skills/` for
-  D.2). The symlinked side does not need its own ignore
-  lines because git does not descend into a directory
-  symlink.
+Recommended (the `magpie-*` glob per **active target dir** —
+[`agents.md`](agents.md) — plus the `.claude/`/`.github/`
+[skills-dir convention](conventions.md)):
+
+- **Universal target (`.agents/skills/`)** — always present:
+  `/.agents/skills/magpie-*` with `!/.agents/skills/magpie-setup`.
+- **Any present holdout** (`.windsurf/skills/`,
+  `.goose/skills/`, …) — the same flat two-line block keyed on
+  its own dir.
+- **Claude Code + GitHub pair**, per convention:
+  - **Pattern A** — `/.claude/skills/magpie-*` (with
+    `!/.claude/skills/magpie-setup`) only.
+  - **Pattern B** — the same glob under **both**
+    `.claude/skills/` and `.github/skills/` (one ignore line
+    per physical symlink).
+  - **Pattern D** — the same glob under the **canonical side
+    only** (`.github/skills/` for D.1; `.claude/skills/` for
+    D.2). The symlinked side does not need its own ignore
+    lines because git does not descend into a directory
+    symlink.
 
 - ✗ if `/.apache-magpie/` is not gitignored — the snapshot
   is at risk of being accidentally committed.
@@ -180,16 +191,23 @@ Recommended (the family patterns the adopter's
 
 ### 5. Symlinks point at live framework skills
 
-For each symlink under `<adopter-skills-dir>` that resolves
+Run this check across **every active target dir**
+([`agents.md`](agents.md) — `.agents/skills/`, `.claude/skills/`,
+`.github/skills/`, plus any present holdout), not just the
+`.claude/`/`.github/` pair.
+
+For each symlink under any active target dir that resolves
 into `.apache-magpie/skills/<name>/`:
 
 - ✓ if the target exists.
-- ✗ if dangling (target deleted or snapshot missing).
-  Remediation: `/magpie-setup adopt` (idempotent re-run)
-  or this same skill with `--auto-fix-symlinks`.
+- ✗ if dangling (target deleted or snapshot missing), naming
+  the target dir. Remediation: `/magpie-setup adopt` (idempotent
+  re-run) or this same skill with `--auto-fix-symlinks`.
 
 For each framework skill in the snapshot **not** symlinked
-in the adopter, classify it:
+in a given active target dir, classify it (a skill missing
+from `.agents/skills/` is as much a gap as one missing from
+`.claude/skills/`):
 
 - **Always-on family** (every `setup-*` *except*
   `setup` itself, and every `list-*` — per
@@ -208,9 +226,9 @@ in the adopter, classify it:
   family; the warning prompts a decision.
 
 The `--auto-fix-symlinks` path repairs the first two
-classes in place without prompting; the ⚠ class needs an
-explicit `/magpie-setup adopt` re-run with the family
-added to the pick.
+classes in place — in **every active target dir** — without
+prompting; the ⚠ class needs an explicit `/magpie-setup adopt`
+re-run with the family added to the pick.
 
 ### 6. `.apache-magpie-overrides/` exists + has the README
 
diff --git a/skills/setup/worktree-init.md b/skills/setup/worktree-init.md
index a527e91..cd33c3d 100644
--- a/skills/setup/worktree-init.md
+++ b/skills/setup/worktree-init.md
@@ -70,13 +70,16 @@ Then verify the chain end-to-end:
 - `ls <worktree>/.apache-magpie/skills/` lists the
   same skills as `ls <main>/.apache-magpie/skills/`.
 
-## Step 1b — Wire up the worktree's `<adopter-skills-dir>` symlinks
+## Step 1b — Wire up the worktree's per-target symlinks
 
 The snapshot symlink in Step 1 only makes the framework's
-*source* available to this worktree. The `<adopter-skills-dir>`
-symlinks (the gitignored per-skill entries the agent harness
-actually resolves) are **per-worktree** — each working copy
-needs its own. A worktree branched from before adoption
+*source* available to this worktree. The per-skill symlinks (the
+gitignored entries the agent harness actually resolves) live in
+**every active target dir** ([`agents.md`](agents.md) —
+`.agents/skills/` (universal), `.claude/skills/`,
+`.github/skills/`, plus any present holdout) and are
+**per-worktree** — each working copy needs its own in every
+target. A worktree branched from before adoption
 landed, or branched from a state where the symlinks were
 cleaned, has none on disk.
 
@@ -91,18 +94,23 @@ Compose the **effective family set** for this worktree:
   [`SKILL.md` Golden rule 8](SKILL.md#golden-rules). These
   are added unconditionally, never read from the lock.
 
-For each framework skill in the effective family set:
+For each framework skill in the effective family set, and for
+**each active target dir**:
 
-- If `<worktree>/<adopter-skills-dir>/magpie-<skill>` is missing —
+- If `<worktree>/<target>/magpie-<skill>` is missing —
   create it (gitignored).
 - If it exists and points at the correct snapshot path —
   leave it alone.
 - If it exists but is broken or points at the wrong path —
   repair it.
 
-Reuse the convention detection from
-[`conventions.md`](conventions.md). The pattern drives how
-many layers the worktree's `<adopter-skills-dir>` needs:
+The `.agents/skills/` (universal) target and any present
+holdout (`.windsurf/skills/`, `.goose/skills/`, …) are wired
+**flat** — one `magpie-<n>` → snapshot per skill, exactly like
+conventions Pattern A. For the `.claude/`/`.github/` pair, reuse
+the convention detection from
+[`conventions.md`](conventions.md); the pattern drives how
+many layers that pair needs:
 
 - **Pattern A (flat)** — one layer at
   `.claude/skills/magpie-<n>`.
@@ -115,20 +123,25 @@ many layers the worktree's `<adopter-skills-dir>` needs:
   automatically through the directory symlink, so there is
   no per-skill plumbing to add or repair on that side.
 
-The worktree's `.claude/skills` / `.github/skills` directory
-symlink itself (for Pattern D) is **not** a framework
-artefact — it is checked into the repo as part of the
-adopter's layout, so every worktree inherits it via the
-ordinary `git worktree add` flow. `worktree-init` does not
-touch it.
-
-Pick any framework skill symlink that should now exist (e.g.
-`<worktree>/.claude/skills/magpie-security-issue-sync/SKILL.md`) and
-confirm `readlink -f` resolves it into
+The worktree's target directories themselves — `.agents/skills/`,
+any holdout, and the `.claude/skills` / `.github/skills`
+directory symlink (for Pattern D) — are **not** framework
+artefacts; they are checked into the repo as part of the
+adopter's layout, so every worktree inherits them via the
+ordinary `git worktree add` flow. `worktree-init` only wires the
+`magpie-*` entries inside them; it does not touch the
+directories.
+
+Pick a framework skill symlink that should now exist in **each**
+active target dir (e.g.
+`<worktree>/.agents/skills/magpie-security-issue-sync/SKILL.md`
+and `<worktree>/.claude/skills/magpie-security-issue-sync/SKILL.md`)
+and confirm `readlink -f` resolves each into
 `<main>/.apache-magpie/...` rather than dangling — same
 sanity check as Step 1's bottom bullet, just now end-to-end
 from agent-harness path through the worktree's symlink
-through the snapshot symlink to the framework source.
+through the snapshot symlink to the framework source, in every
+target.
 
 ## Step 1c — Add the worktree to its own project-local sandbox allowlists
 
@@ -182,9 +195,10 @@ Print a short summary:
 - The main checkout's resolved path.
 - The framework version the main is pinned at (read from
   `<main>/.apache-magpie.lock`).
-- The effective family set wired in Step 1b, split into
-  *opt-in* and *always-on*, with per-skill ✓ / + / ↻
-  counts.
+- The effective family set wired in Step 1b across every
+  active target dir (`.agents/skills/`, the `.claude/`/`.github/`
+  pair, any present holdout), split into *opt-in* and
+  *always-on*, with per-skill ✓ / + / ↻ counts.
 - A reminder: `upgrade` from the main, not from the worktree.
 
 ## Inputs
@@ -218,5 +232,5 @@ different overrides. Symlinking it would conflate branches.
 | Symptom | Likely cause | Fix |
 |---|---|---|
 | Step 0 step 3 stops with "main checkout not adopted" | The main has never 
run `adopt`. | `cd <main> && /magpie-setup`, then re-run `worktree-init` here. |
-| `worktree-init` runs but skills still fail to resolve | The 
`<adopter-skills-dir>/magpie-<skill>` symlinks are missing from this worktree's 
commit (the worktree was branched from before `adopt` ran on main). | Re-run 
`worktree-init` from main's `adopt` flow afterwards, or `git merge` / `git 
rebase` the branch carrying the symlink commits. |
+| `worktree-init` runs but skills still fail to resolve | The per-target 
`magpie-<skill>` symlinks (in `.agents/skills/`, the `.claude/`/`.github/` 
pair, or a holdout) are missing from this worktree's commit (the worktree was 
branched from before `adopt` ran on main). | Re-run `worktree-init` from main's 
`adopt` flow afterwards, or `git merge` / `git rebase` the branch carrying the 
symlink commits. |
 | `<snapshot-dir>` is a regular directory and `--force` is not passed | A 
previous worktree snapshot is still on disk. | Re-run the skill, accept the 
move-aside prompt, then optionally inspect `.apache-magpie.bak.<timestamp>` for 
any non-snapshot content before deleting. |

Reply via email to