# Pi

Pi is a terminal coding agent. It uses the OpenAI Chat Completions format.

Pi has no setting for a custom base URL. Each provider and each of its models must be in `~/.pi/agent/models.json`. The block below reads the live model list and adds the exchange as a provider.

## Start with the Liquid CLI

The [Liquid CLI](https://inference.ai.exchange/docs/cli.md) can start Pi with the exchange as its provider. Pi keeps its settings in a file, so set it up one time with the steps below. `liquid connect pi` prints the same setup with your model filled in. Then start Pi with `liquid pi`.

```bash
curl -fsSL https://inference.ai.exchange/cli/install.sh | bash
liquid login
liquid connect pi
liquid pi
```

## Before you start

- A workspace with a balance and a `spend` key. See [API keys](https://inference.ai.exchange/docs/keys.md).
- Node.js 22.19 or newer, and `jq`.
- Pi installed. The package is `@earendil-works/pi-coding-agent`:

```bash
# installer
curl -fsSL https://pi.dev/install.sh | sh

# or with npm
npm install -g --ignore-scripts @earendil-works/pi-coding-agent
```

## 1. Write the provider

Pi does not read `/v1/models`. It asks for 16,384 output tokens if a model does not set `maxTokens`. Some offers register a lower limit. This block:

- Reads the text models of the book. Pi sends each model to the chat endpoint, so it cannot use an image, speech or video model.
- Keeps the other providers in the file.
- Writes `contextWindow`, `maxTokens`, `reasoning` and `input` from each model.

`apiKey` is the literal `$LIQUID_API_KEY`, which Pi expands at run time. The block sends the key on the models request, so the list includes your presets.

```bash
export LIQUID_API_KEY=sk-liquid-...
mkdir -p ~/.pi/agent && touch ~/.pi/agent/models.json
curl -fsSL "https://router.inference.ai.exchange/v1/models?kind=text" -H "Authorization: Bearer $LIQUID_API_KEY" | jq --slurpfile cur ~/.pi/agent/models.json '
  .data as $book | ($cur[0] // {}) | .providers.liquid = {
    baseUrl: "https://router.inference.ai.exchange/v1",
    api: "openai-completions",
    apiKey: "$LIQUID_API_KEY",
    headers: { "x-liquid-cap-usd": "1.00" },
    models: [$book[] | (.liquid_supported_parameters // []) as $p | {
      id,
      contextWindow: (.max_input_tokens // 128000),
      maxTokens: (.max_tokens // 16384),
      reasoning: ($p | index("reasoning.effort") != null),
      input: (if ($p | index("input.image")) then ["text", "image"] else ["text"] end)
    }]
  }' > ~/.pi/agent/models.json.new && mv ~/.pi/agent/models.json.new ~/.pi/agent/models.json
```

It writes one provider, `liquid`, with a `baseUrl` that ends in `/v1` and `api` set to `openai-completions`. Run the block again when the book changes. It replaces only that provider.

## 2. Run it

```bash
pi --model liquid/liquid.auto
```

## Choosing a model

Step 2 starts Pi on `liquid/liquid.auto`. In a session, `/model` changes the model. To set the reasoning effort for one launch, add it to the end of the id:

```bash
pi --model liquid/liquid.auto:high
```

`off` sends no effort. Pi sends `xhigh` as `high`.

To make a model the default, set `defaultProvider` to `liquid` and `defaultModel` to the model id in `~/.pi/agent/settings.json`.

To get the current names, see the **Market** page or use `GET /v1/models`. See [Market data](https://inference.ai.exchange/docs/market.md). The exchange refuses a name that is not on the book. It never uses another model.

## Control the cost

The provider sends `x-liquid-cap-usd` on each request, including `liquid.auto`. To change it, edit the header in `providers.liquid.headers` in `~/.pi/agent/models.json`. The cap applies to each request, not the session. The provider step resets this value each time you run it.

The exchange fixes the cap before the first token and returns it in the `x-liquid-cap-usd` response header. To limit the total spend, set a spending limit on the key. See [API keys](https://inference.ai.exchange/docs/keys.md) and [Purchasing rules](https://inference.ai.exchange/docs/rules.md).

## Troubleshooting

| Symptom                    | Cause and fix                                                                                                                      |
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| The model is not listed.   | The book changed after the file was written. Run the block again.                                                                  |
| `401`                      | `apiKey` in `models.json` must stay `$LIQUID_API_KEY`, including the `$`. A name without the `$` is sent as that literal string.   |
| `output_bound_unsupported` | `maxTokens` is higher than the offer allows. Run the block again so each model takes its limit from the book.                      |
| `jq` reports a parse error | `models.json` contains comments, which JSON does not allow. Edit the `liquid` provider by hand, or remove the comments and re-run. |

## Next steps

- [Codex](https://inference.ai.exchange/docs/connect-codex.md): the same idea for OpenAI's terminal agent.
- [API keys](https://inference.ai.exchange/docs/keys.md): scopes and spending limits.
- [Purchasing rules](https://inference.ai.exchange/docs/rules.md): cost caps and service floors.
