# pi Cost Tracking — There's No Native Hook, So Cost Comes From the Proxy

pi has no built-in cost tracking and no usage-metering hook to add one to — its extension events (tool_call, tool_result) never see token counts. The only path to per-call cost is routing pi's model traffic through a proxy. The config, what it buys you, and what the tool-call extension still can't tell you about spend.

<div class="acp-shot-frame">
<img src="/assets/img/screenshots/session-trace-dark.png" alt="An ACP session trace: each model call priced with its token and cached-token counts, interleaved with the tool calls it drove — the cost X-ray for one run" style="width:100%;height:auto;border:1px solid var(--line-2);border-radius:10px;box-shadow:0 20px 50px -24px rgba(0,0,0,0.9);margin:8px 0;" />
</div>

<div style="margin:8px 0 28px;padding:20px 22px;border:1px solid var(--line-2);border-radius:12px;background:var(--color-accent-light,#f0effe);">
  <p style="margin:0 0 12px;font-size:15px;line-height:1.6;color:var(--acp-text);"><strong>Just want the answer?</strong> pi has no cost hook to attach to — you have to move where the model traffic goes. Install the tool-call extension, then add a provider for the cost X-ray:</p>
  <pre data-track="PiCost: Hero Config Copy" style="margin:0 0 12px;background:var(--color-surface,#faf9ff);border:1px solid var(--line-2);border-radius:8px;padding:12px 14px;overflow-x:auto;"><code>curl -sf https://agenticcontrolplane.com/install.sh | bash

# ~/.pi/agent/models.json
{
  "providers": {
    "acp": {
      "baseUrl": "https://api.agenticcontrolplane.com/v1",
      "api": "openai-completions",
      "apiKey": "!cat ~/.acp/credentials",
      "compat": { "supportsDeveloperRole": false, "supportsReasoningEffort": false },
      "models": [{ "id": "gemini-3.5-flash" }]
    }
  }
}
# then: pi --model acp/gemini-3.5-flash</code></pre>
  <p style="margin:0;font-size:13px;color:var(--acp-text-dim);"><a href="/integrations/pi" data-track="PiCost: Integration Guide" style="font-weight:600;">Full pi install guide →</a> &nbsp;·&nbsp; <a href="/controls/pi" data-track="PiCost: Controls Reference">pi's control model, explained →</a> &nbsp;·&nbsp; free up to 5 agents</p>
</div>

pi's minimalism is the whole design — four tools, no permission system, extend it yourself. That same minimalism means there's no cost hook to extend, either. The two typed events an extension gets, `tool_call` and `tool_result`, dispatch on *tools*: they see arguments and results, never a token count or a model's usage fields. There is no seam inside pi where an extension could intercept a model call the way it intercepts a tool call, because pi doesn't route model calls through its extension pipeline at all.

That makes pi's cost story different in kind from [Hermes's](/blog/hermes-cost-tracking), which has an in-process hook on every LLM request, and closer in shape to [Codex CLI's](/blog/codex-cli-cost-tracking): the only way to see what a call cost is to change where it goes.

## Why the extension can't do this

The [ACP extension for pi](/controls/pi) is genuinely comprehensive for what it covers — `tool_call` fires before every `bash`, `read`, `write`, `edit`, or custom tool call and can deny or rewrite it; `tool_result` fires after and can redact or rewrite what the model reads back. Because pi has no MCP layer and no second tool-dispatch path, that pair of events sees everything the agent *does*. It just never sees what the agent's model calls cost, because pi's core loop talks to the model provider directly, outside the extension pipeline both events are wired to.

So adding the extension gets you policy and an audit trail on tool calls — deny, ask, allow, redact — with nothing about spend. Cost needs a second, separate mechanism.

## The config

pi's model calls can route through the ACP proxy the same way any OpenAI-compatible client's can. Add a provider entry in `~/.pi/agent/models.json`:

```json
{
  "providers": {
    "acp": {
      "baseUrl": "https://api.agenticcontrolplane.com/v1",
      "api": "openai-completions",
      "apiKey": "!cat ~/.acp/credentials",
      "compat": { "supportsDeveloperRole": false, "supportsReasoningEffort": false },
      "models": [{ "id": "gemini-3.5-flash" }]
    }
  }
}
```

Then launch pi against it:

```bash
pi --model acp/gemini-3.5-flash
```

The proxy is multi-provider — it routes `gpt-*`, `claude-*`, and `gemini-*` model ids to the matching upstream and forwards the request unchanged. Same response back; the difference is the usage fields on the way through get read and priced, and the call lands as a row joined to the tool-audit rows for the same session, in [the console](https://cloud.agenticcontrolplane.com).

## What you get once it's routed

Once a model in `models.json` points at the proxy, calling pi with `--model acp/...` gives you the same per-call cost picture documented for [turning on the cost X-ray](/cost-tracking) generally:

- **Per-call cost** — tokens in and out, priced to dollars, rolled up per run
- **Prompt-cache hit rate** — so a cold cache doesn't silently double a session's cost before anyone notices
- **The loop-vs-leaf split** — how much of the spend is the agent re-reading its own context to decide the next step, versus doing the work
- **A policy check on the tool calls the model emits** — the proxy sees the `tool_use` blocks in the model's response, which is a second, coarser layer than the extension's own `tool_call` interception, not a replacement for it

None of that shows up if pi is still pointed at its default provider. The extension and the provider entry are independent: you can run the extension alone (policy, no cost), the provider alone (cost, no tool-call policy), or both together, which is the configuration that gets you the full picture in one console.

## Budget limits

Once model traffic is routed through the proxy, **workspace-billed** traffic is subject to your workspace's daily LLM cost cap, enforced at the gateway before the call goes upstream — the session fails rather than runs up a bill past the limit. **Bring-your-own-key** traffic is billed by whichever provider you're calling; ACP meters it but can't cap an account it doesn't hold. Without the provider entry in `models.json`, there's no cap at all, because there's nothing in pi's path to enforce one.

## Troubleshooting

**I added the provider but see nothing in the console.** Check you actually launched with `--model acp/<id>` — adding the provider block to `models.json` doesn't change pi's default model selection, it just makes the option available.

**`apiKey": "!cat ~/.acp/credentials"` fails.** That syntax shells out to read the file at launch; confirm the file exists and holds a workspace key (`gsk_...`), which the install script writes when you sign in. A missing or malformed file means pi can't authenticate the request, not that the proxy is unreachable.

**Tool-call policy rows show up but cost rows don't, or vice versa.** That's expected if only one of the two pieces is installed — the extension and the provider entry are unrelated integrations that happen to write to the same console.

## Frequently asked questions



## Where to read more

- [pi's control model, explained](/controls/pi) — what the extension covers natively, and where its two typed events end
- [Prime Agent cost tracking](/blog/prime-agent-cost-tracking) — the same proxy pattern on pi's hard fork, with its own provider seam
- [Hermes Agent cost tracking](/blog/hermes-cost-tracking) — the in-process hook alternative, for comparison
- [Claude Code cost tracking reference](/blog/claude-code-cost-tracking-reference) and [Codex CLI cost tracking](/blog/codex-cli-cost-tracking) — the sibling references for the other coding agents
