# Environment Variables

Every AI config option has an environment variable override with the `AI_CHAT_` prefix.

## Reference

| Variable | Default | Description |
|---|---|---|
| `AI_CHAT_BASE_URL` | --- | AI API endpoint (required) |
| `AI_CHAT_API_KEY` | --- | API key (required) |
| `AI_CHAT_MODEL` | `gpt-4` | Model name |
| `AI_CHAT_SYSTEM_PROMPT` | `You are a helpful assistant.` | System prompt |
| `AI_CHAT_VERIFY_SSL` | `true` | SSL certificate verification |
| `AI_CHAT_REQUEST_TIMEOUT` | `120` | Overall stream timeout in seconds (clamped 10–600) |
| `AI_CHAT_CONNECT_TIMEOUT` | `5` | TCP connect timeout in seconds (clamped 1–30) |
| `AI_CHAT_FIRST_TOKEN_TIMEOUT` | `30` | Max seconds to wait for first token after connect (clamped 5–120) |
| `AI_CHAT_RETRY_MAX_ATTEMPTS` | `3` | Retries on transient errors; 0 disables (clamped 0–10) |
| `AI_CHAT_RETRY_BACKOFF_BASE` | `1.0` | Exponential backoff base delay in seconds (clamped 0.1–30.0) |
| `AI_CHAT_TEMPERATURE` | --- | Model temperature for response randomness (0.0–2.0) |
| `AI_CHAT_TOP_P` | --- | Nucleus sampling parameter (0.0–1.0) |
| `AI_CHAT_SEED` | --- | Random seed for deterministic output (integer) |
| `AI_CHAT_PORT` | `8080` | Port for the web server |
| `AI_CHAT_USER_ID` | --- | Override user identity UUID |
| `AI_CHAT_DISPLAY_NAME` | --- | Override user display name |
| `AI_CHAT_PUBLIC_KEY` | --- | Override user public key (PEM) |
| `AI_CHAT_PRIVATE_KEY` | --- | Override user private key (PEM) |
| `AI_CHAT_SAFETY_ENABLED` | `true` | Enable/disable the tool safety gate |
| `AI_CHAT_SAFETY_APPROVAL_MODE` | `ask_for_writes` | Approval mode: `auto`, `ask_for_dangerous`, `ask_for_writes`, `ask` |
| `AI_CHAT_LOG_LEVEL` | `WARNING` | Log level: `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`. Overridden by `--debug` flag |
| `AI_CHAT_TEAM_CONFIG` | --- | Path to team configuration file (YAML). See [Team Config](../configuration/team-config.md) |
| `AI_CHAT_BACKGROUND_SUGGEST_SECONDS` | `30` | Advisory threshold for background shell tasks (0 = disabled) |
| `AI_CHAT_DETACH_SUGGEST_SECONDS` | `120` | Advisory threshold for detached subagents (0 = disabled) |
| `AI_CHAT_COMPACT_PRESERVE_TAIL` | `6` | Recent messages preserved intact during boundary-based compaction; `0` reverts to full-summary; clamped to `[0, 200]` |
| `AI_CHAT_COMPACT_REHYDRATE` | `true` | Append a bounded `<session_state>` block to compaction summaries (#1414) |
| `AI_CHAT_COMPACT_REHYDRATE_MAX_FILES` | `20` | Max file paths preserved per category (read/written/edited) in the `<session_state>` block; clamped to `[0, 200]` |
| `AI_CHAT_COMPACT_REHYDRATE_MAX_ERRORS` | `5` | Max unresolved tool errors preserved in the `<session_state>` block; clamped to `[0, 50]` |
| `AI_CHAT_MICROCOMPACT_ENABLED` | `true` | Enable the proactive microcompact stage (#1266). When `false`, the agent loop skips the per-turn in-memory sweep |
| `AI_CHAT_SUMMARY_TRIGGER_MSG_COUNT` | `80` | Message-count threshold for proactive summary compaction; clamped to `[10, 1000]` |
| `AI_CHAT_SUMMARY_TRIGGER_TOKEN_COUNT` | `90000` | Estimated-token threshold for proactive summary compaction; clamped to `[5000, 500000]` |
| `AI_CHAT_REACTIVE_MAX_ATTEMPTS` | `4` | Max retries after a `context_length_exceeded` error; clamped to `[0, 10]` (`0` disables reactive recovery) |
| `AI_CHAT_MEMORY_PROMOTION_DEFAULT_REVIEW_STATE` | `candidate` | Landing status for new candidates: `candidate` or `pending_review` |
| `AI_CHAT_MEMORY_PROMOTION_LOCAL_AUTO_APPROVE` | `false` | When true, proposals skip review and land in `active` with an `auto_approved` lineage entry |
| `AI_CHAT_MEMORY_PROMOTION_AGENT_PROPOSALS_ENABLED` | `true` | When false, proposer=`agent` is rejected with HTTP 403 |
| `AI_CHAT_MEMORY_PROMOTION_MAX_LINEAGE_ENTRIES` | `50` | FIFO cap on decision-history entries per memory |
| `AI_CHAT_MEMORY_PROMOTION_MAX_CANDIDATES_PER_CONVERSATION` | `10` | Per-conversation proposal cap; overflow returns HTTP 429 with cap / current / retry_hint |
| `AI_CHAT_MEMORY_PROMOTION_MAX_REJECT_REASON_CHARS` | `500` | Server-side bound on rejection reason; router also enforces Pydantic `max_length=2000` |
| `AI_CHAT_MEMORY_RETENTION_ENABLED` | `false` | Master switch for memory-artifact eviction. When false the retention worker touches zero memories regardless of other fields |
| `AI_CHAT_MEMORY_RETENTION_MAX_AGE_DAYS` | _(unset)_ | Purge memories older than N days (by `created_at`). Unset or `0` disables the rule |
| `AI_CHAT_MEMORY_RETENTION_IDLE_DAYS` | _(unset)_ | Purge memories not recalled in N days (by `metadata.last_recalled_at`, falling back to `created_at`). Unset or `0` disables |
| `AI_CHAT_MEMORY_RETENTION_MIN_AGE_DAYS` | `1` | Grace floor against `idle_days`; memories younger than this survive the idle rule |
| `AI_CHAT_MEMORY_RETENTION_PURGE_STATUSES` | `rejected` | Comma-separated list of statuses eligible for status-based eviction. Invalid statuses are filtered out |
| `AI_CHAT_MEMORY_RETENTION_RESPECT_PINS` | `true` | When true, memories with `metadata.pinned == true` are always skipped. Set to `false` as an explicit escape hatch |
| `AI_CHAT_MEMORY_AUTO_PROPOSE_ENABLED` | `false` | Master switch for selective post-turn extraction (#1454). Off by default; opt-in to surface candidate memories from assistant turns |
| `AI_CHAT_MEMORY_AUTO_PROPOSE_MAX_CANDIDATES_PER_TURN` | `1` | Hard cap on proposals per final assistant turn. Clamped to `>=1` |
| `AI_CHAT_MEMORY_AUTO_PROPOSE_CATEGORIES` | `preference,project_fact,decision,workflow_hint` | Comma-separated subset of `MEMORY_CATEGORIES` the extractor may propose. Invalid entries are dropped at load time |
| `AI_CHAT_MEMORY_AUTO_PROPOSE_MIN_CONFIDENCE` | `0.8` | LLM-reported confidence floor (0.0-1.0). Clamped into range |
| `AI_CHAT_MEMORY_AUTO_PROPOSE_NOTIFY_INLINE` | `true` | When true, CLI prints a one-line notice and the web UI renders an inline banner after a turn that produced candidates |
| `AI_CHAT_MEMORY_AUTO_PROPOSE_COOLDOWN_TURNS` | `5` | Per-conversation suppression window (in turns) for repeats of the same content. Stacks with the per-conversation cap from `MEMORY_PROMOTION_MAX_CANDIDATES_PER_CONVERSATION` |
| `AI_CHAT_SHOW_ATTRIBUTION_FOOTER` | `true` | CLI `[ctx] …` footer after each assistant turn. Set to `false`/`0`/`no` to suppress. The full snapshot is persisted regardless; `/attribution` continues to work. See [Context Attribution](../knowledge/attribution.md) |

## Usage

Environment variables override config file values. This is useful for:

- CI/CD environments where you can't write config files
- Switching between API endpoints without editing config
- Keeping secrets out of config files

```bash
$ export AI_CHAT_BASE_URL="https://api.openai.com/v1"
$ export AI_CHAT_API_KEY="sk-..."
$ export AI_CHAT_MODEL="gpt-4-turbo"
$ aroom chat
```

## Precedence

Configuration is resolved in this order (highest wins):

1. Defaults (lowest)
2. Team config file (if present)
3. Personal config file (`~/.anteroom/config.yaml`)
4. Environment variables
5. CLI flags (highest)

**Exception**: Fields listed in the team config's `enforce` section override all other sources, including environment variables and CLI flags. See [Team Config](../configuration/team-config.md).
