# pi-herdr-worktree

[![CI](https://github.com/mcuste/pi-herdr-worktree/actions/workflows/ci.yml/badge.svg)](https://github.com/mcuste/pi-herdr-worktree/actions/workflows/ci.yml)
[![npm](https://img.shields.io/npm/v/@mcuste/pi-herdr-worktree)](https://www.npmjs.com/package/@mcuste/pi-herdr-worktree)

![Pi using the Herdr worktree extension](docs/demo/pi-worktree-demo.gif)

An extension for the [Pi](https://github.com/earendil-works/pi) and
[Oh My Pi](https://github.com/can1357/oh-my-pi) terminal coding agents. It gives the model one
`herdr_worktree` tool that runs a fixed set of [Herdr](https://herdr.dev) Git worktree operations,
instead of letting it type `herdr` commands into a shell.

If any of those names are new to you:

- **Herdr** is a terminal workspace manager for coding agents. It can back a workspace with a Git
  worktree, so a branch gets its own checkout, its own tabs, and its own panes.
- **Pi** and **Oh My Pi** are terminal coding agents. An **extension** is an npm package they load
  at startup to add tools the model can call.

## Why

An agent with shell access can already run `herdr`, but a shell gives it a free-form command
string. Herdr's CLI does not accept `--flag=value`, so every value is a separate argument, and a
value that starts with `-` silently becomes a flag. A wrong `--workspace` deletes the wrong
checkout, `--force` throws away uncommitted work, and `--focus` moves the user's view away from
what they were doing.

This extension replaces that with a closed set of operations. Each one accepts only its own typed
fields, builds a fixed argument array, checks the repository before running, and verifies the
result against Git afterwards. There is no shell string anywhere.

## Requirements

- Node.js 22 or newer
- Git 2.36 or newer
- Herdr 0.8.2 or newer, and an agent running inside a Herdr-managed pane

The extension loads anywhere. Outside a Herdr pane, outside a Git work tree, or without the
`herdr` CLI, a tool call fails with an explanatory error rather than running an unsupported
command.

## Install

Pi:

```bash
pi install npm:@mcuste/pi-herdr-worktree
```

Oh My Pi:

```bash
omp plugin install @mcuste/pi-herdr-worktree
```

Or through the Oh My Pi marketplace:

```text
/marketplace add mcuste/pi-herdr-worktree
/marketplace install pi-herdr-worktree@pi-herdr-worktree
```

From a local checkout:

```bash
pnpm install
pi install /absolute/path/to/pi-herdr-worktree
omp plugin link /absolute/path/to/pi-herdr-worktree
```

## What the tool does

One tool named `herdr_worktree`, selected by an `operation` field:

| Operation | Runs | Purpose |
| --- | --- | --- |
| `list` | `herdr worktree list` | Read every worktree of the current repository |
| `create` | `herdr worktree create` | Add a worktree on a new branch and open it as a workspace |
| `open` | `herdr worktree open` | Open an existing worktree as a workspace |
| `remove` | `herdr worktree remove` | Delete a worktree checkout and close its workspace |

`list` is read-only. The other three change the repository and the session, and Oh My Pi asks for
execute approval; `remove` always prompts, and so does a `create` that names its own `path`. Full
per-operation fields and guarantees are in [docs/operations.md](docs/operations.md).

## System prompt note

The tool loads on demand, so its description is not in the base prompt. The model can reach for
`herdr` or `git worktree` in a shell before it sees the tool, so the extension appends one note to
the system prompt at the start of each turn:

> Use the herdr_worktree tool for Git worktrees, not herdr or git worktree in bash. Create a
> worktree when work needs its own checkout, for example parallel multi-agent work.

The note is added once per prompt, only where detection succeeds, and only in a host that offers
the `before_agent_start` event. A host without that event still gets the tool.

Detection reads `HERDR_ENV` first. That variable belongs to the process, so outside Herdr the
extension starts no child process at all. Inside a Herdr pane, detection also finds the Git
repository and reads the `herdr` version, then caches the result in memory for ten minutes. A
failed detection is cached for five minutes, so a directory that is not a Git work tree does not
run `git` and `herdr` on every turn.

## What is deliberately missing

- **Workspace, tab, pane, and agent control** (`herdr workspace`, `herdr tab`, `herdr pane`,
  `herdr agent`) is a separate concern. This extension only manages worktree-backed workspaces.
- **Session and server control** (`herdr session`, `herdr server`, `herdr update`) can stop the
  user's session and every process in it.
- **`herdr worktree remove` without a verified target.** The tool always lists the repository's
  worktrees first and refuses a workspace that does not hold a linked worktree of it.

For anything else, the model works through the normal Herdr workflow with the user in the loop.

## Safety

Every operation checks the repository before and after it runs: a new worktree must be registered
by Git on the requested branch, an opened worktree must be the one that was asked for, and a
removed checkout must be gone from `git worktree list`. A failed check is reported as an uncertain
result rather than retried.

Arguments are never concatenated into a shell command. Herdr does not accept `--flag=value`, so
every value travels as its own argument and is rejected before spawning if it starts with `-`. Each
value also carries the option it was parsed for, so a label cannot arrive as a branch. See
[docs/safety.md](docs/safety.md).

Focus defaults to off. The tool passes `--no-focus` unless the caller explicitly asks to move the
user's view.

## Documentation

- [Operations reference](docs/operations.md)
- [Safety model](docs/safety.md)
- [Development and release](docs/development.md)
- [Changelog](CHANGELOG.md)

## License

[MIT](LICENSE)
