How Pi Web Integrates Git Worktrees and Project Grouping
Pi Web integrates git worktrees by resolving the shared repository root via git rev-parse, grouping sessions under a common projectRoot, and exposing REST endpoints that handle worktree creation, deletion, and file access while maintaining a 60-second cache to avoid repeated Git calls.
Pi Web, an open-source project from the agegr/pi-web repository, treats the Git repository as the fundamental organizational unit for terminal sessions. When your working directory resides inside a linked worktree, the system automatically discovers the main repository root and current branch to maintain proper session hierarchy. This integration ensures that all worktrees belonging to the same project appear grouped together in the UI while remaining independently manageable through a dedicated API.
Resolving Repository Context with resolveProject
At the core of the integration is the resolveProject(cwd) function defined in lib/worktree.ts (lines 76‑110). This utility executes a targeted Git command (git rev-parse …) to obtain three critical pieces of information: the common Git directory, the actual top-level checkout path, and the current branch name.
The function distinguishes between the main repository checkout and linked worktrees by setting an isWorktree flag. It also marks the top-level directory with isTopLevel to ensure the UI only renders the worktree switcher at the repository root. To prevent performance degradation from repeated shell calls, results are cached on globalThis.__piProjectCache with a 60-second TTL.
Grouping Sessions by Project Root
Session aggregation occurs in listAllSessions() within lib/session-reader.ts (lines 22‑46). For each unique working directory (cwd), the function invokes resolveProject and merges the returned ProjectInfo into the corresponding SessionInfo objects.
This enrichment adds two key fields:
projectRoot– The main repository root (or thecwditself for non-Git directories), used as the grouping key in the sidebar UI.worktreeBranch– The branch name when the session lives inside a worktree (populated only whenproject?.isWorktree && project.branch).
Consequently, all terminal sessions across different worktrees of the same repository cluster under a single project node in the interface.
REST API for Worktree Management
The route file app/api/worktrees/route.ts exposes three endpoints that surface worktree operations to the frontend:
Listing Worktrees
The GET /api/worktrees?cwd=… endpoint returns the resolved projectRoot, a boolean isGit, the isTopLevel status, and a list of existing worktrees via listWorktrees. The handler automatically calls allowFileRoot for each discovered worktree path, ensuring the file explorer can browse them immediately without manual configuration.
GET /api/worktrees?cwd=/home/user/my-repo/feature-branch
{
"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 }
]
}
Creating Worktrees
The POST /api/worktrees endpoint creates new worktrees under the convention <repoRoot>-worktrees/<sanitized-branch>. The addWorktree function in lib/worktree.ts (lines 73‑88) validates the branch name, ensures the target directory does not already exist, executes git worktree add, and registers the new path with allowFileRoot.
POST /api/worktrees
Content-Type: application/json
{
"cwd": "/home/user/my-repo",
"branch": "feature-xyz"
}
{ "path": "/home/user/my-repo-worktrees/feature-xyz", "branch": "feature-xyz" }
Removing Worktrees
The DELETE /api/worktrees endpoint invokes git worktree remove. If the worktree contains uncommitted changes, the route returns a 409 status with dirty: true, allowing the UI to prompt the user for a forced removal.
DELETE /api/worktrees
Content-Type: application/json
{
"cwd": "/home/user/my-repo",
"path": "/home/user/my-repo-worktrees/old-branch",
"force": true
}
{ "success": true }
File Access and Edge Case Handling
Worktree-aware file access is managed through allowFileRoot, imported from lib/allowed-roots.ts. This function updates an in-memory whitelist that the /api/files endpoint consults, ensuring newly created worktrees are instantly browseable even after a server restart.
When a worktree directory disappears from the filesystem, resolveProject falls back to inferRemovedWorktree, re-grouping existing sessions that pointed at the now-missing worktree under the main repository root rather than leaving them orphaned.
Summary
resolveProject()inlib/worktree.tsdetects worktrees viagit rev-parseand caches results for 60 seconds to optimize performance.listAllSessions()enriches session metadata withprojectRootandworktreeBranch, enabling the UI to group terminals by their underlying repository.- REST endpoints in
app/api/worktrees/route.tsprovide full CRUD operations, creating worktrees under<repoRoot>-worktrees/and handling dirty-state conflicts with409responses. allowFileRootautomatically whitelists worktree paths for the file explorer, whileinferRemovedWorktreegracefully handles deleted worktrees by falling back to the main repository root.
Frequently Asked Questions
How does Pi Web detect the main repository root from a worktree?
Pi Web executes git rev-parse commands within resolveProject() to identify the common Git directory and top-level checkout path. When inside a linked worktree, the function resolves to the shared repository root and sets isWorktree: true, distinguishing it from the main checkout.
What happens to sessions when a worktree directory is deleted?
If a worktree directory is removed outside of Pi Web, the resolveProject function detects the missing path and invokes inferRemovedWorktree to fall back to the inferred project root. Existing sessions are automatically re-grouped under the main repository node instead of becoming orphaned entries in the UI.
Where does Pi Web create new worktrees?
New worktrees are created under the <repoRoot>-worktrees/<sanitized-branch> directory structure as implemented in the addWorktree function (lines 73‑88 of lib/worktree.ts). This convention keeps worktrees organized adjacent to the main repository while preventing name collisions.
How does Pi Web handle file access for new worktrees?
Immediately upon creation, the allowFileRoot utility (from lib/allowed-roots.ts) updates the server's in-memory whitelist of accessible directories. This ensures that the /api/files endpoint can serve content from the new worktree path without requiring a server restart or manual configuration.
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 →