Skip to content

Worktree And Git

From legacy section: Competitive Audit Pipeline

Why: On 2026-05-04, after Evolve-Agency / Evolve-Publishing / Evolve-Consulting moved from ~/Downloads/ to ~/Code/, the initial audit grepped repo file contents for Downloads/Evolve and found 3 small fixes. A second sweep found 54 broken symlinks in ~/.claude/commands/ (40+) and ~/.claude/agents/ (13) — the entire user-global slash command + agent layer was dead weight outside this project. Symlink targets aren't text inside files; they're filesystem metadata, so grep -r skips them. Inside the project, slash commands still resolved (project-level .claude/commands/ takes precedence), making the breakage invisible from the moved directory. How to apply: When auditing fallout from any project directory move, run BOTH a content grep AND a symlink-target sweep:

find ~/.claude -maxdepth 4 -type l 2>/dev/null | while read l; do
  tgt=$(readlink "$l")
  if [[ "$tgt" == *"<old-path-substring>"* ]]; then
    echo "BROKEN: $l$tgt"
  fi
done
Repoint each with ln -sfn <new-target> <link>. Note that during a reorg, files may have moved between projects (e.g., agents went Evolve-Consulting/agents/Evolve-Publishing/agents/), so verify the new target exists before repointing — never assume a 1:1 substring swap. Date: 2026-05-04


Worktree Branches Must Be Auto-Merged and Cleaned Up at Session Start

From legacy section: Hostinger / Server

Pattern: Cloud/parallel sessions create claude/* remote branches containing client work. These pile up and Jim had to manually discover and merge them. Branch names are auto-generated and misleading (e.g., "show-all-commands" branch contained Sandman's Blasting content). Rule: /session-start Step 3b auto-merges all claude/* remote branches into main, then pushes and deletes the remote branches automatically. Never trust branch names — always check file contents with git diff --name-only to identify which client folder the work belongs to. This is the safety net for cloud mode: start session → pull → merge worktrees → push → clean up. Date: 2026-03-24



/session-start on a worktree branch: don't auto-merge or push to main

From legacy section: SEO NEO / Workbook

Pattern: Remote Claude Code session opened on assigned branch claude/update-readme-YK6HC. Session-start skill wanted to auto-merge unrelated claude/* worktree branches (xmvc6, zqcHB) into main and push — but session rules lock development to the assigned branch and forbid pushing elsewhere without explicit permission. Rule: When /session-start detects a claude/* worktree branch as the current session branch, NEVER auto-merge other claude/* branches into main. Report their existence + contents, flag as "needs dedicated merge session," and defer. Only the session's own assigned branch can be committed/pushed without further prompting.


From legacy section: SEO NEO / Workbook

Pattern: The competitive-audit system had two copies of the same canonical spec — one at docs/competitive-analysis-tier-spec.md (read by the /competitive-analysis skill via Read reference) and another at infra/vps/apps/competitive-audit/prompts/_tier-spec.md (read by the VPS pipeline via fs.readFile). Same content was supposed to live in both. Between 2026-04-26 and 2026-04-30, six edits landed in the VPS copy only (Full v1.3 keyword cap, FB/IG verify-pattern, heatmap+citation visuals, accessibility surfaced all-tier, schema pre-fetch, Medium v1.1 cap, plus 2026-04-30 Section 3.5 + 3.6 launch hardening). The skill — which reads canonical by reference — operated on stale rules for those 5 days. Real-world skill exposures: schema detection broken (would web_fetch for <script> blocks Anthropic strips out before Claude sees them), no Section 3.5 heatmap fabrication guard, no Section 3.6 GBP keyword-stuff detection, missing Section 8 contract fields. Parity audit on 2026-05-05 surfaced MODERATE-severity drift overall with 4 HIGH-severity skill exposures. Rule: When two consumers (or N consumers) of "the same content" exist as physical copies in the filesystem, drift is inevitable on any timescale > 1 week. Detect the pattern early: any time a spec/config/prompt/template is supposed to be "shared" but lives in two places, symlink the secondary copy to the primary. For Node.js consumers, fs.readFile() follows symlinks transparently — no code change needed. For rsync-based deploys, always use -L / --copy-links to dereference symlinks during deploy (server gets a real file with the canonical content, not a broken symlink pointing into a path that doesn't exist on the server). Implementation pattern from the canonical-sync v1.5 fix:

# In dev: symlink the duplicate to the canonical
ln -sf ../../../../../docs/competitive-analysis-tier-spec.md \
  infra/vps/apps/competitive-audit/prompts/_tier-spec.md

# In deploy: rsync with -L to dereference the symlink
rsync -avzL --exclude node_modules infra/vps/apps/competitive-audit/ \
  evolve@VPS:/opt/evolve/apps/competitive-audit/
Without -L, rsync ships the symlink AS A SYMLINK (default -a includes -l) and the server gets a broken pointer. Update both manual deploy README and any programmatic deploy scripts (e.g., bin/deploy-verify.mjs) to include -L. Why: Drift between two copies of the same content is a SILENT failure class — clients using one consumer get one report, clients using the other consumer get a different report, and the symptom (different output quality on the same business) is invisible until somebody runs a side-by-side spot-check. Symlinks make the drift impossible by construction; CI lint can later enforce that the secondary path is always a symlink (any commit that materializes the file as a real file fails). Sub-lesson — parity audit before any sync: Before merging two drifted copies, run a structured parity audit (canonical vs. each consumer, severity-tagged). The 2026-05-05 audit produced 4 HIGH-severity issues, 5 MEDIUM, and 4 LOW — not all of which propagate via canonical inheritance (some required inline updates to the skill, like the schema-audit STRONGLY RECOMMENDED flag and the FB/IG verify-pattern guardrail). Doc-vs-doc parity is necessary but not sufficient — the skill needs explicit inline guardrails for things AI inference can't reliably enforce on its own (numerical fabrication discipline, structural-tool-output false-negatives like web_fetch stripping <script>). Sub-lesson — keep .bak files during major sync: Before overwriting a drifted file with the canonical, save .pre-v1.5.bak snapshots for safety net. Reverting takes 5 seconds if the sync introduces an unexpected regression. Delete the backups after a few days of confirmed working state. Date: 2026-05-05


Worktree path writes — STILL HAPPENING, escalate prevention

From legacy section: SEO NEO / Workbook

The feedback_worktree_path_writes.md memory note (May 10, 2026) didn't prevent this exact bug recurring on 2026-05-13/18. Across 10 client audits, 2 schema deployments, and 1 email draft, every single Write tool call used the absolute main-repo path (/Users/jim/Code/Evolve-Agency/clients/_active/...) instead of the worktree path (/Users/jim/Code/Evolve-Agency/.claude/worktrees/optimistic-ramanujan-22c0e0/clients/_active/...). Result: worktree branch showed 0 commits ahead of main; ~25 directories of session work sat in main as untracked. /session-cleanup had to commit from main directly. The lesson lives in MEMORY.md but isn't load-bearing enough to interrupt the Write flow. Why: When in a git worktree, file operations to absolute paths under ~/Code/Evolve-Agency/ (without the .claude/worktrees/<branch>/ prefix) go to the MAIN worktree, not the current worktree. The worktree's branch then has zero commits ahead, while main collects untracked files. This is the second documented occurrence (May 10 with EMN mu-plugin; May 13-18 with audits/schema/email). How to apply: 1. At the start of every session in a worktree, run pwd and capture the worktree root — every subsequent absolute path should start with that prefix. 2. Prefer RELATIVE paths in Write tool calls when in a worktreeclients/_active/... from the cwd works correctly and avoids the prefix confusion. 3. If you do use absolute paths, prefix with $(git rev-parse --show-toplevel) in the path construction — guarantees the worktree path. 4. If the session has multiple Write calls to client folders, add a sanity check after the first onegit status in the worktree should show the new file as untracked; if it doesn't, the write went to main and needs to be moved. Date: 2026-05-18 (escalation; original 2026-05-10)


Worktree path writes — THIRD occurrence same day, sharper prevention rule

From legacy section: SEO NEO / Workbook

Recurred AGAIN within hours of the previous escalation entry. Same-day, second occurrence: law-firm audit tool build, worktree jolly-hypatia-d97ee6. 9 files in infra/vps/apps/competitive-audit/ (5 Edit + 4 Write) all landed in main not the worktree. The earlier "STILL HAPPENING" entry didn't fire because the prior occurrence was on client folders (clients/_active/<slug>/) and the brain didn't generalize the rule to ALL deep paths — infra/vps/..., docs/, anything. Why: Edit/Write calls naturally accept absolute paths returned by Read/grep/ls. Those tools resolve to disk paths under the main repo root because the worktree shares the same git object store. When the Write/Edit lands on the disk path, it writes to MAIN, not the worktree, and git status from the worktree shows clean. Bug discovered only at /session-cleanup. The previous "client folders" framing of the lesson was too narrow. How to apply (universalized — not just client folders): 1. First Bash of any worktree session: pwd. Note the worktree root explicitly. Every Write/Edit absolute path going forward must include .claude/worktrees/<name>/. 2. For ANY deep pathinfra/, docs/, clients/, scripts/, apps/, .claude/, etc. — verify before writing. Not just client folders. 3. After the FIRST Write in a worktree session, run git status in the worktree's cwd immediately. If the file isn't shown, you wrote to main — stop, recover the path NOW, before more files leak. 4. Recovery pattern (proven on 2026-05-18): mv new files from main → worktree; cp modified files from main → worktree; git -C <main> restore <specific files> to revert main's modifications (do NOT use restore . or unstaged-blanket commands — main has unrelated pre-existing dirt that must stay untouched); run verifiers from worktree to confirm work survived the move; commit + merge normally. 5. Structural fix candidate: add a pre-Write hook in the Claude harness that warns when an absolute path doesn't include the worktree root. Track this as an infra request — lessons-only prevention has failed three times now. Date: 2026-05-18 (third occurrence; needs a structural fix, not just another lesson)