Back to Airflow

worktree-init — share the main checkout's snapshot from a worktree

.agents/skills/magpie-setup/worktree-init.md

3.3.0b110.0 KB
Original Source
<!-- SPDX-License-Identifier: Apache-2.0 https://www.apache.org/legal/release-policy.html -->

worktree-init — share the main checkout's snapshot from a worktree

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.

Step 0 — Pre-flight

  1. 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-init only runs in a worktree. Use /magpie-setup (or /magpie-setup upgrade) here instead."

  2. 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.

  3. 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-run worktree-init here once that is complete."

  4. Inspect the worktree's <snapshot-dir> state. Four possibilities, each handled below:

    Current stateAction
    MissingStep 1 — create the symlink.
    Symlink to <main>/.apache-magpie/No-op. Surface "already wired" and stop.
    Symlink to something elseStep 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.
bash
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:

  • Opt-in families the project recorded — read from <main>/.apache-magpie.lock (the committed lock; the worktree shares it via git).
  • Always-on families — every 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:

  • Canonical (.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.
  • Relays (.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.

Step 1c — Add the worktree to its own project-local sandbox allowlists

Defensive against issue #197sandbox.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):

bash
"$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:

  • ✓ already covered, OR
    • added <worktree-path>, OR
  • ⚠ helper not installed — /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.

Step 2 — Recap

Print a short summary:

  • The snapshot symlink that was just created or confirmed.
  • 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 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

FlagEffect
--forceReplace 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-runShow what the skill would do without writing anything.

Adopter overrides

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.

What this sub-action is NOT for

  • Fetching the framework. Use adopt in the main checkout first.
  • Upgrading the framework version. Use upgrade in the main checkout; the symlink means every worktree sees the refreshed snapshot immediately.
  • Auto-running on 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.

Failure modes

SymptomLikely causeFix
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 resolveThe 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 passedA 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.