# pi-managed-axi

`pi-managed-axi` keeps large output from selected CLI executables and loaded Pi extension tools available after compaction. It saves a private recovery artifact, returns a bounded preview, and lets the agent recover the received text with `axi_read`. It does not execute commands, authorize tools, or change Pi's active tool set. See the [AXI design principles](https://axi.md/).

![AXI settings](./settings.png)

## Workflow without pi-managed-axi

```mermaid
flowchart LR
    A[Agent] --> B[Pi Bash or PowerShell tool]
    B --> C[Command]
    C --> D[Tool result]
    D --> A
    D -. "large output may be truncated" .-> A
```

## Workflow with pi-managed-axi

```mermaid
flowchart LR
    A[Agent] --> B[Pi Bash or PowerShell tool]
    B --> C[Command]
    C --> D[Native tool result]
    D --> H[pi-managed-axi result hook]
    H --> P[Bounded preview plus result ID]
    P --> A
    A --> R[axi_read]
    R --> S[Saved stdout stderr and formatted output]
    S --> Q[Page plus nextOffset or eof]
    Q --> A
    Q -- "nextOffset is not null" --> R
```

A single command may be followed by several `axi_read` calls. The agent repeats the call with `offset=nextOffset` until `eof=true`.

## Config

The built-in CLI candidate list is maintained in [`src/policy/default.json`](./src/policy/default.json).

By default, AXI reads:

```text
~/.pi/agent/pi-managed-axi.json
```

Set `PI_CODING_AGENT_DIR` to use another agent directory. AXI then reads `pi-managed-axi.json` from that directory.

```json
{
  "candidateCli": ["curl", "my-cli"],
  "managedCli": ["my-cli"],
  "managedPlugin": ["myPluginTool"]
}
```

- Omit `candidateCli` to use the built-in CLI catalog.
- Set `candidateCli` to an array to replace the catalog; `[]` disables CLI discovery.
- `managedCli` contains selected CLI executables.
- `managedPlugin` contains exact names of selected tools from loaded Pi extensions.
- Stale CLI and plugin selections remain saved and are shown as unavailable until removed.

Older `candidateTools` and `managedTools` keys are read as `candidateCli` and `managedCli` when the new keys are absent. AXI writes only the canonical keys. There is no `candidatePlugin`; plugin candidates come from the loaded Pi runtime.

### `/axi settings`

Run `/axi settings` in interactive Pi. The `CLI` tab scans `PATH`; the `Plugins` tab lists tools registered by loaded extensions. `Tab` switches tabs, `Space` toggles a tool, `Enter` or `Ctrl+S` saves both tabs, and `Esc` cancels. These settings affect AXI output capture only. They never enable or disable Pi tools. `/axi configure` remains a hidden alias.

### `/axi stats`

Run `/axi stats` to show the number of saved AXI results and their stored stdout, stderr, and formatted byte totals for the current session. It works in interactive and non-interactive modes. It does not scan or modify temporary files.

## Recovery

When AXI changes a result, it adds a marker like this:

```text
[axi result=<id> captureComplete=true previewComplete=false; call axi_read with {"result":"<id>","stream":"formatted"}]
```

Call `axi_read` with `result`, an optional `stream` (`stdout`, `stderr`, or `formatted`), and an optional byte `offset` and `limit`.

```json
{
  "result": "<id>",
  "stream": "formatted",
  "offset": 0,
  "limit": 32768
}
```

Result IDs are private bearer references. A child Pi session on the same host can use the parent’s ID with `axi_read`; do not expose IDs outside the trusted session tree. Use the returned `nextOffset` for the next page. `previewComplete=true` means the AXI preview fits; for plugin tools, `captureComplete=false` still means the upstream tool may have supplied incomplete text.

## Behavior and safety

- The hook observes Pi tool results; it does not run, block, or approve commands.
- Only selected CLI executable names in simple Bash or PowerShell commands, and selected loaded-extension plugin tools, are eligible.
- Shell operators, wrappers, unknown executables, recovery tools, mixed plugin content, and unrelated tool results remain unchanged.
- Complete native stdout, stderr, and formatted output are stored in private temporary files. Plugin output is captured only when it has one text content item, and only as received; `captureComplete=false` means the upstream result may already be truncated. AXI leaves mixed text/non-text plugin results unchanged.
- Invalid, unsafe, missing, or incomplete shell spill files are left native rather than guessed. AXI never opens paths supplied by plugin output. A nested command may be observed by its own AXI hook; outer Fabric aggregation is a separate interception boundary.

## Development

```sh
npm install
just setup
just quality
npm run pack:check
```

The package requires Node.js `>=22.19.0`. When developing from this checkout, load the local package only; a second installed `pi-managed-axi` copy causes Pi to reject duplicate `axi_read` registration during reload.
