---
url: /bupha/reference/config.md
---
# Config — `bupha.toml`

## Top level

| field | type | required | notes |
|---|---|---|---|
| `repos` | `Vec<RepoEntry>` | required | Watched repos — one pending slot each, one global worker. TOML-conventional singular; `repos` kept as alias for existing configs. |
| `tunnel` | `TunnelCfg` | optional | How the listener is exposed publicly (cloudflared, direct, none). |
| `cache` | `CacheCfg` | optional | Artifact cache backend (`[cache]`); `runner.sccache_conf` is accepted for older configs — `[cache]` wins. |
| `access` | `AccessCfg` | optional | Who may trigger (`[access]`). Absent = open. |
| `telemetry` | `TelemetryCfg` | optional | Pipeline observability (`[telemetry]`). Absent = none. |
| `attest` | `AttestCfg` | optional | Run provenance (`[attest]`). Absent = none. |
| `queue` | `QueueCfg` | optional | Queue persistence backend (`[queue]`). Absent = redb. |
| `worktree` | `WorktreeCfg` | optional | Where detached git worktrees for runs are created. |

## `[[repo]]`

| field | type | required | notes |
|---|---|---|---|
| `name` | `string` | required | repository.full_name in the webhook payload ("owner/name") — also the status target repo. |
| `dir` | `path` | required | Clone to fetch + create detached worktrees from. |
| `branch` | `string` | optional | The ref to watch (e.g. "refs/heads/main"). |
| `status_repo` | `string` | optional | Status repo override (defaults to `name`). |
| `runner` | `RunnerCfg` | optional | Per-repo runner override — a full \[repo.runner] table replaces the global `[runner]` for this repo. |
| `queue` | `"latest" | "all"` | optional | Queue policy — `latest` (default) or `all` (run every push). |

## `[trigger]`

| field | type | required | notes |
|---|---|---|---|
| `api_base` | `string` | optional | Forge API base — GHES ("https://ghe.acme/api/v3") or default github.com. Used by the trigger, status, and forge-admin impls. |
| `kind` | `string` | required | "github" today; other forges = new impl crates. |
| `listen` | `string` | optional | Webhook listener bind address ("127.0.0.1:9000"). |
| `secret_env` | `string` | optional | Env var holding the webhook secret. |

## `[runner]`

| field | type | required | notes |
|---|---|---|---|
| `kind` | `string` | required | Runner kind: "dagger" | "shell" | "ssh" | impl crates. |
| `token_env` | `string` | optional | Env var name holding the forge token (never the value). |
| `cancel_running` | `bool` | optional | Kill an in-flight run when a newer push supersedes it. Invalid with `queue = "all"` (rejected at load). |
| `extra` | `toml::Table` | required | Impl-owned fields — the matched impl crate deserializes its own config struct from this; core knows none of them. |

## `[status]`

| field | type | required | notes |
|---|---|---|---|
| `kind` | `string` | optional | "github" | "log" (stdout only) | "none". |
| `repo` | `string` | optional | owner/repo for the commit-status API. |
| `context` | `string` | optional | Status context label (e.g. "ci/bupha"). |

## `[tunnel]`

| field | type | required | notes |
|---|---|---|---|
| `provider` | `string` | optional | "none" | "cloudflared" | "direct". |
| `name` | `string` | optional | Named tunnel (stable URL); empty = quick tunnel. |
| `local_url` | `string` | optional | Local URL the tunnel forwards to (listener address). |
| `public_url` | `string` | optional | provider=direct: the external URL GitHub should hit. |

## `[cache]`

| field | type | required | notes |
|---|---|---|---|
| `kind` | `string` | optional | Backend id ("sccache"; "none"/empty disables). |
| `conf` | `string` | optional | Backend conf value (sccache: "file:///dir", "s3://bucket/…"). |

## `[worktree]`

| field | type | required | notes |
|---|---|---|---|
| `base` | `string` | optional | Worktree parent dir — runs land at `&lt;base&gt;-&lt;repo&gt;-&lt;sha12&gt;`. |

## `[runner]` — kind `dagger`

| field | type | required | notes |
|---|---|---|---|
| `function` | `string` | optional | — |
| `shards` | `string` | optional | — |
| `jobs` | `string` | optional | — |
| `dogfood_jobs` | `string` | optional | — |
| `sequential` | `bool` | optional | — |
| `sccache_conf` | `string` | optional | sccache conf passed as `--sccache-conf` (resolved from `[cache]` by the composition root). |
| `cli_source` | `string` | optional | — |
| `extra_args` | `list` | optional | — |

## `[runner]` — kind `shell`

| field | type | required | notes |
|---|---|---|---|
| `cmd` | `string` | optional | — |

## `[runner]` — kind `ssh`

| field | type | required | notes |
|---|---|---|---|
| `remote` | `string` | optional | Remote host ("user@host"; ssh config resolves auth). |
| `remote_dir` | `string` | optional | Remote workdir the worktree syncs into. |
| `cmd` | `string` | optional | Command run remotely (`bash -c`). |

## `[runner]` — kind `container`

| field | type | required | notes |
|---|---|---|---|
| `image` | `string` | required | Image the pipeline runs in (required). |
| `cmd` | `string` | optional | Shell command executed inside the container. |
| `engine` | `string` | optional | Engine binary — `"podman"` (default) or `"docker"`. |
| `network` | `string` | optional | Network mode — `"none"` default (isolated); `"host"`/`"bridge"` for pipelines that genuinely need outbound. |

## Constraints

* `queue = "all"` rejects `cancel_running = true` at load —
  killing a run would silently drop a promised commit.
* `runner.kind` and `trigger.kind`/`status.kind` resolve to impl
  crates; unknown kinds fail at `bupha doctor`/startup.
* `deny_unknown_fields`: typos in field names fail the load.
