# pi-c2c

Native [c2c](https://github.com/clankercode/c2c) integration for
[pi](https://pi.dev).

pi-c2c makes a pi session a c2c peer:

- registers a c2c alias on session start;
- exposes c2c send, list, inbox, room, and alias-management tools to the model;
- exposes `/c2c-*` slash commands for the human;
- polls for inbound c2c messages and injects them into the pi transcript.

## pi-subagents

When `pi-c2c` is loaded in a parent pi session that also uses
`pi-subagents`, every non-isolated subagent becomes its own c2c peer. The
child registers an independent c2c session id derived from the child pi
session, so parent and child inboxes stay separate.

Child aliases are parent-scoped:

```text
<parentAlias>-a<hash6>
```

The hash is derived from the subagent id when `pi-subagents` provides one,
otherwise from the child pi session id. Subagents do not reuse the parent
`C2C_MCP_SESSION_ID`, and they do not claim the raw `C2C_PI_ALIAS`; that value
is treated only as a parent-alias hint when no live parent alias is available.

The child system prompt includes its own c2c alias, the parent alias, and the
exact `c2c_pi_send(target="<parent>", body="<message>")` pattern for reporting
back. The parent transcript also receives a quiet local notice when a child
registers, for example:

```text
Subagent Plan#abc123 registered as `pi-abcd-a012345`.
```

That notice is process-local UI context, not a real c2c direct message.

On `session_shutdown`, pi-c2c deregisters its alias from the per-repo broker
(and the sessions broker when cross-repo registration succeeded). This matters
for in-process subagents: they share the parent process PID, so c2c's pid-based
liveness would otherwise keep finished children listed as alive until the parent
exits.

## Requirements

- pi `0.79` or newer
- Node.js and pnpm for local development

pi-c2c depends on the `@clanker-code/c2c` npm package and will use its
platform binary by default. If you maintain a local/source c2c build, or if the
npm binary is not compatible with your Linux distribution, launch pi with
`C2C_BIN=/path/to/c2c` to override the bundled binary.

## Install

Install from npm:

```bash
pi install npm:pi-c2c
```

For local development:

```bash
pi install /path/to/pi-c2c
```

## Configuration

Common environment variables:

- `C2C_BIN`: c2c binary path, defaults to `c2c`
- `C2C_PI_ALIAS`: preferred alias for this pi session at startup
- `C2C_PI_POLL_INTERVAL_MS`: inbox polling and alias-sync interval, defaults to `5000`

For local-broker auto-delivery, pi-c2c watches the same resolved broker root
as the c2c CLI: `C2C_MCP_BROKER_ROOT`, then
`C2C_STATE_HOME/c2c/repos/<fingerprint>/broker`, then
`$HOME/.c2c/repos/<fingerprint>/broker`. `XDG_STATE_HOME` is intentionally not
used: harnesses can make it profile-specific, which would split a shared c2c
broker. `/c2c-pi-debug` reports the root and resolution source attached by the
watcher.

## Alias changes

In-session renaming is disabled. c2c 0.11.0+ makes aliases **sticky per
session**: re-registering a different alias for an existing session is rejected
(`alias is sticky ... start a fresh session to use a new name`). The
`/c2c-set-alias` command and `c2c_pi_set_alias` tool have been removed
accordingly. To use a different alias, set `C2C_PI_ALIAS` and start a fresh pi
session.

If the alias is changed externally through generic c2c MCP (`c2c_register`) or
the CLI (`c2c register --alias ... --session-id ...`), pi-c2c periodically
detects the broker alias and updates its displayed state to match.

## Runtime state

pi-c2c publishes `idle`, `processing`, `tool`, and `input` lifecycle state
through c2c's canonical statefile sink. Runtime state is **not** sent as c2c
chat, broadcast, room, sessions-broker, or relay traffic.

Each Pi session gets a collision-resistant statefile instance key derived from
its local broker root and c2c session id. Run `/c2c-local-info` or call
`c2c_pi_local_info` to see the key, then inspect the current snapshot with:

```bash
c2c statefile --instance <instance-key> --json
```

As of c2c 0.13 this is a raw inspection surface: Pi statefiles are not listed as
managed c2c instances and are not consumed by the current stats or GUI views.
The file becomes stale after Pi exits rather than being deleted.

When the c2c binary supports `oc-plugin stream-write-statefiles` (c2c **0.14.3+**
with the multi-key sink), pi-c2c multiplexes all in-process identities through
**one** long-lived writer child instead of one process per identity. Older
binaries fall back to per-identity `stream-write-statefile` automatically.
Override the binary with `C2C_BIN` if needed. Packaged multi integration:
`C2C_BIN=/path/to/c2c pnpm exec tsx --test tests/statefile-multi-integration.test.ts`
(or set `C2C_MULTI_INTEGRATION=1` to fail when multi is missing).

For compatibility with older pi-c2c peers, valid legacy XML status envelopes
are still recognised and recorded locally. They are silently removed from
background and manual inbox results; ordinary messages containing status-like
text are left untouched.

## Footer support

pi-c2c publishes a `c2c` status (a colored `●` + your alias) via
`ctx.ui.setStatus`. It renders correctly across pi's footers:

- **Default pi footer** — preserves ANSI; the colored dot shows as-is.
- **pi-bar / tm-bar** — these strip ANSI from extension statuses and prepend a
  `c2c:` key. pi-c2c installs a runtime `Theme.prototype.fg` patch on
  `session_start` that re-colorizes the indicator (green = registered,
  yellow = not). No configuration needed.
- **pi-powerline-footer** — does *not* strip embedded ANSI, so the `c2c`
  status already shows with color + glyph in powerline's aggregate
  `extension_statuses` segment with no configuration.

### Promoting `c2c` to a dedicated powerline segment (optional)

To give c2c its own powerline segment (instead of the aggregate
`extension_statuses` group), add a `powerline.customItems` entry to
`~/.pi/agent/settings.json` (or project-local `.pi/settings.json`) and run
`/reload`:

```json
{
  "powerline": {
    "customItems": [
      { "id": "c2c", "statusKey": "c2c", "position": "right", "prefix": "c2c" }
    ]
  }
}
```

Note: pi-c2c's `c2c` status already carries its own ANSI color (the
green/yellow dot), so the dot stays correctly colored in a dedicated segment.
Adding a `color` to the custom item is **not** recommended — powerline applies
that color over the whole value, but the embedded color codes win per-run, so
it would not recolor the alias and only risks leaving a dangling color. Omit
`color` to keep pi-c2c's built-in green/yellow coloring. The aggregate
`extension_statuses` segment shows the same coloring with no config at all.

## Development

```bash
pnpm install
pnpm check
pnpm test
```

The test suite fixtures the c2c CLI boundary for unit coverage and includes
isolated integration tests for real c2c binaries.

See [RELEASE.md](RELEASE.md) for the current manual release flow.
