myco:feature-branch-worktree-squash-merge-delivery · v1 · 2026-06-30 · sha256 8877e9f5b0c7736b

myco:feature-branch-worktree-squash-merge-delivery v1A

Immutable. This exact content is served forever at /api/v1/blob/8877e9f5b0c7736b.

---
name: myco:feature-branch-worktree-squash-merge-delivery
description: >-
  Use this skill when delivering a non-trivial Myco feature that spans
  multiple files and needs clean PR history. It applies whenever you need
  git worktrees for isolated implementation, the `code-review high` quality
  pass (multi-agent fan-out; `/simplify` is deprecated), `make build` as
  the full quality gate, or a single clean squash-merge commit for the
  final PR.
managed_by: myco
version: 1
user-invocable: true
allowed-tools: [Bash]
---

# Feature Branch Worktree Squash-Merge Delivery

Use this skill when delivering a non-trivial Myco feature that spans multiple files and requires clean commit history in a PR. This is the standard delivery mechanism for all non-trivial Myco features.

## When to Apply

- Delivering a new feature that spans multiple files
- Implementing any non-trivial change that requires a clean PR commit
- Working on a named feature branch (`feature/branch-name` convention)
- Whenever you need to isolate implementation from the main branch during development

## Procedure

### Step 1: Design on `main`

Write the design spec in `docs/superpowers/specs/` while on the main branch. Commit only the spec, not implementation.

```bash
docs/superpowers/specs/2026-04-13-my-feature-design.md
git add docs/superpowers/specs/
git commit -m "docs: add design spec for my-feature"
```

Note: `docs/superpowers/specs/` is gitignored for external contributors but tracked locally.

### Step 2: Create a git worktree

```bash
git worktree add ../myco-branch-name feature/branch-name
cd ../myco-branch-name
```

**Critical**: use a sibling directory (e.g., `../myco-branch-name`), **not a subdirectory inside the repo**. Nested worktrees confuse Myco's CWD detection and create phantom sessions.

### Step 2b: Pin the worktree to its dev binary

```bash
make dev-link-worktree
```

This writes a `.myco/runtime.command` file that pins this worktree to the freshly-built in-repo binary (not via the shared `~/.local/bin/myco-dev` wrapper script). All hooks, MCP calls, and CLI invocations in this worktree then dispatch to the worktree build. The file is gitignored, so it's never committed. When you're done (Step 6), run `make dev-unlink-worktree` to remove the pin.

Skip this step ONLY when you deliberately want the worktree to fall back to the global binary.

**Isolation caveat — schema migrations**: Do NOT use `make dev-link-worktree` when the feature branch carries a schema migration that the shared `~/.myco` vault hasn't seen yet. Running the worktree binary against the shared vault will migrate it in place, breaking the main branch. For isolated programmatic testing in schema-migration scenarios, use a temp git repo with a separate `MYCO_HOME`:

```bash
export MYCO_HOME=$(mktemp -d)   # scratch vault — migrated fresh, main vault untouched
./dist/myco-daemon &
# run your tests here
unset MYCO_HOME
```

**Vendor asset caveat**: Native vendor assets are not automatically rebuilt in new worktrees. If the daemon or tests fail with native module errors after creating a worktree, run `npm rebuild` to force recompilation before proceeding.

**Safe dogfood sequence**: (1) develop and commit on the worktree; (2) run isolated tests with a temp `MYCO_HOME` if the branch has schema changes; (3) switch to the root checkout for live daemon dogfood once the migration is confirmed safe.

### Step 3: Implement with incremental commits

Commit regularly in the worktree. Don't worry about commit message quality — these will be squashed. Keep `.myco/` and `VAULT_GITIGNORE`-tracked files out of commits.

### Step 4: Run the `code-review high` Quality Pass

After implementation, run `code-review high` (the current quality pass — `/simplify` is deprecated) to trigger a multi-agent fan-out review targeting four classes of technical debt that accumulate during fast feature work. This pass must complete **before** the squash — review changes belong in the final commit, not a follow-up PR.

**Sequence constraint**: commit review changes in the worktree — they will be squashed into the single feature commit at delivery.

#### 4a. Identify and Extract Duplication

```bash
git diff --name-only main          # files changed in this branch
grep -rn "\.slice(0, 8)" packages/ # session ID truncation patterns
grep -rn "new Date().toLocaleString" packages/ # date formatter candidates
```

Any logic appearing 2+ times across changed files is a candidate for extraction. Shared helpers go in `packages/myco/src/utils/` or the appropriate utility module within the relevant package. **Check existing utility modules before adding anything** — re-extracting an existing helper creates a naming conflict and a second source of truth.

```typescript
// Before: inline in two components
const display = sessionId.slice(0, 8) + '...';
// After: import from utility module
import { shortSession } from '../utils';
const display = shortSession(sessionId);
```

#### 4b. Replace If-Ladders with Dispatch Tables (3+ cases only)

```typescript
// Before: growing if-else chain
if (type === 'session_start') { handleSessionStart(payload); }
else if (type === 'spore_created') { handleSpore(payload); }
else { log.warn('unknown type', type); }

// After: dispatch table — new types are one-line additions
const handlers: Record<string, (p: Payload) => void> = {
  session_start: handleSessionStart,
  spore_created: handleSpore,
};
const handler = handlers[type];
if (handler) handler(payload);
else log.warn('unknown type', type);
```

Only apply when there are **3+ cases** or the list is clearly growing. A 2-entry dispatch table is often less readable than a plain if/else.

#### 4c. Simplify Function Signatures (4+ parameters)

Functions with 4+ parameters where 2+ are always passed together → group into a context object:

```typescript
// Before: 5 loose parameters
function emitNotification(sessionId, type, payload, machineId, timestamp)

// After: stable params grouped into a context object
interface NotificationCtx { sessionId: string; machineId: string; timestamp: number; }
function emitNotification(ctx: NotificationCtx, type: string, payload: object)
```

The daemon layer (`packages/myco/src/daemon/`) and CLI handlers (`packages/myco/src/cli/`) accumulate parameter debt the fastest.

#### 4d. Check React Prop Threading (3+ component layers)

If a value passes through 3+ React component layers without being used by intermediate layers, use `React.createContext` or restructure the component tree:

```tsx
// Red flag: sessionId passes A → B → C but B never uses it
<SessionPage sessionId={id}>
  <SessionContainer sessionId={id}>  {/* passes through, never reads */}
    <SessionCard sessionId={id} />   {/* actual consumer */}
  </SessionContainer>
</SessionPage>
```

Check React components in the UI package after any feature that adds new data to page-level views.

#### 4e. Verify Zero Regressions

Run TypeScript **before** tests — TypeScript catches renamed/refactored signature mismatches before you waste time debugging misleading test failures:

```bash
npx tsc --noEmit
npm test
```

Both must be clean before committing.

#### 4f. Commit the review pass

```bash
git add -A
git commit -m "refactor: code-review pass — <feature-name>"
```

This commit will be squashed into the feature commit in Step 6.

### Step 5: Run `make build`

```bash
make build
```

This runs lint + fast unit tests + bundler (`tsc` + `vitest` fast profile + `tsup` + `vite`). Integration, smoke, and daemon tests are excluded from the default profile — they run in CI on every PR. **Do NOT use `npm run build`** — it runs only the bundler, silently skipping type checks and tests. For pre-release confidence when tagging a release, use `make build-all` instead. `make build` is the standard gate before squash. Never proceed until it passes cleanly.

### Step 6: Squash all commits, delete worktree, push

Run from inside the worktree directory (`../myco-branch-name`):

```bash
# Squash all implementation + simplify commits into one
git reset --soft $(git merge-base HEAD main)
git commit -m "feat: <single clear description of the feature>"

# Remove the dev binary pin
make dev-unlink-worktree

# Delete the worktree before pushing
git worktree remove ../myco-branch-name

# Push the feature branch
git push origin feature/branch-name
```

The single squashed commit becomes the PR commit.

## Key Gotchas

### Core Worktree Hazards

- **Native modules fail to build inside worktrees** — packages with native dependencies (sqlite-vec, better-sqlite3) cannot compile inside git worktrees. All test failures trace to native module build errors, not code issues. Use `npm rebuild` after creating worktrees to force recompilation.

- **Nested UI workspace installs required** — new worktrees need `npm install` inside each `packages/*/ui` directory. The root install doesn't cover nested UI workspaces. Run manually after worktree creation to prevent build failures in UI components.

- **Daemon segfault on worktree activation** — activating a worktree while the daemon is running can cause segmentation faults. Stop the daemon before creating or switching worktrees: `pkill -f "myco-daemon"` then restart after worktree setup.

- **Wrong daemon takeover** — worktrees can spawn duplicate daemon processes that compete for the same vault. Check for phantom processes with `ps aux | grep myco` before starting work in a worktree.

- **Config path contamination** — worktree-local paths can leak into shared config files, breaking subsequent sessions. Avoid absolute path references in temporary configs; use relative paths or environment variables.

- **Branch activation failures** — switching branches within an active worktree confuses git state. Always `git checkout` to the intended branch immediately after worktree creation, before any commits.

- **Resource cleanup incomplete** — interrupted worktree operations leave stale references. Use `git worktree prune` periodically to clean orphaned worktree entries.

- **`git checkout <sha>` silently detaches HEAD in worktrees** — running `git checkout <commit-sha>` inside a worktree puts the worktree in detached HEAD state; subsequent commits are orphaned from the branch ref and will be lost after `git worktree remove`. Recovery: `git checkout -B <branch-name> <sha>` to re-attach HEAD to the intended branch before committing.

### Binary and Path Safety

- **Hardcoded binary names leak between scopes** — build scripts that reference fixed binary names (e.g., `myco-daemon`) break when multiple worktrees exist. Use dynamic scope dispatch to isolate binary instances.

- **Absolute path leaks** — worktree-specific absolute paths contaminate shared configuration. Always use relative paths or project-root-relative references in config files.

- **Build artifact scope collision** — multiple worktrees can overwrite each other's build outputs. Ensure build directories are worktree-scoped or use unique naming.

- **Never run `make dev-link` from a worktree directory** — `make dev-link` copies the built binary to `~/.myco-dev/bin/myco` and writes a wrapper script at `~/.local/bin/myco-dev`; running it from inside a worktree routes the global daemon through the worktree binary, breaking isolation for all other sessions. Always run `make dev-link` from the root repo checkout. Use `make dev-link-worktree` (inside the worktree) to pin only that worktree's binary.

- **`make build` alone does NOT update the standalone dev daemon** — the dev daemon runs via a copied standalone binary at `~/.myco-dev/bin/myco` (not a symlink to the repo build). Running `make build` only refreshes the in-repo build output. To propagate changes to the main dev daemon, run `make dev-link` + daemon restart. Exception: worktrees using `make dev-link-worktree` point directly to the in-repo build, so `make build` + restart is sufficient there.

### CLI and Configuration Compatibility

- **CLI subcommand help regression prevention** — when adding new CLI commands or modifying existing ones, ensure help text remains accessible and accurate. Test `myco <command> --help` patterns after CLI changes.

- **Config tier migration safety** — features that modify configuration must be compatible with Myco's three-tier config system (machine/grove/project/personal). Test config changes across all scope levels during worktree development.

- **Cross-worktree config isolation** — configuration changes made in a worktree should not affect the main development environment or other concurrent worktrees. Use environment variables or temporary config files when needed.

### Standard Quality and Build Gotchas

- **`npm run build` silently ships broken packages** — only `make build` runs lint + fast unit tests + `tsc` + `tsup` + `vite`; for the full test sweep including integration/smoke, use `make build-all`
- **Sibling directory, not subdirectory** — always use `../myco-branch-name`; nested worktrees cause CWD detection misattribution
- **`code-review high` before squash, not after** — review changes belong in the final squashed commit, not a follow-up cleanup PR (`/simplify` is deprecated)
- **Delete the worktree before pushing** — `git worktree remove` must precede `git push`; lingering worktrees confuse subsequent Claude Code sessions
- **Design spec on `main` first** — commit the spec in `docs/superpowers/specs/` before switching to the worktree
- **Run `npm rebuild` after branch switches involving native modules** — if the dependency tree includes native Node addons (e.g., `better-sqlite3`), switching between branches requires `npm rebuild` before running tests or the daemon; failures manifest as cryptic runtime errors, not build errors
- **Stage untracked files before `code-review high`** — Claude Code's review tools only see git-tracked files; new files that haven't been `git add`-ed are invisible; run `git add -N .` (intent-to-add) before any review pass
- **Check existing utility modules before extracting helpers** — re-extracting an existing helper creates a naming conflict during the simplify pass
- **`gh pr merge --squash` exit code is unreliable inside worktrees** — the command can exit non-zero (local checkout fails) even when the remote merge succeeded; do not treat a non-zero exit as a failed merge. Always verify with `gh pr view --json state,mergeCommit` to confirm the actual PR state before retrying or force-pushing.