# Extension bundle

The curated set of extensions that auto-load for this repo. Each `.ts` file (or
directory with `index.ts`) here is loaded by pi as `@garaje/base` package
extensions: the local-path `packages` pin in `.pi/settings.json` names this
directory (`extensions/**`, with an optional filter), and pi merges it in at
session start — no symlink involved.

See [`docs/garaje-spec.md`](../../docs/garaje-spec.md) for the
**bundle** vs **preset** vs **role** terminology and the framework design.

> **Status — testing scaffolding vs garaje substrate.** The **vendored** and
> **example-forked** rows below (notably `subagent/` and `plan-mode/`) are
> **development-time testing scaffolding**: placeholder copies of pi's bundled
> *example* extensions, carried while the framework is built out. They are
> **not** committed framework features — the plan is to replace them with
> maintained off-the-shelf pi packages (e.g. `npm:pi-subagents`,
> `pi-web-access`) pinned declaratively in `.pi/settings.json` `packages`. Only
> the garaje-specific extensions — `agent-rules` + `protected-paths` (forked)
> and `role-commands` + `standalone-commands` + `usage-status` (local) — are
> intended as permanent `@garaje/base` substrate. Do not build new features on
> top of the vendored copies. See the Phase-3 spec's "Known follow-ups".

## Lineup

| File                  | Origin    | Purpose                                                                                  |
| --------------------- | --------- | ---------------------------------------------------------------------------------------- |
| `agent-rules.ts`      | forked    | Scans base package rules (`packages/base/rules/*.md`) plus local `.agent/rules/*.md` overrides, lists them in the system prompt so the agent can read them. |
| `protected-paths.ts`  | forked    | Blocks `write`/`edit` to secrets, VCS internals, deps, and the framework substrate (`docker-compose.yml`, `compose.framework.yaml`, Dockerfile, entrypoint, `packages/base/`, `.pi/settings.json`). |
| `confirm-destructive` | vendored  | Confirms before destructive session actions (`/new`, `/resume`, fork).                   |
| `dirty-repo-guard`    | vendored  | Refuses session switches while the git working tree is dirty.                            |
| `git-checkpoint`      | vendored  | Stashes a checkpoint each turn; offers to restore on fork.                               |
| `plan-mode/`          | forked    | Read-only "plan first" mode toggle and badge. Command renamed `/plan` → `/plan-mode` so role-commands can own `/plan`. |
| `subagent/`           | vendored  | Spawn isolated child pi processes as named subagents. Base roles ship in the `@garaje/base` package's `agents/` (regenerated by `bin/build-roles`); `.pi/agents/` is the local project override dir. |
| `preset.ts`           | vendored  | `/preset <name>` to swap model + thinking + tool allowlist + prompt fragment in one shot. Base presets ship in the `@garaje/base` package's `presets.json` (regenerated by `bin/build-roles`); `.pi/presets.json` is the local project override file. |
| `role-commands.ts`    | local     | `/plan`, `/spec`, `/review` — thin wrappers that switch preset and kick off a templated turn. |
| `standalone-commands.ts` | local  | `/checkpoint`, `/handoff`, `/proof` — repo-flavored commands that don't wrap a preset. |
| `session-name.ts`     | vendored  | `/session-name` command for naming sessions in the picker.                               |
| `custom-compaction`   | vendored  | Replaces default compaction with a full-context summary (uses Gemini Flash).             |
| `status-line.ts`      | vendored  | Footer "Turn N…/✓ Turn N complete" indicator.                                           |
| `model-status.ts`     | vendored  | Footer badge with current model id; notifies on changes.                                 |
| `usage-status.ts`     | local     | Footer block: live tokens + $ for the current session. Resets on every `session_start`. |
| `notify.ts`           | vendored  | Terminal-native notification (OSC 777/99/toast) when the agent goes idle.                |

## Vendored vs forked

- **vendored** files are byte-for-byte copies of the upstream examples shipped
  with `@earendil-works/pi-coding-agent`. Don't edit them in place — if you
  need a behaviour change, fork (rename + edit + note the divergence in the
  file header) so future refreshes don't clobber local changes.
- **forked** files have a header block stating what was changed relative to
  upstream.

## Refreshing from upstream

The pi npm package ships the originals at
`/usr/local/lib/node_modules/@earendil-works/pi-coding-agent/examples/extensions/`.
When bumping pi:

```bash
SRC=/usr/local/lib/node_modules/@earendil-works/pi-coding-agent/examples/extensions
DST=packages/base/extensions
for f in confirm-destructive.ts custom-compaction.ts dirty-repo-guard.ts \
         git-checkpoint.ts model-status.ts notify.ts preset.ts \
         session-name.ts status-line.ts; do
  diff -u "$DST/$f" "$SRC/$f" || cp "$SRC/$f" "$DST/$f"
done
diff -ru "$SRC/plan-mode" "$DST/plan-mode"
diff -ru "$SRC/subagent"  "$DST/subagent" --exclude=agents --exclude=prompts --exclude=README.md
```

Re-review the forks (`agent-rules.ts`, `protected-paths.ts`) against the
upstream originals (`claude-rules.ts`, `protected-paths.ts`) to pick up bug
fixes.

## Adding to the bundle

1. Drop a `.ts` file (or directory with `index.ts`) into this folder.
2. Add a row above and note whether it's vendored or homegrown.
3. Restart pi (or `/reload`).

## Where these fit

These extensions are the agent-side substrate the garaje ships with: rules
surfacing (`agent-rules`), guardrails (`protected-paths`, `dirty-repo-guard`,
`confirm-destructive`, `git-checkpoint`), flow (`plan-mode`, `preset`,
`role-commands`, `standalone-commands`, `subagent`), and footer telemetry
(`status-line`, `model-status`, `usage-status`, `notify`). Slash commands
(`/plan`, `/spec`, `/review`, `/checkpoint`, `/handoff`, `/proof`) come from
the `role-commands` / `standalone-commands` rows; subagent roles live in
`packages/base/prompts/roles/`, regenerated into `packages/base/presets.json`
and `packages/base/agents/` by `bin/build-roles`.

See [`docs/garaje-spec.md`](../../docs/garaje-spec.md) for the framework
design and [`docs/extensions.md`](../../docs/extensions.md) for the
maintainer-side loading/refresh details.
