---
title: "Configure your deployment"
description: "Where each Chickpea setting lives, which source wins when two are set, and the switches an operator should know."
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.chickpea.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Configure your deployment

**Configuration** is the deployment-wide set of values an operator controls: credentials, behaviour switches, retention, and outbound network policy. Where an Agent's instructions, connections, and channel grants are per-Agent state a workspace admin edits in Admin, configuration applies to the whole deployment and mostly arrives as environment variables. This page covers where each value can live, which source wins when two are set, how to change one on each target, and the switches worth knowing.

## Where a value can live

Chickpea reads configuration from two places: the deployment's environment, and its own settings store. Some values accept either.

| Setting | Environment variable | Stored in Chickpea |
|---|---|---|
| Model provider API key | `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `OPENROUTER_API_KEY` | **Settings → Model providers** |
| Composio project key | `COMPOSIO_API_KEY` | **Settings → Connectors** |
| GitHub App credentials | `GITHUB_APP_ID`, `GITHUB_APP_PRIVATE_KEY` | **Settings → GitHub** |
| Public origin for Slack links | `SLACK_TAG_PUBLIC_URL` | resolved and saved during setup |
| Ambiguity hint, join welcome | `SLACK_TAG_UNASSIGNED_HINT`, `SLACK_TAG_WELCOME_ON_JOIN` | `slack.behavior.*` settings |
| Outbound access policy | none | **Settings → Outbound access** |
| Slack bot token and signing secret | none at runtime | encrypted credential revision written by setup |

Everything else on this page is environment only.

## The precedence rule

- **An environment value beats a stored value.** Each setting with both homes checks the environment first and reports its source as `env`, then falls back to the settings store and reports `stored`.
- **Admin refuses to overwrite an environment value.** Saving a provider key that the environment already supplies returns `provider_key_read_only`; a behaviour switch the environment already sets returns `slack_setting_read_only` and names the keys. A Composio key from the environment is returned as read only, so Admin can prepare defaults but cannot replace or disable it.
- **A blank Worker variable means unset.** Chickpea's environment helper takes the Worker variable or secret whenever one is bound, so a deliberately blank binding is not overridden by a stale process value. It reads as unset.
- **Two settings have no environment path at all.** Outbound access is stored only, and so are the Slack credentials.

Because the environment wins, moving a value out of the environment and into Admin means removing the variable and restarting, not only saving in the browser.

## On Cloudflare

1. **Add the value**

   Set a secret from a clone of your deployment's repository:

```bash
npx wrangler secret put ANTHROPIC_API_KEY
```

   Set a non-secret label, such as `CHICKPEA_TELEMETRY_ENVIRONMENT`, as a plain variable in the Worker's dashboard settings instead.
2. **Restart the deployment**

   Restart the deployment after changing its environment.

**A button deploy asks for no keys.** `.dev.vars.example` contains only comments because the Deploy to Cloudflare button renders every active key in that file as a required prompt, and provider keys must stay optional. `wrangler.jsonc` carries no `vars` block for the same reason: non-secret defaults live in product code rather than as customer-editable deploy fields.

**Redeploy with the wrapper.** Use `npm run deploy`, or `npm run deploy:sandbox` for the coding sandbox. Bare `wrangler deploy` skips the artifact check, the preserved `AUTH_DB` identity and credential roots, the reviewed migrations, and the readiness check.

## On Node

The built server reads runtime environment variables. It does not load your development `.env` file, so production values belong in a protected environment file the supervisor passes in.

1. **Add the value to the environment file**

   Edit the protected file the service reads, for example `/etc/chickpea/runtime.env` at mode 0600:

```dotenv title="/etc/chickpea/runtime.env"
TAG_RUN_BODY_RETENTION_DAYS=30
CHICKPEA_TELEMETRY_ENVIRONMENT=production
```

   The systemd unit references it with `EnvironmentFile=/etc/chickpea/runtime.env`.
2. **Restart the service**

```bash
sudo systemctl restart <your-chickpea-unit>
```

   The production entry point handles `SIGTERM` and waits for shutdown, with a 60-second internal deadline.

> **Generate the auth secret once and keep the keyring**
>
> Generate `CHICKPEA_AUTH_SECRET` once and preserve it across restarts. Never regenerate it on each start. Preserve the credential keyring at `CHICKPEA_CREDENTIAL_KEYRING_PATH` as well, and back it up with every database: losing encryption keys makes stored credentials unusable.

## Verify

- **Check a provider key's source.** In **Settings → Model providers**, a key supplied by the environment reads `Environment managed`; one saved in the browser reads `Saved in Chickpea`.
- **Check a Slack behaviour switch.** `GET /admin/api/slack-behavior` returns each switch as a value plus a source of `env`, `stored`, or `default`.
- **Check outbound access.** `GET /admin/api/egress` returns the stored policy.

## Slack behaviour switches

Four switches are on by default and turn off only for an explicit false spelling: `false`, `0`, `off`, or `no`, in any case. Any other value, including an unset one, leaves the behaviour on.

| Variable | What turning it off does |
|---|---|
| `SLACK_TAG_UNASSIGNED_HINT` | Silences the private guidance sent when a mention matches more than one Agent. |
| `SLACK_TAG_WELCOME_ON_JOIN` | Suppresses the short welcome when `@Chickpea` joins an already-assigned channel. |
| `SLACK_TAG_PROGRESSIVE_STREAMING` | Stops offering model-selected answer streaming on new Slack turns. |
| `SLACK_TAG_SEMANTIC_ACTIVITY_STATUS` | Stops offering the activity status Chickpea shows while an Agent works. |

The first two also have stored twins, `slack.behavior.unassignedHint` and `slack.behavior.welcomeOnJoin`. Chickpea resolves them in this order: an environment value, then the stored value, then the default of on. While the environment sets one, a write to it returns `slack_setting_read_only` and names that key. The twins have no control in the Admin browser app; they are read and written through `GET` and `PUT /admin/api/slack-behavior` with a body of `{"unassignedHint": false}` or `{"welcomeOnJoin": false}`.

The last two switches are deployment only. They have no stored twin and no Admin control, and `SLACK_TAG_SEMANTIC_ACTIVITY_STATUS` is not listed in `.env.example`.

## The Slack credential exception

`.env.example` and the README's configuration table say an environment value takes precedence for `SLACK_SIGNING_SECRET` and `SLACK_BOT_TOKEN`. The running deployment does not do that. Slack credential resolution is backed by one complete encrypted credential revision, and no runtime source reads those two variables or `SLACK_BOT_USER_ID`; only development and test scripts do. A regression test sets all three to conflicting values and asserts the stored revision still wins.

So changing Slack credentials means running Chickpea's Slack connection flow again, which writes a new encrypted revision. Setting the variables changes nothing, and Admin reports each credential's source as `stored` or `missing`, never `env`. Treat the two lines in `.env.example` and the README as stale.

## Outbound access

Outbound access is the policy that governs the internet access available to the coding sandbox's `curl`. MCP connectors are separate and always work, and private and internal addresses are always blocked. Change it in **Settings → Outbound access**.

| Mode | Effect |
|---|---|
| `allowlist` | Permits only the hosts you list. This is the default, with an empty list. |
| `open` | Permits the whole internet. |
| `off` | Disables outbound access. |

The policy is stored under the `egress.policy` setting. There is no environment variable for it, and an unparseable or malformed stored value falls back to the default allowlist rather than opening access.

## Telemetry and usage

Anonymous, content-free product telemetry is on by default and has a complete opt-out.

| Variable | Default | Purpose |
|---|---|---|
| `DO_NOT_TRACK` | unset | Set to `1`, `true`, or `yes` to disable telemetry completely. |
| `CHICKPEA_DISABLE_TELEMETRY` | unset | The same opt-out, scoped to Chickpea. |
| `CHICKPEA_TELEMETRY_ENVIRONMENT` | `production` on Cloudflare, `development` on Node | Labels events as `production`, `development`, or `test`. |
| `USAGE_RUNTIME_RECORDING` | on | Set to `0` to stop recording runtime usage. |
| `USAGE_ESTIMATES` | on | Set to `0` to stop cost estimates. |
| `USAGE_ADMIN_UI` | on | Set to `0` to hide the Usage section in Admin. |
| `CHICKPEA_INSTALLATION_ID` | `chickpea` | A non-secret accounting label shared by this deployment. |

Opting out of telemetry is total: the composition returns a no-op before reading or creating identity state, reading inventory, generating randomness, starting a timer, or making a network request. Nothing is buffered for later delivery. An unsupported `CHICKPEA_TELEMETRY_ENVIRONMENT` value is labelled `development` rather than entering the production measurement set; when the variable is unset, a `NODE_ENV` of `production`, `development`, or `test` is used before the target default.

The three usage layers are independent, and only `1` and `true` keep one on. Any other value switches that layer off, so use `0`. `CHICKPEA_INSTALLATION_ID` must match `^[A-Za-z0-9][A-Za-z0-9:._/@-]{0,255}$`; anything else falls back to `chickpea`.

## Retention

`TAG_RUN_BODY_RETENTION_DAYS` sets the retention recorded when a canonical run body is written. It takes an integer from 1 through 365 and defaults to 30. A non-integer or out-of-range value fails with `TAG_RUN_BODY_RETENTION_DAYS must be an integer from 1 to 365`.

Changing the value does not rewrite existing expiries; it applies to bodies written after the change. A Chickpea purge does not delete Flue transcripts, which follow the transcript database at `TAG_DB_PATH` on Node.

## Advanced switches

Two switches exist for incident response and staged rollout. Neither changes work that has already been admitted, and neither tells you anything about the state of the other.

- **`CHICKPEA_LIVE_CHANNEL_CONFIG`** is on by default, so channel events resolve current Agent and channel configuration. Setting `0`, `false`, or `off` restores write-once thread snapshots for new channel admissions. It is an emergency rollback; unset it and redeploy once the incident is understood.
- **`SLACK_TAG_LEDGER_CANARY_CHANNELS`** is empty by default and takes at most 20 comma-separated `workspace/channel` pairs, such as `T123/C456`. Agents with connections or repositories, and deployments whose outbound access is `open` or a non-empty allowlist, stay on the established lane regardless. Read `docs/runbooks/agent-runtime-rollout.md` in the product repository before setting it.

## Next steps

- [Deploy and operate](/operate): the Cloudflare and Node procedures these values apply to.
- [Environment variables](/reference/environment-variables): the complete variable list, with when each is required and what it defaults to.
- [Security model](/security/security-model): what the outbound access policy and credential handling actually guarantee.
- [A tour of Admin](/admin/tour): the browser app where stored settings live.

Source: https://docs.chickpea.co/operate/configuration/index.mdx
