How Pi-Web Manages Git Worktree Operations and Project Grouping
Pi-Web treats Git repositories as the fundamental organizing unit for sessions, automatically detecting worktrees to group related sessions under a single project root while exposing create, list, and delete operations through a dedicated API.
Pi-Web, an open-source terminal session manager from the agegr/pi-web repository, leverages Git's worktree feature to organize development environments. When your session's working directory resides inside a worktree, the system discovers the shared repository root and current branch to enable seamless project grouping. This architecture ensures that all worktrees belonging to the same repository appear as a unified project in the UI, with new worktrees instantly accessible without server restarts.
Resolving Projects and Worktrees
The core discovery logic lives in lib/worktree.ts, specifically within the resolveProject(cwd) function spanning lines 76-110. This utility executes git rev-parse commands to obtain the common Git directory, the actual top-level checkout path, and the current branch name.
The function distinguishes between the main checkout and linked worktrees by setting an isWorktree flag. It also determines if the provided path represents the repository root through an isTopLevel boolean, ensuring the UI only displays the worktree switcher at the appropriate hierarchy level. To minimize performance overhead, results are cached on globalThis.__piProjectCache with a 60-second TTL, preventing repeated Git commands during rapid session operations.
Session Enrichment and Project Grouping
Once project metadata is resolved, listAllSessions() in lib/session-reader.ts (lines 22-46) calls resolveProject for each unique working directory. The returned ProjectInfo object enriches SessionInfo with two critical fields:
projectRoot– The main repository root for Git directories, or thecwditself for standard folders.worktreeBranch– The branch name when the session exists within a worktree (populated only whenproject?.isWorktree && project.branchevaluates true).
This enrichment allows the sidebar UI to cluster sessions by their common projectRoot, creating a single project node that contains all associated worktrees.
Worktree Management API
The route file app/api/worktrees/route.ts exposes three HTTP endpoints for worktree operations. Each endpoint integrates with the file system through allowFileRoot (imported from lib/allowed-roots.ts), which updates an in-memory whitelist that the /api/files endpoint references for directory access.
List Existing Worktrees
A GET request to /api/worktrees?cwd=... returns the resolved projectRoot, isGit status, isTopLevel flag, and an array of existing worktrees via the listWorktrees function.
curl "http://localhost:3000/api/worktrees?cwd=/home/user/my-repo/feature-branch"
Response:
{
"projectRoot": "/home/user/my-repo",
"isGit": true,
"isTopLevel": true,
"worktrees": [
{ "path": "/home/user/my-repo-worktrees/feature-branch", "branch": "feature-branch", "isMain": false },
{ "path": "/home/user/my-repo", "branch": "main", "isMain": true }
]
}
Create New Worktrees
A POST request to /api/worktrees creates a new worktree under <repoRoot>-worktrees/<sanitized-branch>. The addWorktree implementation (lines 73-88 in lib/worktree.ts) validates the branch name and ensures the target directory does not exist before registration.
curl -X POST "http://localhost:3000/api/worktrees" \
-H "Content-Type: application/json" \
-d '{"cwd": "/home/user/my-repo", "branch": "feature-xyz"}'
Response:
{ "path": "/home/user/my-repo-worktrees/feature-xyz", "branch": "feature-xyz" }
Remove Worktrees
A DELETE request to /api/worktrees executes git worktree remove. If the worktree contains uncommitted changes, the endpoint returns a 409 status with dirty: true, enabling the frontend to prompt users for forced removal.
curl -X DELETE "http://localhost:3000/api/worktrees" \
-H "Content-Type: application/json" \
-d '{"cwd": "/home/user/my-repo", "path": "/home/user/my-repo-worktrees/old-branch", "force": true}'
Response:
{ "success": true }
File System Integration
Worktree directories must be explicitly whitelisted for the file explorer to browse them. The allowFileRoot utility updates the in-memory whitelist immediately upon worktree creation, ensuring new worktrees are browseable without requiring a server restart. This integration applies to both automatically discovered worktrees and manually added ones through the API.
Handling Removed Worktrees
When a worktree directory disappears from disk, resolveProject falls back to the inferred project root via inferRemovedWorktree. This prevents existing sessions from becoming orphaned; instead, they are re-grouped under the main repository root, maintaining project cohesion even when worktrees are deleted outside of Pi-Web.
Summary
- Pi-Web uses
resolveProject()inlib/worktree.tsto detect Git repositories and worktrees viagit rev-parse, caching results for 60 seconds to optimize performance. - Session grouping occurs in
lib/session-reader.tsthroughlistAllSessions(), which attachesprojectRootandworktreeBranchmetadata to cluster related sessions under unified project nodes. - API endpoints in
app/api/worktrees/route.tsprovide RESTful interfaces for listing, creating, and deleting worktrees, with automatic file system registration viaallowFileRoot. - Graceful degradation ensures sessions point to the main repository root when worktrees are removed externally, preventing orphaned session records.
Frequently Asked Questions
How does Pi-Web detect if a session is running inside a Git worktree?
Pi-Web executes git rev-parse commands through the resolveProject(cwd) function in lib/worktree.ts to identify the common Git directory and top-level path. It sets an isWorktree flag when the session resides in a linked worktree rather than the main checkout, distinguishing between the primary repository and additional worktrees.
Can I create a worktree through the Pi-Web interface?
Yes, the POST /api/worktrees endpoint creates new worktrees under a <repoRoot>-worktrees/<sanitized-branch> directory structure. The system validates branch names, checks for existing directories, and automatically registers the new path with the file explorer whitelist through allowFileRoot from lib/allowed-roots.ts.
What happens to my sessions if I delete a worktree outside of Pi-Web?
Pi-Web handles removed worktrees gracefully through the inferRemovedWorktree fallback mechanism. When resolveProject cannot locate the original worktree directory, it redirects the session's project root to the main repository checkout, ensuring sessions remain grouped under the correct project rather than becoming orphaned.
Why does Pi-Web cache project resolution results?
The system caches ProjectInfo objects on globalThis.__piProjectCache for 60 seconds to avoid the performance overhead of repeatedly executing Git commands when listing or updating sessions. This cache ensures rapid UI updates while maintaining accurate worktree and branch information.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →