# pi-peon-adapter

[![npm version](https://img.shields.io/npm/v/pi-peon-adapter.svg)](https://www.npmjs.com/package/pi-peon-adapter)

A small pi extension that forwards selected pi lifecycle events to the `peon` executable from the [PeonPing](https://www.peonping.com) project.

PeonPing can then play sounds for events such as submitted prompts, failed bash commands, and completed agent turns.

## When and why to use this extension

This is not the first attempt to write a PeonPing variant for pi.
A few already exist, and some are well-crafted.
However, they come with trade-offs:

* some essentially reimplement PeonPing inside pi, including sound handling, lifecycle behavior, and terminal interaction
* some target older pi APIs
* not all are structured for testability

Use this extension when:

* you want audio feedback on agentic events such as a completed task
* you want to use the official `peon` executable together with pi
* you care about well-tested code

## Installation

First, make sure you have [PeonPing](https://www.peonping.com) installed.
Install and configure it to your liking!

```shell
# NPM
pi install npm:pi-peon-adapter
# GitHub
pi install git:github.com/enolive/pi-peon-adapter
```

## Install locally

Check out the code from the official code repository `https://github.com/enolive/pi-peon-adapter`, and then:

```bash
pi install ./pi-peon-adapter
```

To run once without installing:

```bash
pi -e ./pi-peon-adapter
```

## Configuration

The extension looks for the `peon` executable on your `PATH`.
You can override this by setting up the `PEON_BIN` environment variable to your liking.

**📌 NOTE**\
If the executable is not found, this extension will display a startup warning and won’t activate.

```bash
export PEON_BIN=/path/to/your/peon
```

Set `PI_PEON_ADAPTER_DEBUG_LOG` to enable debug logging.
This is useful when analyzing or reporting a bug.
When debug logging is not configured, the adapter stays silent except for startup warnings such as a missing `peon` executable.

```bash
# will produce a simple log in the given path
export PI_PEON_ADAPTER_DEBUG_LOG=/tmp/pi-peon-debug.log
pi

# follow the log in a second terminal
tail -f /tmp/pi-peon-debug.log
```

## Event mapping

|     |     |     |     |     |
| --- | --- | --- | :-: | --- |
| pi event | PeonPing hook event | [CESP category](https://github.com/PeonPing/openpeon/blob/main/spec/cesp-v1.md) | Sound | notes |
| `session_start` | `SessionStart` | `session.start` | 🔔 | Skips `reload`, `fork`, and contexts without UI. Uses `source=resume` for resume, otherwise `source=startup`. |
| `input` | `UserPromptSubmit` | `task.acknowledge` or `user.spam` | 🔔 | Fires when user input is received. Only for contexts with UI. |
| `agent_settled` | `Stop` | `task.complete` | 🔔 | Sent once after an agent run has fully settled (no pending retry, compaction, or continuation), so the sound fires exactly once per task. |
| `tool_execution_end` | `PostToolUseFailure` | `task.error` | 🔔 | Only for failed bash executions: `isError=true` and `toolName=bash`. Scoping to `bash` is deliberate: PeonPing reserves `task.error` for command failures, not tool errors in general. |
| `session_before_compact` | `PreCompact` | `resource.limit` | 🔔 | Sent before compaction starts. |
| `session_shutdown` | `SessionEnd` | `session.end` | 🔇 | Sent when the session runtime is shutting down. Cleanup only, PeonPing plays no sounds. |
| `permissions:ui_prompt` (event bus) | `PermissionRequest` | `input.required` | 🔔 | Fires immediately before the user-facing permission prompt is shown. `tool_name` carries the event’s `surface`; `session_id` lets peon correlate the popup with the following `PreToolUse` dismissal. |
| `permissions:decision` (event bus) | `PreToolUse` | — | 🔇 | Sourced from the permission system’s decision channel; `tool_name` carries the decision’s `surface`. Only `result=allow` decisions are forwarded; deny decisions are skipped. PeonPing plays no sound, but will remove "needs approval" in compatible terminals. |

Every payload includes `cwd` and a `session_id` prefixed with `pi-`.

**📌 NOTE**\
The two event-bus rows require the optional extension [@gotgenes/pi-permission-system](https://pi.dev/packages/@gotgenes/pi-permission-system) to be installed. Those channels carry no pi context, so `session_id` and `cwd` are reused from the most recent `session_start` captured by the adapter; if no `session_start` has fired yet (or after `session_shutdown`), the event is skipped rather than sent with a guessed `cwd` or `session_id`.

**📌 NOTE**\
`PreToolUse` is sourced from the `permissions:decision` channel rather than any of pi’s `tool_execution_*` lifecycle events. Per pi’s documented lifecycle, `tool_execution_start` is a _preflight_ event that fires **before** the `tool_call` gate (where the permission system runs), so it fires before the permission decision and even for tools that end up denied; `tool_execution_update` fires only for non-blocked calls, but multiple times with each update; `tool_execution_end` always fires (including on block, with `isError=true`). None of them mark "the tool is about to run" exactly once after a successful gate. `permissions:decision` with `result=allow` does, which is why it is the source for `PreToolUse`.

**💡 TIP**\
You can turn individual CESP categories on and off to your likings in [PeonPing’s Configuration](https://github.com/PeonPing/openpeon/blob/main/spec/cesp-v1.md).

## Commands

This extension intentionally does not implement any pi commands such as
`/peon-disable` or `/peon-enable`.
You can always run the executable directly from the pi prompt and use all available commands.

From pi, use a user shell command:

```
# turns peon on and off
!!peon toggle
```

## Separate PeonPing sound pack from the author

**💡 TIP**\
This adapter does not bundle or require any sound pack.
However, I also created a separate sound pack for PeonPing with the voice of [2B from Nier Automata](https://openpeon.com/packs/nier-2b).
Check it out, especially if you get tired of the default voice pack!

## Inspiration

* [PeonPing adapter for OpenCode on GitHub](https://github.com/PeonPing/peon-ping/blob/main/adapters/opencode/peon-ping.ts)
* [helle253@pi-peon on GitHub](https://github.com/helle253/pi-peon)
