# Environment variables

> Every environment variable kin reads. Environment variables sit above both settings.toml files in precedence and below CLI flags, so an exported KIN is always a one-off override. For the full precedence model, see Con…

Every environment variable `kin` reads. Environment variables sit above both `settings.toml` files in precedence and below CLI flags, so an exported `KIN_*` is always a one-off override. For the full precedence model, see [Configuration](/docs/kin/getting-started/configuration/).

<!-- SOURCE: src/kin/harness/presets.py, src/kin/harness/backends/factory.py, src/kin/harness/backends/base.py, src/kin/harness/backends/responses.py, src/kin/harness/settings/, src/kin/harness/sandbox.py, src/kin/harness/command_safety.py, src/kin/harness/env.py, src/kin/harness/compaction.py, src/kin/harness/skills.py, src/kin/harness/persistence/, src/kin/harness/session/, src/kin/harness/status_file.py, src/kin/harness/mcp/, src/kin/harness/backends/anthropic.py, src/kin/harness/tools/_media.py, src/kin/harness/tools/web_search.py, src/kin/harness/tools/outpost.py, src/kin/harness/tools/diagnostics.py, src/kin/harness/term_notify.py, src/kin/harness/memory/, src/kin/harness/shelf.py, src/kin/tui/shelf_watch.py, src/kin/tui/banner.py, src/kin/tui/cli.py, src/kin/tui/theme.py, container/dashboard/keystore.py, container/dashboard/scheduler.py, container/dashboard/governor.py -->

## Variables

The **scope** column matches the variable's `settings.toml` equivalent: `project-ok` keys may live in a project file, `global-only` keys are honored only from the global file / env / CLI, and `env only` variables have no settings key. See [settings.toml keys](/docs/kin/reference/settings-toml/) for the file side.

### Backend and model

| Variable | What it does | `settings.toml` key | Scope |
|---|---|---|---|
| `KIN_PROVIDER` | Provider family: `openai` or `anthropic`. With a base URL and neither identity axis set, the vLLM heuristic picks Anthropic. Explicit `openai` without `KIN_WIRE_API` means Chat. | `provider` | project-ok |
| `KIN_WIRE_API` | OpenAI wire: `chat` or `responses`. Either implies OpenAI and bypasses the bare-base-URL Anthropic heuristic. Responses is opt-in; Chat is the default. `messages` is internal and rejected here. | `wire_api` | project-ok |
| `KIN_MODEL` | Model id. Set to `default` to follow whatever model your local server (vLLM/Ollama) is currently running — the harness probes `/v1/models` on session start and reads `response.model` off each turn so the displayed name always reflects the live server. The alias is sent verbatim on the wire. | `model` | project-ok |
| `KIN_BASE_URL` | OpenAI-compat endpoint URL for the default backend (a trailing `/v1` is trimmed for the Anthropic wire). A selected provider preset owns its endpoint instead; an explicit caller `base_url` can still override the preset. | `base_url` | global-only |
| `KIN_PRESET` | Provider preset id (built-ins: direct `openai` / `anthropic`, plus curated `minimax`, `zai`). Bundles wire + endpoint/auth identity; curated presets also supply a default model. | `provider_preset` | global-only |
| `KIN_API_KEY` | Generic endpoint auth fallback. For direct vendor presets it follows that vendor's conventional variable. | `api_key` | global-only |
| `OPENAI_API_KEY` | Direct OpenAI auth (then `KIN_API_KEY`); never used by the direct Anthropic preset. Compatibility/custom presets retain the broad legacy fallback chain. | `api_key` | global-only |
| `ANTHROPIC_API_KEY` | Direct Anthropic auth (then `KIN_API_KEY`); never used by the direct OpenAI preset. Compatibility/custom presets retain the broad legacy fallback chain. | `api_key` | global-only |
| `KIN_CONTEXT_WINDOW` | Token budget for the context meter. | `context_window` | project-ok |
| `KIN_MAX_TOKENS` | Per-response output cap. | `max_tokens` | project-ok |
| `KIN_TEMPERATURE` | Sampling temperature (OpenAI-compat wire only). | `temperature` | project-ok |
| `KIN_TOP_P` | Nucleus sampling `top_p` (OpenAI-compat wire only). | `top_p` | project-ok |
| `KIN_TOP_K` | `top_k` via `extra_body` (OpenAI-compat wire only). | `top_k` | project-ok |
| `KIN_ENABLE_THINKING` | Chat-template thinking soft switch for Qwen-style OpenAI-compatible serves and an Anthropic custom provider with `reasoning_profile="poolside"`. | `enable_thinking` | project-ok |
| `KIN_REASONING_EFFORT` | OpenAI reasoning-effort hint — top-level `reasoning_effort` on Chat, or `reasoning.effort` on Responses. Qwen-style vLLM serves may instead use `KIN_ENABLE_THINKING`. The resolver is opaque to each serve's vocabulary; the picker (see [Models & providers](/docs/kin/guide/models-and-providers/)) translates the cross-wire `effort` knob. | `reasoning_effort` | project-ok |
| `KIN_STRICT_TOOLS` | Strict tool schemas on the streaming registry path (OpenAI-compat wire only, default off) — each tool spec ships a strict-normalized copy (`additionalProperties: false`, all-required, optionals as null-unions) + `strict: true`, so endpoints that honor it (OpenAI-proper; vLLM ≥ 0.24 auto tool choice) grammar-enforce the arguments. See [Strict decoding](/docs/kin/guide/models-and-providers/#strict-decoding-schema-valid-tool-calls). | `strict_tools` | project-ok |
| `KIN_EFFORT` | Anthropic adaptive-thinking effort (default `high`). | `effort` | project-ok |
| `KIN_THINKING_TYPE` | Anthropic-wire `thinking.type` knob (default `adaptive`) — z.ai / MiniMax / Fable's canonical reasoning control. Common values: `adaptive`, `enabled`, `disabled` (the disabled shape 400s on some serves). | `thinking_type` | project-ok |
| `KIN_CACHE_TTL` | Anthropic system-prompt prefix-cache TTL (`1h` opts into the 1-hour cache). | `cache_ttl` | project-ok |
| `KIN_CACHE_MIN_PREFIX_TOKENS` | Minimum prefix length before the Anthropic prefix cache engages. | — | env only |
| `KIN_IMAGE_DETAIL` | OpenAI vision tier for tool-returned images (`low` / `high` / `auto`). | `image_detail` | project-ok |
| `KIN_STREAM_STALL_TIMEOUT` | Seconds of silence (no stream event) before a model turn is aborted as stalled, across Messages, Chat, and Responses (default `120`). Guards against a compat endpoint that keeps a connection open with keep-alive bytes after silently dropping the generation. | — | env only |

### Permissions and sandbox

| Variable | What it does | `settings.toml` key | Scope |
|---|---|---|---|
| `KIN_MODE` | Permission mode at launch (`auto` / `strict`; the legacy `default` / `accept-edits` / `plan` still resolve via the alias map). | `mode` | global-only |
| `KIN_SANDBOX` | OS sandbox backend for auto-mode shell (`auto` / `seatbelt` / `bwrap` / `off` / `container`). `container` trusts an external boundary so auto-mode shell runs unconfined instead of asking (see the [auto-mode guide](/docs/kin/guide/auto-mode-and-sandbox/#trust-the-container)). | `sandbox` | global-only |
| `KIN_SANDBOX_NETWORK` | Set to `0` to isolate networking inside Seatbelt/bubblewrap; default is network available with workspace/secret containment intact. | `sandbox_network` | global-only |
| `KIN_SANDBOX_STRICT` | Opt `strict` mode's shell into the OS sandbox. | `sandbox_strict` | global-only |
| `KIN_SANDBOX_DEFAULT` | Legacy (pre-two-mode) name, still honored as a fallback for `KIN_SANDBOX_STRICT`. | `sandbox_default` | global-only |
| `KIN_SHELL_ALLOWLIST` | Set to a falsy value to disable the read-only shell allowlist (every command then asks). | `shell_allowlist` | global-only |

### Fleet safety

| Variable | What it does | `settings.toml` key | Scope |
|---|---|---|---|
| `KIN_TOKEN_BUDGET` | Per-run cumulative token budget (prompt + completion, summed across every model round — subagent rounds included). A budget hit stops the run cleanly at the next model-round boundary (done reason `token_budget`; headless exit `1`). `0` / unset = off. Human-only — not model-writable. See [Fleet safety](/docs/kin/guide/headless/#fleet-safety-the-per-run-token-budget). | `token_budget` | project-ok |
| `KIN_MAX_TURNS` | Per-turn model-round cap: the maximum model↔tool round-trips one user turn may take before it ends with done reason `turn_cap`. `0` / unset = **unlimited** (the default) — the [doom-loop guard](/docs/kin/guide/headless/#fleet-safety-the-per-run-token-budget) (3× identical call+result) is the real no-progress backstop, so an unbounded cap is safe for long-running agentic turns. Human-only — not model-writable. | `max_turns` | project-ok |
| `KIN_REQUEST_PRIORITY` | Legacy vLLM priority-scheduling passthrough (`extra_body["priority"]`, lower = earlier; OpenAI-compat wire **only**). Serve-gated: requires `--scheduling-policy priority`; vLLM errors on a non-zero priority otherwise, and current DS4 does not implement the field, so the default is *absent*, not `0`. See [Models & providers](/docs/kin/guide/models-and-providers/#priority-scheduling-passthrough-vllm). | `request_priority` | project-ok |

### Planning

| Variable | What it does | `settings.toml` key | Scope |
|---|---|---|---|
| `KIN_PERSIST_PLANS` | **Retired, no-op** — plans are now saved to `<workdir>/.kin/plans/` unconditionally on every `write_plan` call. Kept only so an existing `settings.toml`/env doesn't error. | `persist_plans` | project-ok |

### Sessions and persistence

| Variable | What it does | `settings.toml` key | Scope |
|---|---|---|---|
| `KIN_SESSION_DIR` | Directory for session journals (the usual override; takes precedence over the settings key). | `session_dir` | global-only |
| `KIN_NO_SAVE` | Run ephemerally — write no session journal or durable prompt history; composer recall remains memory-only for this process. | `no_save` | global-only |
| `KIN_PROMPT_HISTORY_CAP` | Maximum interactive composer submissions retained per project for ↑/↓ and ++ctrl+r++ across restarts (default `100`). `0` makes recall memory-only without deleting retained history; negative or malformed values use `100`. Stores submitted model prompts, slash commands, and `!` command text—not shell output—and never includes headless `kin -p` prompts. Every no-save route overrides this and disables durable history. | `prompt_history_cap` | project-ok |
| `KIN_DETACH` | Interactive launches run as [background sessions](/docs/kin/guide/sessions/#background-sessions-detach-reattach) by default when tmux ≥ 3.2 is available (DR 0097); set `KIN_DETACH=0` to opt out (`=1` forces it on). `kin --no-detach` always wins; headless `-p` and launches inside your own tmux are never wrapped. | `detach` | project-ok |
| `KIN_HOME` | Relocate the `~/.kin` base where `settings.toml` (and the default `projects/` journal root) live. | — | env only |
| `KIN_STATUS_FILE` | Path to a best-effort JSON state sidecar a wrapper writes/reads. kin writes `running` / `waiting` / `idle` there atomically; unset (a plain `kin` run) = no sidecar. Advisory only — never authoritative for liveness. (The Outpost's ttyd→tmux→kin pipeline was the one consumer before the middle-way plan's Step 3 ttyd cut, 2026-07-06, DR 0033; no current wrapper sets this env var.) | — | env only |

### Context and compaction

| Variable | What it does | `settings.toml` key | Scope |
|---|---|---|---|
| `KIN_ENV_CONTEXT` | Set to `0` to omit the Environment + git-state blocks from the system prompt. | `env_context` | project-ok |
| `KIN_COMPACT_THRESHOLD` | Auto-compact once prompt usage crosses this fraction of the window; the output reservation may impose an earlier hard limit. | `compact_threshold` | project-ok |
| `KIN_COMPACT_KEEP_TURNS` | Minimum recent turns to preserve when compacting (default `4`). | `compact_keep_turns` | project-ok |

### Skills, tools, and web

| Variable | What it does | `settings.toml` key | Scope |
|---|---|---|---|
| `KIN_STRICT_SKILLS` | Set to `1` to raise on malformed skill / agent frontmatter instead of graceful-degrading. | `strict_skills` | project-ok |
| `KIN_SEARCH_ENABLED` | Set to `0` to unregister the default-on [`search_workspace`](/docs/kin/guide/workspace-search/) tool (ranked lexical full-text search over workspace content, stdlib SQLite FTS5). | `search_enabled` | project-ok |
| `KIN_SHELF_ENABLED` | Set to `0` to disable [shelf](/docs/kin/guide/shelf/) board hints and the TUI returned-branch watcher. | `shelf_enabled` | project-ok |
| `KIN_SHELF_WATCH_INTERVAL` | Seconds between fixed-refspec shelf branch probes; minimum 30, default 120, read at TUI mount. | `shelf_watch_interval` | project-ok |
| `KIN_RUN_CODE` | Set to `0` to unregister the [`run_code` / `run_code_reset`](/docs/kin/guide/tools/#code-interpreter-python) interpreter tools (the stateful per-session Python kernel). On by default — they ride the full `shell` permission gate. | `run_code_enabled` | project-ok |
| `KIN_DIAGNOSTICS` | Set to `0` to disable the [diagnostics-after-edit](/docs/kin/guide/tools/#filesystem) lint pass appended to `write_file`/`edit_file` results (`ruff check`, v1). On by default; `shutil.which`-gated (no-op if the linter isn't installed) and never blocks or fails the write. | `diagnostics_after_edit` | project-ok |
| `KIN_DIAGNOSTICS_TY` | Set to `1` to also run an opt-in `ty` typecheck pass inside diagnostics-after-edit. Off by default (`ty` is slow and typed-project-specific). | `diagnostics_ty` | project-ok |
| `KIN_SNAPSHOTS` | Set to `0` to disable the [file snapshot-before-write safety net](/docs/kin/guide/sessions/#file-snapshots) (`/rewind files`/`both`'s source). On by default; a no-op outside a git workspace. | `snapshots` | project-ok |
| `KIN_PASTE_MENTIONS` | Set to `0` to make the Composer insert [Finder drag-drops / terminal pastes of absolute file paths](/docs/kin/guide/at-mentions/#pasting-files-drag-drop-terminal-paste) verbatim instead of converting them to `@`-mentions. On by default. | `paste_file_mentions` | project-ok |
| `KIN_SPANS` | Set to `1` to write OTel-GenAI-shaped [JSONL spans](https://github.com/kinra-ai/kin/blob/dev/docs/guide/evals.md#the-span-sink) (`invoke_agent` / `chat` / `execute_tool`; metadata only — no prompt/tool text) next to each session journal (`<session_id>.spans.jsonl`). Off by default. | `spans_enabled` | project-ok |
| `KIN_PRICING` | Set to `1` to display a running USD cost total (`/tokens`, StatusBar). Sourced from a stdlib pricing table keyed by `(provider, model id)`; an unpriced serve shows nothing. Off by default. See [Cost display](/docs/kin/guide/models-and-providers/#cost-display). | `pricing_enabled` | project-ok |
| `KIN_RIG` | Set to `0` to unregister the [Rig](/docs/kin/guide/rig/) tool family. Registration also requires a URL and token. | `rig_enabled` | project-ok |
| `KIN_RIG_URL` | Rig's semantic API origin. | `rig_url` | global-only |
| `KIN_RIG_TOKEN` | Rig bearer credential. Deployments prefer the file form below. | `rig_token` | global-only |
| `KIN_RIG_TOKEN_FILE` | Read the Rig bearer from a secret file without exporting it to child environments. | — | env only |
| `KIN_BROWSER` | Legacy no-op retained so existing settings do not fail validation. | `browser_enabled` | project-ok |
| `KIN_BROWSER_PRIVATE` | Legacy no-op; local Rig development uses `task rig:local`. | `browser_allow_private` | global-only |
| `KIN_MEMORY` | Set to `0` to unregister the [`memory` tool](/docs/kin/guide/memory/) and disable the memory index/recall injections. On by default. | `memory_enabled` | project-ok |
| `KIN_MEMORY_REFLECT` | Set to `0` to skip the [end-of-run memory reflection](/docs/kin/guide/memory/#memory-capture-at-session-end) pass (a bounded extra turn over the live `memory` tool, fired automatically on a terminal clean `kin -p` stop with no pending human gate and at TUI quit). On by default; a run that succeeded is never recorded as `error` because of it. | `memory_reflect` | project-ok |
| `KIN_MEMORY_DIR` | Relocate the [memory root](/docs/kin/guide/memory/) (e.g. for a workspace-local store). Default `~/.kin/memory`. | `memory_dir` | global-only |
| `KIN_OUTPOST_URL` | Your [Outpost](/docs/kin/guide/outpost/)'s origin (e.g. `https://outpost.kinra.ai`) — the `outpost`/`outpost-send` tools' target. Both tools register only when this AND `KIN_OUTPOST_TOKEN` resolve. | `outpost_url` | global-only |
| `KIN_OUTPOST_TOKEN` | The bearer token (`svc_<id>.<secret>`) authenticating the `outpost`/`outpost-send` tools against your Outpost's v1 API. | `outpost_token` | global-only |
| `BRAVE_API_KEY` | Brave Search key; enables the `web_search` / `web_context` tools. | `brave_api_key` | global-only |
| `KIN_BRAVE_API_KEY` | Alternate name for the Brave key, read after `BRAVE_API_KEY`. | `brave_api_key` | global-only |
| `KIN_MCP_TRUST` | Path to the persistent MCP server trust store. | — | env only |
| `KIN_MCP_AUTH` | Directory for per-server [MCP OAuth](/docs/kin/guide/mcp/#oauth-for-remote-servers) token state (default `~/.kin/mcp_auth/`; files are `0600`). | — | env only |

### Background subagents

| Variable | What it does | `settings.toml` key | Scope |
|---|---|---|---|
| `KIN_AGENT_STALL_TIMEOUT` | Seconds without model/tool activity before an active, non-paused task agent becomes advisory `stale`. Clamped to 30–3600; never cancels or restarts the child. | `agent_stall_timeout` | project-ok |

### Scheduled jobs & the v1 service registry (Outpost operator)

These are read by the Outpost dashboard / scheduler (`container/dashboard/`), not the harness proper. Operator/deployment-scoped, never written to `settings.toml`.

| Variable | What it does | `settings.toml` key | Scope |
|---|---|---|---|
| `KIN_MASTER_KEY` | The v1 service-registry Key Encryption Key (KEK) — a Fernet key that wraps every service's bearer token + webhook signing secret at rest in `services.db` (`container/dashboard/keystore.py`, `services_db.py`; PROTOCOL.md §2.1). Resolution order: this env var (the deployment-time secret-manager path) → the `0600` key file at `<kin_home>/keystore/service_kek.bin` (auto-generated on first dashboard startup / first `kin service create`, refused if group/other-readable). Ignored (with a logged error) if set to something that isn't a valid Fernet key. Also the NEW key during a `kin service rekey` rotation. KEK loss is recoverable-by-re-registration only — every service must re-register. | — | env only |
| `KIN_OLD_MASTER_KEY` | The PREVIOUS KEK during a `kin service rekey` rotation (`container/dashboard/services_db.py::rekey`, `src/kin/harness/cli/service.py`). `rekey` needs BOTH env vars — `KIN_OLD_MASTER_KEY` (decrypt with the current key) + `KIN_MASTER_KEY` (re-encrypt with the new key) — and rotates every service secret in one transaction. Generate a new key with `python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"`. | — | env only |
| `KIN_GPU_PRIORITY` | Legacy vLLM-only scheduler switch. On an explicitly qualified vLLM serve with `--scheduling-policy priority`, flips background children to OpenAI Chat and stamps their resolved `KIN_REQUEST_PRIORITY`. Keep unset on the current DS4 fleet: DS4 does not implement this request field, and the named Responses profile must remain intact. | — | env only |
| `KIN_GPU_PRESSURE_URL` | Optional URL of a compatible vLLM Prometheus endpoint exposing `vllm:num_requests_waiting`. Only then may the Background limits card enable `defer_when_interactive`; absent means the control is unavailable. Keep unset on DS4, which exposes no compatible queue metric. A configured endpoint fails open if its scrape becomes unreachable. | — | env only |
| `KIN_JOB_ID` / `KIN_JOB_NAME` | Set by the Outpost scheduler on a scheduled job's `kin -p` subprocess env (`container/dashboard/scheduler.py`), never by an operator directly. Read by the harness's [end-of-run memory reflection](/docs/kin/guide/memory/#memory-capture-at-session-end) to tag that job's memory writes, so a recurring job updates ONE memory in place instead of accumulating near-duplicates across runs. | — | env only |

### Meta and UI

| Variable | What it does | `settings.toml` key | Scope |
|---|---|---|---|
| `KIN_STRICT_SETTINGS` | Set to `1` to raise on a malformed `settings.toml` instead of degrading to no settings. | — | env only |
| `KIN_ASCII` | Force plain-ASCII rendering — the welcome banner (no box-drawing) and the ASCII-safe `line` spinner style. | — | env only |
| `KIN_THEME` | TUI theme name. `kin` is the transparent terminal-ground default; `kin-graphite` is the opaque Graphite+ fallback. A higher-precedence env value shadows choices saved by `/theme`. | `theme` | project-ok |
| `KIN_SPINNER` | The busy-spinner style name (`rain` · `braille` · `arc` · `toggle` · `line` — see [Identity](/docs/kin/concepts/identity/#spinner-vibes)). Unknown names fall back to the default; pick interactively with `/spinner`. | `spinner` | project-ok |
| `KIN_NOTIFY` | Set to `0` to disable the [terminal bell / OSC 9 walk-away notification](/docs/kin/guide/sessions/#terminal-notifications) — a completion bell on a turn that ran 15s+ and on every needs-input prompt (TUI), or on process completion when stderr is a real terminal ([`kin -p`](/docs/kin/guide/headless/#exit-codes-the-contract)). On by default. | `notify` | project-ok |

> **Host environment kin also reads**
>
> Beyond its own knobs, `kin` reads a few standard host variables: `SHELL`, `LANG`, and `LC_ALL` feed the environment block in the system prompt; `TMPDIR` scopes the OS sandbox's writable temp path; and `XDG_CONFIG_HOME` locates user-level `AGENTS.md` guidance. These are not `kin` configuration — they are the ambient environment it observes.

For the meaning of `provider`, `base_url`, and the sampling knobs, see [Models & providers](/docs/kin/guide/models-and-providers/). For the global-only safety boundary, see [settings.toml keys](/docs/kin/reference/settings-toml/).
