omp packages

@jordyvanvorselen/pi-bare-worktrees0.1.1

Git worktrees for --bare checkouts in pi: one worktree per task, shared env links, protected branches, and a worktree tool the agent uses itself.

GitHub Actions Published 17 days ago MIT ~502 downloads/mo

Untested on omp

This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.

Did it work for you?

Result

One report per person. A new report replaces your old one.

Reports 0

No reports yet.

Readme

pi-bare-worktrees

Git worktrees for --bare checkouts in pi. One worktree per task, shared env files linked in, protected branches kept read-only, and a worktree tool the agent calls itself.

What it does

  • Every change gets its own worktree. main and other protected branches are read-only. The first edit on them is blocked with a message that tells the model to call worktree create. It then continues in the new worktree without a cd.
  • Shared env, zero config. Every file under <root>/.shared-env/ is symlinked into each worktree at the same relative path. Real files are never overwritten.
  • Fast. No git process on session start or on tool calls. Root detection, worktree listing and link checks read the filesystem. Git runs only when you create, remove, clean, or in the background for the footer.
  • Native. The tool shows up in the system prompt, the footer shows the active worktree, state survives /resume, and subagents inherit the worktree.

Layout it expects

project/
├── .bare/            bare repo (core.bare = true)
├── .shared-env/      gitignored files to mirror, e.g. connect-backend/.env.keys
├── main/             worktree for main
└── feat/login/       worktree for feat/login

Path equals branch name. Create one with:

mkdir project && cd project
git clone --bare git@github.com:org/repo.git .bare
git --git-dir=.bare config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'
git --git-dir=.bare fetch
git --git-dir=.bare worktree add main main

Outside this layout the extension turns itself off and says so once at startup.

Install

pi install npm:@jordyvanvorselen/pi-bare-worktrees

Then, inside a worktree:

/wt setup

Setup opens one screen with every setting prefilled: shared env directory, base branch, protected patterns, branch template, fetch before create, auto-link, post-create commands and copy list. Press Enter through the fields to keep the defaults, or type to edit a value in place. ↑↓ moves between fields, space toggles a yes/no field, ctrl+s saves from anywhere and esc cancels. It saves to .bare/config under [bare-worktrees] and runs doctor right away.

Commands

Command What it does
/wt Pick a worktree and switch the session into it
/wt new <branch> [--from <ref>] [--move] Create at <root>/<branch>, link env, run post-create, switch
/wt use <branch> [--move] Switch into an existing worktree
/wt list Worktrees with active and read-only marks
/wt link Re-sync shared env links into the active worktree
/wt rm <branch> [--force] [--branch] Remove a worktree, optionally its branch
/wt clean Fetch with prune, then pick which gone or missing worktrees to remove
/wt doctor [--fix] Missing links, conflicts, detached HEADs, prunable entries
/wt sync Move the session cwd into the active worktree after the model created it
/wt on / /wt off Enforcement for this session. Off needs a confirm
/wt setup Run the wizard again

--move stashes uncommitted changes and pops them in the target.

The worktree tool

worktree({ action: "create" | "use" | "list" | "status" | "link" | "remove" | "doctor",
           branch?, from?, move?, force? })

After create or use, every built-in tool call is routed into that worktree: relative paths are resolved there and bash runs there. The model never needs cd. Run /wt sync when you want the session itself to move too.

Enforcement

Call Protected worktree Feature worktree
read, grep, find, ls allow allow
bash: build, test, git status/log/diff allow allow
bash: git commit/push/rebase/reset/..., rm, sed -i, > block allow
bash: git worktree, git switch, git checkout <branch> block block
edit, write block allow
subagent cwd set to active worktree same

Blocked calls return a reason that names the exact worktree create call to make. Bash detection is a regex over the command; it catches the common cases and is cheap. git checkout -- <file> is allowed.

Configuration

Per repo, in .bare/config:

[bare-worktrees]
	sharedEnv = .shared-env
	baseBranch = main
	protected = release/*
	branchTemplate = feat/{slug}
	fetchBeforeCreate = false
	postCreate = yarn install --immutable
	copy = .idea
	autoLink = true

Global, in ~/.pi/agent/pi-bare-worktrees.json:

{
  "warnWhenNotBare": true,
  "systemPrompt": true,
  "systemPromptFile": "/path/to/custom-section.md",
  "defaults": { "branchTemplate": "task/{slug}" }
}

systemPromptFile replaces the built-in <worktrees> section. Placeholders: {root} {active} {activePath} {state} {branchTemplate} {example} {baseBranch} {protected}.

Footer and other extensions

The extension publishes its state through ctx.ui.setStatus("wt", ...), which the built-in footer shows. In pi-powerline-footer add a custom item with "statusKey": "wt".

Text looks like ⎇ feat/login ↑2 ● or ⌂ main · ro. ↪ means tools are routed into a worktree the session cwd is not in.

For richer bars, subscribe on the shared bus:

pi.events.on("bare-worktrees:changed", (s) => {
  // { root, active: { branch, path, name, protected } | null, enforcement, routed,
  //   live: { dirty, ahead, behind, gone, missingLinks } | null }
});

Performance notes

  • Session start: one directory walk of .bare/worktrees/* and one lstat per shared file. About 5 ms for 40 worktrees and 12 shared files.
  • Tool calls: string operations only. Under 0.1 ms.
  • Dirty and ahead/behind run in the background after the agent settles, debounced, and stale results are dropped.
  • /wt clean is the only command that touches the network.

Development

npm install
npm run lint
npm run typecheck
npm test
pi -e ./src/index.ts

Run npm run lint:fix to fix lint and formatting problems.

Versioning and releases

This package follows semantic versioning. Every pull request must raise the version in package.json. CI fails the pull request when the version is not higher than on main.

Pick the bump that matches the change:

Change Command Example
Bug fix, docs, internal change npm version patch --no-git-tag-version 0.1.0 → 0.1.1
New feature or setting that keeps old behaviour npm version minor --no-git-tag-version 0.1.1 → 0.2.0
Breaking change, such as a removed or renamed setting npm version major --no-git-tag-version 0.2.0 → 1.0.0

The command updates both package.json and package-lock.json. Commit both files.

When a pull request merges, GitHub Actions runs the checks again and publishes the new version to npm. It then creates a GitHub release tagged with the version number, such as 0.1.2. GitHub generates the release notes from the merged pull requests.