# Configuration

All keys are optional. Layered: `~/.pi/agent/pinata.json`, then `<repo>/.pi/pinata.json`,
then the run's `config`. `models`, `fallbacks`, `limits` and `toolProviders` merge per entry; other keys
replace. Unknown keys are rejected.

| Key                  | Default and meaning                                                                                     |
| -------------------- | ------------------------------------------------------------------------------------------------------- |
| `models`             | `{default?, [agentName]?}`, each `{provider, id, thinking}`                                             |
| `fallbacks`          | `{agentName: [model, …]}`, at most 5, used when the preferred model is unknown or has no authentication |
| `limits`             | See below                                                                                               |
| `mode`               | `lean`; or `observe` (see [modes](../how-to/modes.md))                                                  |
| `backend`            | `in-process`; or `process`, `herdr-pi` (see [backends](../how-to/backends.md))                          |
| `codemode`           | `true`: agents get Pi's `codemode` tool                                                                 |
| `setup`              | Builders' setup: detected from root lockfiles; a command string to override; `false` for none           |
| `worktreeRoot`       | External directory for new worktrees; defaults to the platform's user data directory (see below)        |
| `includeUncommitted` | `true`: builders start from the checkout with uncommitted changes; `false` starts them from `HEAD`      |
| `webExtension`       | pi-web-access's entry file, detected from this Pi                                                       |
| `toolProviders`      | Named `{extension, tools}` records for custom agent tools; only required providers load                 |
| `passEnv`            | Extra environment variable names for agents' checks and setup (never values)                            |

For example, put this in `.pi/pinata.json` to limit each run in this repository
to four agents at once and skip dependency setup for a project that needs none:

```json
{ "limits": { "concurrency": 4 }, "setup": false }
```

Use the same object inside `pinata_run`’s `config` for one run. Task ownership and
checks do not belong here: `ownership`, `checks`, and `evidenceChecks` belong on
tasks; `integratedChecks` belongs on the run.

## Models

`thinking` is `off`, `minimal`, `low`, `medium`, `high`, `xhigh` or `max`. A task uses the
first of `task.model`, `models[agent]`, the definition model, `models.default` and this Pi's current model; if that
model is unknown or has no configured authentication, `fallbacks[agent]` (or definition fallbacks) in order.
`models` and `fallbacks` accept any installed agent name. See [creating agents](../how-to/agents.md)
for definition defaults and tool providers.

## Limits

| Key            | Default                          | Maximum  |
| -------------- | -------------------------------- | -------- |
| `concurrency`  | 16 agents at once per run        | 64       |
| `taskMs`       | 1200000 (20 minutes per agent)   | 86400000 |
| `jobMs`        | 5400000 (90 minutes per run)     | 86400000 |
| `repairs`      | 2 per task                       | 10       |
| `maxTurns`     | 60 per agent                     | 1000     |
| `maxToolCalls` | 400 per agent                    | 10000    |
| `costUsd`      | none: a dollar limit for the run | 10000    |

An agent over its turns, tool calls or wall clock fails with the reason. When the run's
cost passes `costUsd`, the run is cancelled; the agent that crossed it fails with "cost
limit reached". Providers' rate limits are handled adaptively (each provider starts at 8
agents at once, halves on a 429 and recovers).

## Worktree location

New builder and pull-request review worktrees live at
`<worktreeRoot>/<repository-id>/<run-id>/<task>/`. The repository ID is derived from
the canonical Git common directory, so linked checkouts share an identity. Run
metadata, logs, and the dependency cache remain under `<git common dir>/pinata/`.

Default roots:

| Platform             | Default                                                                                        |
| -------------------- | ---------------------------------------------------------------------------------------------- |
| Linux and other Unix | `$XDG_DATA_HOME/pinata/worktrees`, or `~/.local/share/pinata/worktrees` when unset or relative |
| macOS                | `~/Library/Application Support/pinata/worktrees`                                               |
| Windows              | `%LOCALAPPDATA%\pinata\worktrees`, or `~\AppData\Local\pinata\worktrees`                       |

Override the location globally in `~/.pi/agent/pinata.json`, in the project's
`.pi/pinata.json`, or in a run's `config`:

```json
{
  "worktreeRoot": "~/worktrees/pinata"
}
```

Absolute paths, `~/` paths, and paths relative to the initiating repository root
(such as `../pinata-worktrees`) are supported. The resolved root must be outside
the repository's registered checkouts and Git metadata, including through symlinks.
This keeps tools such as Vite from rejecting working files under `.git`.

Each run saves its absolute worktree paths in `run.json`. Changing the setting
affects new runs only; resume, repair, and review reuse the saved locations. Runs
created before this setting retain their original `<run>/worktrees/` paths and are
not moved automatically. Start a new run to use the external layout for those jobs.
Worktrees remain available after a run for review and recovery. To remove one when
it is no longer needed, use `git worktree remove <path>` from the repository after
preserving any wanted changes; deleting run logs alone does not remove its worktrees.

## Setup

| `setup`  | Result                                                       |
| -------- | ------------------------------------------------------------ |
| omitted  | Detect from root lockfiles in the run's starting checkout    |
| a string | Run that command (`sh -c`, or `cmd.exe /d /s /c` on Windows) |
| `false`  | Run nothing                                                  |

Detection picks one command per ecosystem and joins them with `&&`:

| Root lockfile                              | Command                                           |
| ------------------------------------------ | ------------------------------------------------- |
| `pnpm-lock.yaml`                           | `pnpm install --frozen-lockfile --prefer-offline` |
| `bun.lock`, `bun.lockb`                    | `bun install --frozen-lockfile`                   |
| `yarn.lock` with `.yarnrc.yml`             | `yarn install --immutable`                        |
| `yarn.lock`                                | `yarn install --frozen-lockfile`                  |
| `package-lock.json`, `npm-shrinkwrap.json` | `npm ci --prefer-offline --no-audit --no-fund`    |
| `uv.lock`                                  | `uv sync --frozen`                                |
| `poetry.lock`                              | `poetry install --no-interaction`                 |
| `Pipfile.lock`                             | `pipenv sync`                                     |

Setup gets the agents' environment plus `PINATA_ROOT` (your checkout). See
[dependencies](../how-to/dependencies.md).

## Environment

Agents' checks and setup inherit an allowlist (path, home, user, shell, locale, temp
directories and, on Windows, the system variables), plus `passEnv` names and
`PINATA_AGENT=1`. `passEnv` entries match `^[A-Z][A-Z0-9_]*$` and may not start with
`PINATA_` or `HERDR_`.

## Ignored keys

`pi`, `herdr`, `session`, `workspaceReuse`, and `limits.startupMs` have no effect.
Pinata ignores them and prints a notice.
