# 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_SERVER_MAX_UPLOAD_MB` | `50` | Maximum request body size in MB (clamped to `[1, 1000]`) |
| `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. `DEBUG` also enables correlated, redacted CLI per-turn debug diagnostics |
| `AI_CHAT_TEAM_CONFIG` | --- | Path to team configuration file (YAML). See [Team Config](../configuration/team-config.md) |
| `AI_CHAT_MODEL_CONTEXT_WINDOW` | `128000` | Model context window size for context meter and model-aware thresholds; clamped to `[1000, 2000000]` |
| `AI_CHAT_CONTEXT_RESERVED_OUTPUT_TOKENS` | `AI_CHAT_MAX_OUTPUT_TOKENS` | Output headroom reserved before deriving context thresholds. Clamped to leave at least 1000 effective context tokens |
| `AI_CHAT_CONTEXT_WARN_BUFFER_TOKENS` | `43904` | Free-token buffer for the derived context warning threshold. The default resolves to `80000` for a 128k window with 4096 reserved output tokens |
| `AI_CHAT_CONTEXT_AUTO_COMPACT_BUFFER_TOKENS` | `23904` | Free-token buffer for the derived CLI auto-compact threshold. The default resolves to `100000` for a 128k window with 4096 reserved output tokens |
| `AI_CHAT_CONTEXT_WARN_TOKENS` | derived | Explicit context warning threshold for CLI and web metadata. Overrides the model-aware derived value |
| `AI_CHAT_CONTEXT_AUTO_COMPACT_TOKENS` | derived | Explicit CLI auto-compact threshold. Overrides the model-aware derived value |
| `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_UPDATE_CHECK` | `true` | Check for newer Anteroom versions on CLI startup. Set to `false`/`0`/`no` to disable the automatic startup check entirely; manual `aroom version check` still runs when invoked |
| `AI_CHAT_UPDATE_CHECK_COMMAND` | --- | Trusted shell command that prints the latest Anteroom version to stdout. Replaces the default `pip index versions anteroom` checker for startup and manual checks |
| `AI_CHAT_UPDATE_CHECK_MESSAGE` | `Update available: {current} -> {latest} -- pip install --upgrade anteroom` | Startup update notification template. Supports `{current}`, `{latest}`, and `{upgrade_command}`; empty string suppresses the startup notification without disabling manual checks |
| `ANTEROOM_PROJECT_PROFILE` | `public` | Project-link profile for CLI/docs/unpack rendering. Use `neutral` for no built-in public repo URLs, or a custom profile name |
| `ANTEROOM_PROJECT_PROFILE_PATH` | --- | Explicit YAML profile file to load before config/env overrides |
| `ANTEROOM_PROJECT_NAME` | `Anteroom` | Project display name override |
| `ANTEROOM_PROJECT_REPO_LABEL` | profile value | Repository display label override |
| `ANTEROOM_PROJECT_REPO_URL` | profile value | Repository URL override for GitHub, GitLab, Bitbucket, or an internal forge |
| `ANTEROOM_PROJECT_DOCS_URL` | profile value | Published docs URL override |
| `ANTEROOM_PROJECT_SUPPORT_URL` | --- | Support/contact URL override |
| `ANTEROOM_PROJECT_RELEASE_URL_TEMPLATE` | profile value | Release URL template override using `{version}` |
| `ANTEROOM_PROJECT_ISSUE_TRACKING_ENABLED` | profile value | Set `false`/`0`/`no` to render issue references without URLs |
| `ANTEROOM_PROJECT_ISSUE_LABEL_TEMPLATE` | `#{number}` | Issue label template override using `{number}` |
| `ANTEROOM_PROJECT_ISSUE_URL_TEMPLATE` | profile value | Issue URL template override using `{number}` |
| `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_HISTORICAL_TOOL_COLLAPSE_ENABLED` | `true` | Enable proactive historical tool-result collapse under token pressure. In-memory only; never persists collapsed tool results |
| `AI_CHAT_HISTORICAL_TOOL_COLLAPSE_TRIGGER_TOKEN_COUNT` | `80000` | Estimated-token threshold for proactive historical tool-result collapse; clamped to `[5000, 500000]` |
| `AI_CHAT_HISTORICAL_TOOL_COLLAPSE_KEEP_RECENT_GROUPS` | `6` | Recent turn groups preserved verbatim by proactive historical tool-result collapse; clamped to `[0, 200]` |
| `AI_CHAT_HISTORICAL_TOOL_COLLAPSE_COMPACT_CHARS` | `1000` | Character budget for each proactively collapsed historical tool result; clamped to `[50, 50000]` |
| `AI_CHAT_SUMMARY_TRIGGER_MSG_COUNT` | `80` | Message-count threshold for proactive summary compaction; fires independently from the token threshold; clamped to `[10, 1000]` |
| `AI_CHAT_SUMMARY_TRIGGER_TOKEN_COUNT` | derived | Explicit estimated-token threshold for proactive summary compaction; overrides the model-aware derived value and is clamped to `[5000, 500000]` |
| `AI_CHAT_SUMMARY_TRIGGER_BUFFER_TOKENS` | `33904` | Free-token buffer for the derived proactive summary threshold. The default resolves to `90000` for a 128k window with 4096 reserved output tokens |
| `AI_CHAT_REACTIVE_MAX_ATTEMPTS` | `4` | Max retries after a `context_length_exceeded` error; clamped to `[0, 10]` (`0` disables reactive recovery) |
| `AI_CHAT_COMPACT_SUMMARY_MAX_TOKENS` | `1000` | Maximum output budget for LLM compaction summaries; scaled by conversation size and clamped to `[256, 16000]` |
| `AI_CHAT_COMPACT_SUMMARY_RETRY_MAX_ATTEMPTS` | `3` | Total attempts for prompt-too-long compaction-summary recovery; clamped to `[1, 10]` |
| `AI_CHAT_COMPACT_SUMMARY_RETRY_DROP_GROUPS` | `2` | Oldest safe turn groups dropped before each summary retry; clamped to `[1, 50]` |
| `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 explicitly true, proposals skip review and land in `active` with an `auto_approved` lineage entry. The environment fallback stays review-first; solo local setup may write the config value to `true`. |
| `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) |
| `AI_CHAT_CLI_HIERARCHY_SHOW_TIMESTAMPS` | `false` | Right-align a subtle per-turn timestamp on the user and assistant lanes. See [CLI Themes](../cli/themes.md) |
| `AI_CHAT_CLI_HIERARCHY_TURN_SEPARATOR_CHAR` | `─` | Single visible character used by `render_turn_separator()` between turns. See [CLI Themes](../cli/themes.md) |
| `AI_CHAT_CLI_HIERARCHY_CODE_BLOCK_LANGUAGE_LABEL` | `true` | Emit a small language label above fenced code blocks. Set to `false`/`0`/`no` for a quieter layout. See [CLI Themes](../cli/themes.md) |
| `AI_CHAT_CLI_STREAMING_ENABLED` | `false` | Master toggle for live markdown streaming (#1365). Set to `true`/`1`/`yes` to enable incremental markdown rendering as tokens arrive. Auto-disabled in non-TTY, `NO_COLOR`, and exec-mode contexts regardless of value. See [CLI Streaming](../cli/index.md#streaming-rendering) |
| `AI_CHAT_CLI_STREAMING_REFRESH_HZ` | `20.0` | Live-region refresh rate in Hz. Clamped to `[1.0, 60.0]` with a logger warning on out-of-range values. `20.0` = 50 ms per tick |
| `AI_CHAT_CLI_STREAMING_LIVE_IN_EXEC_MODE` | `false` | When `true`/`1`/`yes`, also activate Live rendering in `aroom exec` mode. Default `false` preserves the static-render-at-end contract for scripting and CI capture |
| `AI_CHAT_CLI_STREAMING_CODE_FENCE_CONTAINER` | `true` | When `true`, render a visible fenced-code container as soon as the opening ``` arrives. Set to `false`/`0`/`no` to defer container rendering until the closing fence |
| `AI_CHAT_CLI_LIVE_TOOLS_SHOW_ARGS_IN_VERBOSE` | `true` | In VERBOSE verbosity, emit a muted `args: {...}` footline under each tool-call completion line. Set to `false`/`0`/`no` to suppress (#1364) |
| `AI_CHAT_CLI_LIVE_TOOLS_SHOW_METRIC_SUFFIX` | `true` | Append a compact metric suffix (lines, bytes, exit code, match count) on tool-call completion lines. Set to `false`/`0`/`no` for a quieter line |
| `AI_CHAT_CLI_LIVE_TOOLS_METRIC_MAX_CHARS` | `40` | Upper bound on the metric suffix before truncation. Clamped to `[1, 200]` with a logger warning on out-of-range values |
| `AI_CHAT_CLI_DENSITY_MODE` | `normal` | Tool-result density (#1367). One of `minimal`, `compact`, `normal`, `detailed`. Default `normal` is byte-identical to pre-#1367 rendering. Invalid values warn and fall back to `normal`. See [CLI Commands](../cli/commands.md#tool-result-density) |
| `AI_CHAT_CLI_DENSITY_COLLAPSE_REPEATS` | `true` | When density is `compact` or `minimal`, collapse ≥3 identical-shape tool results into one line. Set to `false`/`0`/`no` to always show each result. No effect when mode is `normal` |
| `AI_CHAT_CLI_DENSITY_DIFF_CONTEXT_LINES` | `3` | In compact/minimal modes, lines of unchanged context preserved around each diff change. Longer runs collapse to a `[N unchanged lines]` marker |
| `AI_CHAT_CLI_DENSITY_HEAD_LINES` | `3` | Leading lines kept when trimming long tool output in compact/detailed modes |
| `AI_CHAT_CLI_DENSITY_TAIL_LINES` | `2` | Trailing lines kept when trimming long tool output in compact/detailed modes |
| `AI_CHAT_FEEDBACK_INCLUDE_HISTORY` | `false` | Default history opt-in for feedback bundles. Leave `false` unless users understand feedback reports may include conversation content |
| `AI_CHAT_FEEDBACK_MAX_HISTORY_MESSAGES` | `10` | Max recent conversation messages included when feedback history is explicitly enabled. Clamped to `[1, 50]` |
| `AI_CHAT_FEEDBACK_RETRY_ATTEMPTS` | `2` | Total synchronous reporter attempts before a feedback report is marked failed. Clamped to `[1, 5]` |
| `AI_CHAT_FEEDBACK_RETRY_BACKOFF_SECONDS` | `1.0` | Seconds to wait between feedback reporter attempts. Clamped to `[0.0, 30.0]` |
| `AI_CHAT_FEEDBACK_MAX_BUNDLE_BYTES` | `1000000` | Maximum serialized feedback bundle size before details/history are dropped. Clamped to `[10000, 5000000]` |
| `AI_CHAT_DIAGNOSTICS_BUNDLE_MAX_FILES` | `8` | Optional diagnostics/audit source files considered per local bundle. Clamped to `[1, 50]` |
| `AI_CHAT_DIAGNOSTICS_BUNDLE_MAX_ENTRIES` | `200` | JSONL entries included per source group. Clamped to `[1, 5000]` |
| `AI_CHAT_DIAGNOSTICS_BUNDLE_MAX_SOURCE_BYTES` | `512000` | Bytes read from the tail of each source file. Clamped to `[10000, 5000000]` |
| `AI_CHAT_DIAGNOSTICS_BUNDLE_MAX_BUNDLE_BYTES` | `2000000` | Target total diagnostics bundle cap. Clamped to `[50000, 50000000]` |
| `AI_CHAT_DIAGNOSTICS_BUNDLE_MAX_TIME_WINDOW_HOURS` | `168` | Default and maximum diagnostics export time window. Clamped to `[1, 744]` |
| `AI_CHAT_DIAGNOSTICS_ERROR_LOG_ENABLED` | `true` | Enable the separate redacted diagnostics error log for debug-enabled failed turns |
| `AI_CHAT_DIAGNOSTICS_LOG_PATH` | `app.data_dir/diagnostics` | Directory for diagnostics JSONL files |
| `AI_CHAT_DIAGNOSTICS_LOG_SUCCESSFUL_DEBUG_TURNS` | `false` | Also persist successful debug summaries. Default is failure-only |
| `AI_CHAT_DIAGNOSTICS_REDACT_CONTENT` | `true` | Redact raw prompts, streamed token text, tool arguments/output, API keys, bearer tokens, and secrets |
| `AI_CHAT_DIAGNOSTICS_RETENTION_DAYS` | `14` | Opportunistic diagnostics file retention. Clamped to `[0, 365]` |
| `AI_CHAT_DIAGNOSTICS_ROTATE_SIZE_BYTES` | `1048576` | Rotate active diagnostics JSONL around this size. Clamped to `[65536, 104857600]` |
| `AI_CHAT_DIAGNOSTICS_MAX_ENTRY_BYTES` | `32768` | Truncate oversized diagnostics entries. Clamped to `[1024, 1048576]` |
| `AI_CHAT_DIAGNOSTICS_MAX_LOG_DIR_BYTES` | `10485760` | Opportunistic total diagnostics directory cap; oldest files are deleted first. Clamped to `[65536, 1073741824]` |

## Debug Logging

Set `AI_CHAT_LOG_LEVEL=DEBUG` or pass `--debug` to emit correlated diagnostic
logs through the configured process logger, normally stderr. Debug logs include
sparse lifecycle events with request/turn correlation fields and redacted
operational metadata. They do not create a new always-on file sink, do not emit
per-token lines, and do not include raw prompts, raw messages, raw tool
arguments, raw tool output, API keys, bearer tokens, passwords, or secrets.

Use shell redirection when you intentionally need a local capture:

```bash
AI_CHAT_LOG_LEVEL=DEBUG aroom chat 2>debug.log
```

## 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).
