{"_id":"@aoligiegie/plannotator-pi-extension","name":"@aoligiegie/plannotator-pi-extension","dist-tags":{"latest":"0.27.6"},"versions":{"0.27.6":{"name":"@aoligiegie/plannotator-pi-extension","version":"0.27.6","type":"module","description":"Plannotator Pi extension - interactive plan review with annotations, annotate agent messages, and review code/PRs","author":{"name":"backnotprop"},"license":"MIT OR Apache-2.0","publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/eightHundreds/plannotator.git","directory":"apps/pi-extension"},"homepage":"https://github.com/eightHundreds/plannotator","bugs":{"url":"https://github.com/eightHundreds/plannotator/issues"},"keywords":["pi-package","plannotator","plan-review","ai-agent","coding-agent"],"//pi":"skills/ is vendored by vendor.sh from apps/skills/core/plannotator and is gitignored, so the shipped copy cannot drift from the single source.","pi":{"extensions":["./"],"skills":["skills/plannotator/SKILL.md"]},"scripts":{"build":"cp ../hook/dist/index.html plannotator.html && cp ../hook/dist/review.html review-editor.html && bash vendor.sh","prepublishOnly":"cd ../.. && bun run build:pi"},"dependencies":{"@joplin/turndown-plugin-gfm":"^1.0.64","@pierre/diffs":"1.3.2","@plannotator/webtui":"0.1.0","chokidar":"^5.0.0","diff":"^8.0.4","parse5":"^7.3.0","turndown":"^7.2.4"},"peerDependencies":{"@earendil-works/pi-coding-agent":">=0.79.1"},"devDependencies":{"glimpseui":"^0.8.0","@earendil-works/pi-coding-agent":">=0.79.1","@earendil-works/pi-agent-core":">=0.79.1","@earendil-works/pi-ai":">=0.79.1","@earendil-works/pi-tui":">=0.79.1"},"gitHead":"fecb2830460345f9284183e5b0b414d8fbcf1fcc","_id":"@aoligiegie/plannotator-pi-extension@0.27.6","_nodeVersion":"24.12.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-HzQnPncGUtwg/+9t9vDAPUk2Et8TkGGRsyKHyX9AqaZaRICSmNkNcThe6jlCfyFH7WZe+7Dj02kv+3yQ2pMynA==","shasum":"e89b3167400c118ff909f1b9275917c3a719e505","tarball":"https://registry.npmjs.org/@aoligiegie/plannotator-pi-extension/-/plannotator-pi-extension-0.27.6.tgz","fileCount":209,"unpackedSize":41581338,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIHwC64dOma2FQeZC5Tb4AV/DI0IPTxbiN09LTkPEYZisAiA/U2RJ/5AAgFLvpl7cn8eF9TT9o2ZWxSHfMOZSx2K5jQ=="}]},"_npmUser":{"name":"aoligiegie","email":"mingoing@outlook.com"},"directories":{},"maintainers":[{"name":"aoligiegie","email":"mingoing@outlook.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/plannotator-pi-extension_0.27.6_1787534836978_0.39706923922459425"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-24T01:27:16.809Z","0.27.6":"2026-08-24T01:27:17.388Z","modified":"2026-08-24T01:27:17.649Z"},"maintainers":[{"name":"aoligiegie","email":"mingoing@outlook.com"}],"description":"Plannotator Pi extension - interactive plan review with annotations, annotate agent messages, and review code/PRs","homepage":"https://github.com/eightHundreds/plannotator","keywords":["pi-package","plannotator","plan-review","ai-agent","coding-agent"],"repository":{"type":"git","url":"git+https://github.com/eightHundreds/plannotator.git","directory":"apps/pi-extension"},"author":{"name":"backnotprop"},"bugs":{"url":"https://github.com/eightHundreds/plannotator/issues"},"license":"MIT OR Apache-2.0","readme":"# Plannotator for Pi\n\nPlannotator integration for the [Pi coding agent](https://github.com/earendil-works/pi). Adds file-based plan mode with a visual browser UI for reviewing, annotating, and approving agent plans.\n\n## Install\n\n**From npm** (recommended):\n\n```bash\npi install npm:@plannotator/pi-extension\n```\n\n**From source:**\n\n```bash\ngit clone https://github.com/backnotprop/plannotator.git\npi install ./plannotator/apps/pi-extension\n```\n\n**Try without installing:**\n\n```bash\npi -e npm:@plannotator/pi-extension\n```\n\n## Pi version and project trust\n\nPlannotator requires **Pi 0.79.1 or newer**. Updating only the Plannotator\nextension does not repair the security behavior of an older Pi host; update Pi\nitself before loading the extension.\n\nPi 0.79 introduced project trust for repository-local inputs. In interactive\nsessions, Pi asks before loading project settings, instructions, resources, and\npackages, and can save the decision for that working directory. Plannotator\nhonors the same decision for `.pi/plannotator.json`.\n\nNoninteractive sessions ignore project-local inputs unless the project already\nhas a saved trust decision or Pi is started with `--approve` (`-a`). Use\n`--no-approve` (`-na`) to disable project inputs for a run even when the project\nwas previously trusted.\n\n## Uninstall\n\nRemove a standalone Pi installation with:\n\n```bash\npi remove npm:@plannotator/pi-extension\n```\n\nIf Pi was configured by the full Plannotator installer, `plannotator uninstall`\nalso detects and removes the extension through Pi.\n\n## Build from source\n\nIf installing from a local clone, build the HTML assets first:\n\n```bash\ncd plannotator\nbun install\nbun run build:pi\n```\n\nThis builds the plan review and code review UIs and copies them into `apps/pi-extension/`.\n\n## Usage\n\n### Plan mode\n\nStart Pi in plan mode:\n\n```bash\npi --plan\n```\n\nOr toggle it during a session with `/plannotator-plan-mode` or `Ctrl+Alt+P`. The command accepts an optional file path argument (`/plannotator-plan-mode plans/auth.md`) or prompts you to choose one interactively.\n\nIn plan mode the agent is restricted — destructive commands are blocked, writes are limited to the plan file. It explores your codebase, then writes a plan using markdown checklists:\n\n```markdown\n- [ ] Add validation to the login form\n- [ ] Write tests for the new validation logic\n- [ ] Update error messages in the UI\n```\n\nWhen the agent calls `plannotator_submit_plan`, the Plannotator UI opens in your browser. You can:\n\n- **Approve** the plan to begin execution\n- **Deny with annotations** to send structured feedback back to the agent\n- **Approve with notes** to proceed but include implementation guidance\n\nThe agent iterates on the plan until you approve, then executes with full tool access. On resubmission, Plan Diff highlights what changed since the previous version.\n\n### Programmatic plan-mode control\n\nOther Pi extensions can enter, exit, toggle, or query Plannotator plan mode through the shared Pi event bus without invoking the `/plannotator-plan-mode` slash command:\n\n```ts\nimport { PLANNOTATOR_REQUEST_CHANNEL } from \"@plannotator/pi-extension/plannotator-events\";\n\nconst response = await new Promise((resolve) => {\n  pi.events.emit(PLANNOTATOR_REQUEST_CHANNEL, {\n    requestId: crypto.randomUUID(),\n    action: \"plan-mode\",\n    payload: { mode: \"enter\" }, // \"enter\" | \"exit\" | \"toggle\" | \"status\"\n    respond: resolve,\n  });\n});\n```\n\nA handled response returns the resulting phase, for example `{ status: \"handled\", result: { phase: \"planning\" } }`.\n\n### Configuring per-phase behavior\n\nPlannotator loads configuration in three layers:\n\n1. Built-in base config shipped with the package: `plannotator.json`\n2. Global user config: `~/.pi/agent/plannotator.json`\n3. Project-local config: `<cwd>/.pi/plannotator.json`\n\nLater layers overwrite earlier ones. If a field is omitted, it inherits the value from lower-precedence layers. If a value is set to `null`, an empty string, or an empty array, it clears the inherited value instead of merging it. You can also set `defaults` or an entire phase object to `null` to clear all inherited settings from lower-precedence layers.\n\n#### Top-level shape\n\n```json\n{\n  \"executionMode\": \"automatic\",\n  \"defaults\": {\n    \"model\": { \"provider\": \"anthropic\", \"id\": \"claude-sonnet-4-5\" },\n    \"thinking\": \"medium\",\n    \"activeTools\": [\"read\", \"bash\"],\n    \"statusLabel\": \"Ready\",\n    \"instructions\": \"Optional phase-entry message template\"\n  },\n  \"phases\": {\n    \"planning\": {\n      \"model\": null,\n      \"thinking\": null,\n      \"activeTools\": [\"grep\", \"find\", \"ls\", \"plannotator_submit_plan\"],\n      \"statusLabel\": \"⏸ plan\",\n      \"instructions\": \"[PLANNING]\\nPlan file: ${planFilePath}\"\n    },\n    \"executing\": {\n      \"model\": { \"provider\": \"anthropic\", \"id\": \"claude-sonnet-4-5\" },\n      \"thinking\": \"high\",\n      \"activeTools\": [],\n      \"statusLabel\": \"\",\n      \"instructions\": \"[EXECUTING]\\nExecute ${planFilePath}.\\n\\nEntry checklist:\\n${todoList}\"\n    },\n    \"reviewing\": {\n      \"instructions\": \"...\"\n    }\n  }\n}\n```\n\n#### Option reference\n\n| Option | Type | Meaning |\n|--------|------|---------|\n| `executionMode` | `automatic` \\| `external` | `automatic` executes approved plans in the current Pi session; `external` emits a handoff event and returns to idle |\n| `defaults` | object | Base values applied to every phase before phase-specific overrides |\n| `phases` | object | Phase-specific overrides |\n| `phases.planning` | object | Settings for planning mode |\n| `phases.executing` | object | Settings for execution mode |\n| `phases.reviewing` | object | Reserved for future review-mode customization |\n| `model` | `{ provider, id }` \\| `null` | Sets the model for the phase; `null` leaves the current model unchanged |\n| `thinking` | `off` \\| `minimal` \\| `low` \\| `medium` \\| `high` \\| `xhigh` \\| `max` \\| `null` | Sets the thinking level; `null` leaves the current level unchanged. Pi clamps a level the running model does not support, and an unrecognized value is reported as a warning instead of being ignored |\n| `activeTools` | string[] \\| `null` | Tools to turn on for the phase. Setting it **replaces** the inherited list rather than adding to it (phase overrides `defaults`, your config overrides the built-in one); `[]` or `null` means no extra phase tools. `plannotator_submit_plan` is always enabled during planning regardless of this setting |\n| `statusLabel` | string \\| `null` | Optional UI label for the phase; empty/null clears it |\n| `instructions` | string \\| `null` | Phase framing template, delivered **once** as a hidden conversation message when the phase is entered; empty/null disables the framing message. Replaces the removed `systemPrompt` key, which is now ignored with a warning |\n\n#### Prompt variables\n\nUse these inside `instructions` strings. They render once, when the phase is entered:\n\n- `${planFilePath}` — current plan file path\n- `${todoList}` — remaining checklist items as markdown checkboxes (an entry-time snapshot; live updates arrive as separate per-turn messages)\n- `${completedCount}` — completed checklist count\n- `${totalCount}` — total checklist count\n- `${remainingCount}` — remaining checklist count\n- `${phase}` — current runtime phase (`planning`, `executing`, `reviewing`, or `idle`)\n\n#### Behavior notes\n\n- **Plannotator never modifies Pi's system prompt.** Pi's base prompt (AGENTS.md context, the skills catalog, tools guidance, `--append-system-prompt` text, working directory) always reaches the model untouched. Phase framing is injected as conversation messages instead, so prompt-cache invalidation reduces to appends at the tail of the conversation plus one history adjustment per phase transition.\n- The `instructions` template is delivered exactly once per phase entry as a hidden message; later prompts in the same phase inject nothing. During execution, a small todo-status message is added per prompt as steps complete. Only the newest framing for the current phase is kept in model context: stale framing from other phases or earlier plan cycles is filtered out, and everything Plannotator injected is filtered while idle.\n- The one exception while idle is a hidden \"plan mode off\" notice, delivered on the first prompt after plan mode is turned off (or a plan completes/hands off), which tells the model the planning/execution instructions no longer apply. It is delivered once but then stays anchored in model context for the rest of the idle session; unlike phase framing it is not re-delivered after a compaction. Sessions that never enter plan mode inject nothing at all.\n- Executing `instructions` that do not reference `${todoList}` get the entry-time todo snapshot appended automatically, so the first executing prompt always carries the checklist.\n- The old `systemPrompt` config key is obsolete and ignored; a warning at session start points to `instructions`.\n- Unknown template variables trigger a warning in the UI and are rendered as empty strings.\n- `activeTools` **replaces** the list it inherits — it does not merge with it. Defining `phases.planning.activeTools` in your own config supersedes the built-in `[\"grep\", \"find\", \"ls\", \"plannotator_submit_plan\"]` entirely, so list every tool you want for that phase.\n- The resolved list is then turned on *alongside* whatever tools are already active in the session, so Plannotator still preserves tools provided by other extensions, and on phase exit it turns off only the tools it added.\n- `plannotator_submit_plan` is always enabled during planning even if your `activeTools` omits it — the planning instructions tell the model to call it, so the phase cannot complete without it.\n- Execution progress remains dynamic (`[DONE:n]` + checklist tracking), even if `statusLabel` is set.\n- `executionMode` defaults to `automatic`, preserving the existing approval-to-execution flow.\n- In `external` mode, approval restores the pre-planning model, thinking level, and active tools before emitting the handoff event.\n\n#### Example files\n\n- Built-in base config shipped with the package: `apps/pi-extension/plannotator.json`\n- Global user override: `~/.pi/agent/plannotator.json`\n- Project-local override: `<cwd>/.pi/plannotator.json`\n\n### Code review\n\nRun `/plannotator-review` to open your current VCS changes in the code review UI. Annotate specific lines, switch between the modes supported by the detected Git, GitButler, or JJ provider, and submit feedback that gets sent to the agent. Pass `--git` or `--gitbutler` to force that provider; GitButler requires `but` 0.21.0 or newer on `PATH`.\n\n### Shared Plannotator event API\n\nPlannotator also listens on the shared `plannotator:request` event channel so other extensions can reuse the same browser review flows without importing Plannotator internals.\n\nSupported actions and payloads:\n\n- `plan-review`: `{ planContent, planFilePath? }`\n- `review-status`: `{ reviewId }`\n- `code-review`: `{ cwd?, defaultBranch?, diffType? }`\n- `annotate`: `{ filePath, markdown?, mode?, folderPath? }`\n- `annotate-last`: `{ markdown? }`\n- `archive`: `{ customPlanPath? }`\n\nPlan review is asynchronous:\n\n- callers send `plannotator:request` with action `plan-review`\n- Plannotator opens the browser review and immediately responds with `{ status: \"handled\", result: { status: \"pending\", reviewId } }`\n- when the human approves or rejects in the browser, Plannotator emits `plannotator:review-result` with `{ reviewId, approved, feedback, savedPath?, agentSwitch?, permissionMode? }`\n- callers can query `review-status` with the same `reviewId` to recover from startup races or session restarts\n\nThe other shared actions remain request/response flows. Payloads are intentionally minimal and only include fields the shared implementation actually uses.\n\n#### External plan execution handoff\n\nSet `executionMode` to `external` when another Pi extension should orchestrate an approved plan instead of letting Plannotator execute it in the current session:\n\n```json\n{\n  \"executionMode\": \"external\"\n}\n```\n\nAfter approval, Plannotator returns to idle and emits `plannotator:plan-approved` with:\n\n```ts\n{\n  cwd: string;\n  planFilePath: string;\n  planContent: string;\n  feedback?: string;\n}\n```\n\n`planFilePath` is the path exactly as it was submitted, so it is normally relative to `cwd`. Resolve it against `cwd` before reading the file rather than against the companion extension's own working directory.\n\nCompanion extensions can subscribe through the shared event bus:\n\n```ts\nimport { PLANNOTATOR_PLAN_APPROVED_CHANNEL } from \"@plannotator/pi-extension/plannotator-events\";\nimport { resolve } from \"node:path\";\n\npi.events.on(PLANNOTATOR_PLAN_APPROVED_CHANNEL, (event) => {\n  const planPath = resolve(event.cwd, event.planFilePath);\n  // Compile and dispatch the approved plan with an external orchestrator.\n});\n```\n\nAs with `plannotator:request`, the channel is a plain string, so a companion can listen with `pi.events.on(\"plannotator:plan-approved\", ...)` and never import Plannotator internals. The constant and the `PlannotatorPlanApprovedEvent` type are exported purely as a typing convenience.\n\nPlannotator does not send `Continue with the approved plan`, enter its executing phase, or track checklist progress in this mode. The companion extension owns execution after the handoff.\n\n### Markdown annotation\n\nRun `/plannotator-annotate <file.md>` to open any markdown file in the annotation UI. Useful for reviewing documentation or design specs with the agent.\n\nURL targets work too. A loopback `http` URL that answers with an HTML page (a running dev app, e.g. `http://localhost:5173`) opens **live**: the app is served through a local reverse proxy and annotated in place, with HMR and WebSockets passed through. `--static` forces the classic markdown conversion; `--app` requires a live session and errors instead of falling back. Live sessions are unavailable in remote mode (`PLANNOTATOR_REMOTE`).\n\n### Annotate last message\n\nRun `/plannotator-last` to annotate the agent's most recent response. The message opens in the annotation UI where you can highlight text, add comments, and send structured feedback back to the agent.\n\n### Archive browser\n\nThe Plannotator archive browser is available through the shared event API as `archive`, which opens the saved plan/decision browser for future callers. The orchestrator does not expose a dedicated archive command yet.\n\n### Progress tracking\n\nDuring execution, the agent marks completed steps with `[DONE:n]` markers. Progress is shown in the status line and as a checklist widget in the terminal.\n\n## Commands\n\n| Command | Description |\n|---------|-------------|\n| `/plannotator-plan-mode` | Toggle plan mode. The agent writes a markdown plan file anywhere in the working directory and submits its path |\n| `/plannotator-review` | Open code review UI for current changes |\n| `/plannotator-annotate <file>` | Open markdown file in annotation UI |\n| `/plannotator-last` | Annotate the last assistant message |\n\n## Flags\n\n| Flag | Description |\n|------|-------------|\n| `--plan` | Start in plan mode |\n\n## Keyboard shortcuts\n\n| Shortcut | Description |\n|----------|-------------|\n| `Ctrl+Alt+P` | Toggle plan mode |\n\n## How it works\n\nBy default, the extension manages a state machine: **idle** → **planning** → **executing** → **idle**. With external execution enabled, approval follows **idle** → **planning** → **idle** and emits the handoff event.\n\nDuring **planning**:\n- All tools from other extensions remain available\n- Bash is unrestricted — the agent is guided by the planning instructions not to run destructive commands\n- Writes and edits restricted to the plan file only\n\nDuring **executing**:\n- Full tool access: `read`, `bash`, `edit`, `write`\n- Progress tracked via `[DONE:n]` markers in agent responses\n- Plan re-read from disk each turn to stay current\n\nState persists across session restarts via Pi's `appendEntry` API.\n\n## Requirements\n\n- [Pi](https://github.com/earendil-works/pi) >= 0.74.0\n","readmeFilename":"README.md","_rev":"1-ece4d1805142bd25bf388a540c1520f3"}