.agents/skills/magpie-setup/worktree-init.md
adopt and upgrade are main-checkout-only. A new git
worktree of an already-adopted tracker repo gets the framework
state by symlinking its .apache-magpie/ directory to the
main checkout's snapshot, rather than maintaining its own copy.
One snapshot on disk, one upgrade source, every worktree always
current.
This sub-action is the worktree counterpart of adopt:
adopt runs in the main checkout, fetches the snapshot,
writes both lock files, and wires up symlinks.worktree-init runs in a worktree, validates the main is
adopted, and points the worktree's <snapshot-dir> at the
main's. Nothing is fetched; no lock files are written.The skill is idempotent: re-running on a worktree that already has the right symlink is a no-op.
Confirm we are in a git worktree, not the main checkout.
Compare git rev-parse --git-dir against
git rev-parse --git-common-dir. They are equal in the main
checkout and different in a worktree. If equal, stop:
"You appear to be in the main checkout (
<path>).worktree-initonly runs in a worktree. Use/magpie-setup(or/magpie-setup upgrade) here instead."
Resolve the main checkout's path. Take
$(cd "$(git rev-parse --git-common-dir)" && pwd); the
parent of that is the main checkout's working tree. Pin
the result as <main> for the rest of this flow.
Confirm the main checkout is adopted. Check that
<main>/.apache-magpie/ exists and that
<main>/.apache-magpie.lock exists. If either is missing,
stop:
"The main checkout at
<main>is not adopted yet. From the main checkout:cd <main> && /magpie-setup. Re-runworktree-inithere once that is complete."
Inspect the worktree's <snapshot-dir> state. Four
possibilities, each handled below:
| Current state | Action |
|---|---|
| Missing | Step 1 — create the symlink. |
Symlink to <main>/.apache-magpie/ | No-op. Surface "already wired" and stop. |
| Symlink to something else | Step 1 with a move-aside warning. The skill backs the existing link up, names what it pointed at, and asks the user to confirm before replacing. |
| Regular directory (per-worktree snapshot from before this convention) | Step 1 with a move-aside warning. Back up the directory to .apache-magpie.bak.<timestamp> and create the symlink. Do not rm -rf without confirmation — the directory may hold uncommitted local edits the operator wants to preserve before the framework standardised on snapshot-from-main. |
ln -s <main>/.apache-magpie <worktree>/.apache-magpie
Then verify the chain end-to-end:
ls -la <worktree>/.apache-magpie returns a symlink pointing
at <main>/.apache-magpie.ls <worktree>/.apache-magpie/skills/ lists the
same skills as ls <main>/.apache-magpie/skills/.The snapshot symlink in Step 1 only makes the framework's
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/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.
Compose the effective family set for this worktree:
<main>/.apache-magpie.lock (the committed lock; the
worktree shares it via git).setup-* skill in the
snapshot except setup itself, and every
list-* skill, per
SKILL.md Golden rule 8. These
are added unconditionally, never read from the lock.Wiring follows the canonical-plus-relay model
(agents.md), with no per-layout variation. For each
framework skill in the effective family set:
.agents/skills/) — ensure
<worktree>/.agents/skills/magpie-<skill> →
../../.apache-magpie/skills/<skill>/ (the worktree's snapshot
symlink from Step 1). Create if missing, repair if broken or
pointing at the wrong path, leave alone if correct..claude/skills/, .github/skills/, any present
holdout) — ensure <worktree>/<target>/skills/magpie-<skill>
→ ../../.agents/skills/magpie-<skill>. Create / repair / leave
alone the same way.All these entries are gitignored and per-worktree.
The worktree's target directories themselves — .agents/skills/,
.claude/skills/, .github/skills/, any holdout — 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, in every
target.
Defensive against
issue #197 —
sandbox.filesystem.allowRead: ["."] does not in practice cover
the worktree's working dir, so reads under this worktree fail
under the sandbox until an explicit absolute path is added. See
setup-isolated-setup-install/SKILL.md → Step P
for the underlying rationale.
If ~/.claude/scripts/sandbox-add-project-root.sh is installed,
invoke it from the worktree's working directory (no
--all-worktrees flag — only this one worktree needs adding;
the helper picks up the current worktree's
git rev-parse --show-toplevel and writes the abs path to
<this-worktree>/.claude/settings.local.json):
"$HOME/.claude/scripts/sandbox-add-project-root.sh"
Invoke with dangerouslyDisableSandbox: true — the target
settings.local.json is in Claude Code's built-in sandbox
denyWithinAllow set, so a sandboxed Bash write fails with
operation not permitted. Surface the bypass proposal to the
operator before invoking; name the helper and the target file
(<worktree>/.claude/settings.local.json); confirm. Reason:
"writing project-local sandbox-allowlist entry (issue #197
fix)".
The helper writes to project-local scope, not user-scope —
each worktree carries its own .claude/settings.local.json
entry, and the per-worktree file is gitignored. The helper is
idempotent (no-op when already added) and exits 0 when
prereqs are missing (no jq, not in a git repo). Surface a
one-line recap row for the Step 2 summary:
<worktree-path>, OR/magpie-setup-isolated-setup-install to wire it up.worktree-init does not fail when the helper is absent;
secure-agent isolation is independent of framework adoption.
Print a short summary:
<main>/.apache-magpie.lock)..agents/skills/, the .claude//.github/
pair, any present holdout), split into opt-in and
always-on, with per-skill ✓ / + / ↻ counts.upgrade from the main, not from the worktree.| Flag | Effect |
|---|---|
--force | Replace an existing <snapshot-dir> (symlink or regular dir) without the confirmation prompt. Skips the move-aside backup. Use only when you are sure the existing state holds nothing worth keeping. |
dry-run | Show what the skill would do without writing anything. |
This sub-action does not touch .apache-magpie-overrides/.
That directory is committed in the tracker repo and is
worktree-local by design — different branches may carry
different overrides. Symlinking it would conflate branches.
adopt in the main checkout
first.upgrade in the
main checkout; the symlink means every worktree sees the
refreshed snapshot immediately.git worktree add. Adopters who want
automatic worktree initialisation can wrap git worktree add
with a script that calls /magpie-setup worktree-init —
the framework does not install that wrapper.| 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 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. |