pi-worktrees/pi-worktree-implementation-plan.md
2026-07-24 12:16:00 +10:00

15 KiB

pi-worktree Implementation Plan

Overview

Step-by-step engineering plan for building the pi-worktree extension. Breaks down into discrete implementable units with milestones, sequencing, dependencies, and validation tasks.

Milestones

Milestone 1: Foundation (Day 1-2)

Goal: Set up extension structure and register basic tools.

Task 1.1: Create Extension File

mkdir -p .pi/extensions
touch .pi/extensions/pi-worktree.ts

Deliverable: Empty extension file with correct imports and structure.

Validation: Extension loads without errors when pi starts.


Task 1.2: Register Tool Scaffolding

Register all four tools with minimal implementations (return placeholder responses).

import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { Type } from "typebox";

export default function (pi: ExtensionAPI) {
  // Register tools here
}

Deliverable: Four tool registrations with correct signatures but placeholder execute functions.

Validation:

  • pi.getAllTools() includes all four tools after loading extension.
  • Calling each tool returns a response (even if just "not implemented").

Task 1.3: Implement git_worktree_list

Implementation:

async function executeGitWorktreeList(toolCallId, params, signal, onUpdate, ctx) {
  const result = await pi.exec("git", ["worktree", "list"], { cwd: ctx.cwd });
  
  if (result.exitCode !== 0) {
    return {
      content: [{ type: "text", text: `Error listing worktrees: ${result.stdout}` }],
      isError: true
    };
  }
  
  // Parse output into structured format
  const lines = result.stdout.trim().split("\n");
  const worktrees = lines.map(line => {
    const parts = line.split(/\s+/);
    return {
      path: parts[0],
      branch: parts[1] || "detached",
      isCurrent: line.includes("(current)")
    };
  });
  
  return {
    content: [{ 
      type: "text", 
      text: worktrees.map(w => `${w.branch}${w.path}${w.isCurrent ? " (current)" : ""}`).join("\n")
    }],
    details: { worktrees }
  };
}

Deliverable: Tool that lists all linked worktrees with branch and path.

Validation:

  • Run in a repo with multiple worktrees — verify output matches git worktree list.
  • Test error case (no git repo) — should return clear error message.

Milestone 2: Create and Remove Operations (Day 3-5)

Goal: Implement create and remove operations with error handling.

Task 2.1: Implement git_worktree_create

Implementation Steps:

  1. Validate input parameters.
  2. Check if path already exists — refuse if so.
  3. Determine whether to use -b flag (create new branch) or not.
  4. Run git worktree add <path> [branch].
  5. Handle errors with clear messages.

Error Handling:

  • Path exists: "Path '' already exists. Choose a different location."
  • Branch is current: "Can't create worktree on the current branch — switch first."
  • Git error: Surface git's message and suggest fixes (e.g., "Git reported 'fatal: ...'. Check if you have permissions or if there's a naming conflict.").

Deliverable: Tool that creates linked worktrees with proper validation.

Validation:

  • Create worktree on new branch — verify it appears in git worktree list.
  • Try to create at existing path — should refuse with clear error.
  • Try to create on current branch — should refuse with clear error.

Task 2.2: Implement git_worktree_remove

Implementation Steps:

  1. Validate input parameters.
  2. Check if target is the main repo — refuse if so (suggest git worktree prune).
  3. Check for uncommitted changes — refuse with message if found.
  4. Run git worktree remove <path>.
  5. Handle errors with clear messages.

Error Handling:

  • Main repo: "Can't remove the main repository. Use 'git worktree prune' instead."
  • Uncommitted changes: "Worktree '' has uncommitted changes. Stash or commit them first?"
  • Git error: Surface git's message and suggest fixes (e.g., "Git reported 'fatal: ...'. Check if you have permissions or if there are open files.").

Deliverable: Tool that removes linked worktrees with proper validation.

Validation:

  • Remove a worktree with no changes — verify it disappears from git worktree list.
  • Try to remove main repo — should refuse with clear error.
  • Try to remove worktree with uncommitted changes — should refuse with clear error.

Milestone 3: Switch Operation (Day 6-7)

Goal: Implement switch operation with cwd change and session integration hooks.

Task 3.1: Implement git_worktree_switch

Implementation Steps:

  1. Validate input parameters.
  2. Resolve target to a path (if it's a branch name, look up the worktree path).
  3. Check if already in that worktree — refuse if so.
  4. Check for uncommitted changes in target — fail fast with message if switching away from it.
  5. Change pi's cwd to the target path.
  6. Trigger session integration hooks (see Milestone 4).

Error Handling:

  • Already there: "Already in this worktree."
  • Uncommitted changes in source: "Worktree '' has uncommitted changes. Stash them first?"
  • Target not found: "No worktree found at ''. Run 'git_worktree_list' to see available worktrees."

Deliverable: Tool that switches pi's working directory to a linked worktree.

Validation:

  • Switch to an existing worktree — verify cwd changes and branch display updates.
  • Try to switch to non-existent target — should refuse with clear error.
  • Verify session integration hooks fire after successful switch.

Milestone 4: Session Integration (Day 8-9)

Goal: Wire up session integration hooks for switch operations.

Task 4.1: Update Branch Display on Cwd Change

Implementation:

// In git_worktree_switch execute function, after changing cwd:
ctx.ui.notify(`Switched to worktree at ${targetPath}`, "info");
// Pi's footer data provider will pick up the new HEAD file automatically
// when it detects the cwd change. No additional code needed for branch display.

Deliverable: Branch display updates automatically after switching worktrees.

Validation:

  • Switch to a worktree on feature-x — verify pi's footer shows feature-x.
  • Switch back to main — verify pi's footer shows main (or whatever the main branch is).

Task 4.2: Offer New Session Creation

Implementation:

// In git_worktree_switch execute function, after successful switch:
const choice = await ctx.ui.select("Create a new session?", [
  "Yes, start fresh for this worktree",
  "No, keep the current session"
]);

if (choice?.startsWith("Yes")) {
  await ctx.newSession({
    setup: async (sm) => {
      sm.appendMessage({
        role: "user",
        content: [{ 
          type: "text", 
          text: `Switched to worktree for branch ${branchName}. Context from previous session...` 
        }],
        timestamp: Date.now()
      });
    },
    withSession: async (newCtx) => {
      newCtx.ui.notify("New session created for this worktree.", "info");
    }
  });
}

Deliverable: After switching worktrees, user is offered the option to create a new pi session.

Validation:

  • Switch to a worktree and choose "Yes" — verify new session is created with appropriate context message.
  • Switch to a worktree and choose "No" — verify current session continues unchanged (except branch display).

Task 4.3: Implement Back-Switching Behavior

Implementation:

// Track previous sessions in memory during pi process lifetime:
const worktreeSessionMap = new Map<string, string>(); // worktree path -> session file
let mainRepoSessionFile: string | undefined;

// When switching TO a worktree:
worktreeSessionMap.set(targetPath, ctx.sessionManager.getSessionFile());

// When switching TO the main repo (detected by checking if target is the original cwd):
if (mainRepoSessionFile) {
  await ctx.switchSession(mainRepoSessionFile);
} else {
  // No previous session tracked — stay in current session
  mainRepoSessionFile = ctx.sessionManager.getSessionFile();
}

Deliverable: Switching back to the main repo auto-restores the previous session.

Validation:

  • Start a session, switch to a worktree (create new session), then switch back to main — verify pi returns to the original session.
  • Verify that the worktreeSessionMap is cleared on pi restart (stateless tools).

Milestone 5: Interactive Command (Day 10)

Goal: Implement /worktree command with interactive picker.

Task 5.1: Register and Implement /worktree Command

Implementation:

pi.registerCommand("worktree", {
  description: "Switch between linked worktrees interactively.",
  handler: async (args, ctx) => {
    // 1. List all worktrees
    const listResult = await pi.callTool("git_worktree_list");
    if (listResult.isError) {
      ctx.ui.notify(`Error listing worktrees: ${listResult.content}`, "error");
      return;
    }
    
    // 2. Parse the structured data and display as picker
    const worktrees = listResult.details.worktrees as Array<{
      path: string;
      branch: string;
      isCurrent: boolean;
    }>;
    
    if (worktrees.length === 0) {
      ctx.ui.notify("No linked worktrees found.", "info");
      return;
    }
    
    // 3. Show interactive picker
    const choice = await ctx.ui.select("Pick a worktree:", 
      worktrees.map(w => `${w.branch}${w.path}${w.isCurrent ? " (current)" : ""}`)
    );
    
    if (!choice) return;
    
    // 4. Find the selected worktree and switch to it
    const selected = worktrees.find(w => 
      choice.startsWith(`${w.branch}${w.path}`)
    );
    
    if (selected) {
      await pi.callTool("git_worktree_switch", { target: selected.path });
    }
  }
});

Deliverable: /worktree command shows an interactive picker and switches to the selected worktree.

Validation:

  • Run /worktree in a repo with multiple worktrees — verify picker shows all options with correct format.
  • Select a worktree — verify pi switches to it and branch display updates.
  • Cancel the picker (Esc) — verify no switch occurs.

Milestone 6: Polish and Documentation (Day 11-12)

Goal: Add final polish, edge case handling, and documentation.

Task 6.1: Handle Edge Cases

Add error handling for:

  • Nested worktrees (git will error — surface the error clearly).
  • Detached HEAD states in worktrees (use path instead of branch name for identification).
  • Untracked files preventing removal (suggest removing or moving them first).
  • Worktrees on the same branch (let git handle it, surface the error if it fails).

Deliverable: Robust error handling for all common edge cases.

Validation:

  • Test each edge case scenario manually and verify appropriate error messages.

Task 6.2: Write README.md

Create .pi/extensions/README.md (or update existing) with:

  • Extension name and purpose.
  • Installation instructions (project-local auto-discovery).
  • Tool descriptions with examples for each of the four tools.
  • Command description with example usage.
  • Session integration behavior.
  • Error handling strategy.

Deliverable: Complete documentation for users and developers.

Validation:

  • Review README for clarity, completeness, and accuracy.
  • Verify all examples work as documented.

Task 6.3: Final Testing and Cleanup

  • Test the complete workflow end-to-end: create → switch → remove.
  • Verify error messages are clear and actionable.
  • Check that session integration works correctly in all scenarios.
  • Clean up any debug logging or TODO comments.

Deliverable: Production-ready extension with no known issues.

Validation:

  • Run through the complete workflow multiple times to catch any regressions.
  • Review code for quality, readability, and maintainability.

Dependencies

External Dependencies

  • Node.js built-ins: child_process (for exec), fs, path. No external npm packages needed in v1.
  • Git: Requires git 2.x with worktree support (available in all modern git versions).
  • TypeBox: Already available as a pi dependency for tool parameter schemas.

Internal Dependencies

  • Pi's extension API (ExtensionAPI, ExtensionContext).
  • Pi's session management (ctx.sessionManager, ctx.newSession(), ctx.switchSession()).
  • Pi's UI methods (ctx.ui.select(), ctx.ui.notify(), etc.).

Validation Strategy

Unit Testing (Manual)

Test each tool in isolation with various inputs:

  • Valid inputs — verify correct behavior.
  • Invalid inputs (missing params, non-existent paths/branches) — verify clear error messages.
  • Edge cases (existing path, current branch, uncommitted changes) — verify appropriate refusals.

Integration Testing (Manual)

Test the complete workflow:

  1. Create a worktree on a new branch.
  2. Switch to it via /worktree command or git_worktree_switch.
  3. Verify branch display updates correctly.
  4. Choose "Yes" when offered a new session — verify new session is created.
  5. Switch back to main — verify auto-restore of previous session.
  6. Remove the worktree — verify it disappears from list.

User Acceptance Testing (Manual)

Have early users run through typical workflows:

  • Feature branch development cycle (create → use → remove).
  • Switching between multiple worktrees frequently.
  • Handling errors and edge cases.

Gather feedback on clarity, usability, and any missing features or confusing behavior.


Timeline Summary

Milestone Days Deliverables
1: Foundation Day 1-2 Extension structure, tool scaffolding, git_worktree_list implemented
2: Create/Remove Day 3-5 git_worktree_create and git_worktree_remove with error handling
3: Switch Operation Day 6-7 git_worktree_switch with cwd change
4: Session Integration Day 8-9 Branch display updates, new session offering, back-switching behavior
5: Interactive Command Day 10 /worktree command with interactive picker
6: Polish and Documentation Day 11-12 Edge case handling, README.md, final testing

Total Estimated Time: ~12 days (assuming part-time development on top of other work).


Success Criteria

The extension is ready for release when:

  • All four tools (create, list, switch, remove) work correctly with clear error messages.
  • /worktree command provides an intuitive interactive picker with branch-first display.
  • Session integration works: branch display updates on switch, new session offered after switch, auto-restore of previous session when returning to main.
  • Edge cases (existing path, current branch, uncommitted changes) are handled gracefully with helpful error messages.
  • Documentation is complete and accurate.
  • No known regressions or critical bugs remain.