Worktree And Git¶
After a project directory move, sweep ~/.claude/ for broken symlinks — content greps miss them¶
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 forDownloads/Evolveand 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, sogrep -rskips 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:Repoint each withfind ~/.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 doneln -sfn <new-target> <link>. Note that during a reorg, files may have moved between projects (e.g., agents wentEvolve-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-startStep 3b auto-merges allclaude/*remote branches into main, then pushes and deletes the remote branches automatically. Never trust branch names — always check file contents withgit diff --name-onlyto 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 unrelatedclaude/*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-startdetects aclaude/*worktree branch as the current session branch, NEVER auto-merge otherclaude/*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.
Two-spec drift class — symlink as the prevention pattern¶
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-analysisskill viaReadreference) and another atinfra/vps/apps/competitive-audit/prompts/_tier-spec.md(read by the VPS pipeline viafs.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 (wouldweb_fetchfor<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-linksto 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:Without# 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/-L, rsync ships the symlink AS A SYMLINK (default-aincludes-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 theschema-audit STRONGLY RECOMMENDEDflag 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.bakfiles during major sync: Before overwriting a drifted file with the canonical, save.pre-v1.5.baksnapshots 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.mdmemory 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-cleanuphad 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, runpwdand capture the worktree root — every subsequent absolute path should start with that prefix. 2. Prefer RELATIVE paths in Write tool calls when in a worktree —clients/_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 one —git statusin 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 ininfra/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, andgit statusfrom 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 path —infra/,docs/,clients/,scripts/,apps/,.claude/, etc. — verify before writing. Not just client folders. 3. After the FIRST Write in a worktree session, rungit statusin 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):mvnew files from main → worktree;cpmodified files from main → worktree;git -C <main> restore <specific files>to revert main's modifications (do NOT userestore .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)