Skip to content

settings.toml keys

Every key kin reads from a settings.toml file. The file is the persistent baseline under your environment and flags — it feeds new sessions only (resuming reproduces a session's saved settings, never a live file). For the full precedence model, see Configuration.

File locations

kin reads two layered TOML files, parsed with the standard-library tomllib (no extra dependency):

File Path Role
Global ~/.kin/settings.toml Your machine-wide baseline. The base directory is relocatable with the KIN_HOME environment variable.
Project <workdir>/.kin/settings.toml Per-repo overlay, merged on top of the global file.

The project file overlays the global one key by key. Both are optional — a missing or malformed file degrades to "no settings" with a warning (set KIN_STRICT_SETTINGS=1 to raise instead). A complete, commented template ships as settings.toml.example in the repo.

Project files can't set global-only keys

A handful of keys are stripped (with a warning) from any project .kin/settings.toml — see Global-only keys. Set those in the global file, the environment, or a flag.

Keys

The scope column marks whether a key may live in a project file (project-ok) or only in the global file / environment / CLI (global-only).

Backend and model

Key Meaning Default Scope Env
provider Wire: openai or anthropic. openai (or anthropic when base_url is set and provider is unset) project-ok KIN_PROVIDER
model Model id. Set to default (any stable alias you register with your server) to follow whatever model is currently loaded; the harness probes /v1/models on session start and piggybacks response.model off each turn so the displayed name always reflects the live server. The alias survives model swaps on the wire. gpt-4o-mini (openai) / claude-opus-4-8 (anthropic) project-ok KIN_MODEL
base_url OpenAI-compat endpoint URL (trailing /v1 trimmed for the Anthropic wire). none global-only KIN_BASE_URL
api_key Endpoint auth. none (not-needed is sent) global-only KIN_API_KEY / OPENAI_API_KEY / ANTHROPIC_API_KEY
context_window Token budget for the context meter. 200000, then refined from the server's max_model_len when base_url is set project-ok KIN_CONTEXT_WINDOW
max_tokens Per-response output cap. 16000 (anthropic) / 8192 (openai) project-ok KIN_MAX_TOKENS
provider_preset First-party provider preset id (minimax, zai, or a [[providers]] id). Bundles wire + URL + default model + auth style. none global-only KIN_PRESET
provider_keys Per-provider key table ({<preset_id> = "<key>"}) — the recommended shape when you swap between multiple providers. Read first by the factory's chain (most specific selector — beats the generic api_key + env vars) so a stray ANTHROPIC_API_KEY baked into an image can't silently shadow the key you stored for the active provider. /providers writes here when you paste a key. none global-only (also _SECRET_SETTINGS_KEYS — redacted wholesale to [SET] on read)
model_favorites List of "provider_id/model" strings the bare /model picker pins to the top (a Favorites group). Toggle a row with f in the picker. [] global-only

Custom endpoints

A custom endpoint is a [[providers]] array-of-tables block — a self-contained preset (id, wire, base URL, default model) you can refer to from provider_preset. A custom row's id can shadow a built-in (so operators can override a built-in's URL without code changes), but the built-in lookup runs first so the curated catalogue wins for the common case.

[[providers]]
id = "openrouter"
provider = "openai"
base_url = "https://openrouter.ai/api/v1"
default_model = "anthropic/claude-3.7-sonnet"
models = ["anthropic/claude-3.7-sonnet"]

Add a custom endpoint via /providers → "Custom endpoint…" or by hand. See Provider presets for the full shape and which keys are recognized.

model is an alias for default_model on custom rows

The one-key model = "default" shape (no default_model, no models) is accepted as a convenience for one-line single-model / stable-alias rows — the parser aliases modeldefault_model and seeds models = [model] so the /model picker still surfaces a pickable row. Use the explicit two-key form (default_model + models = [...]) when the picker should show every model your server actually serves.

Per-provider keys ([provider_keys])

When you swap between multiple providers, the recommended storage shape is the [provider_keys] table — one key per preset id. The factory's resolution chain (_preset_key in src/kin/harness/backends/factory.py) reads provider_keys[<active_preset_id>] before falling back to api_key / env vars, so a key stored here is the most specific selector:

# ~/.kin/settings.toml
provider_preset = "zai"          # which preset is "active" for next session
model = "glm-5.2"

[provider_keys]
zai = "sk-..."
minimax = "sk-..."

/providers writes to this table when you paste a key, so the next session finds the key — no /reload, no manual settings.toml editing. The Outpost dashboard's per-provider paste-key field writes to the same table (see Outpost). Top-level api_key is the generic fallback (one key, one endpoint); [provider_keys] is the per-provider shape.

Sampling (OpenAI-compat wire only)

These apply only on the OpenAI-compat wire. The Anthropic wire (including a vLLM serve reached via the heuristic) ignores per-request sampling — set it on the server instead.

Key Meaning Default Scope Env
temperature Sampling temperature (0 = greedy). provider default project-ok KIN_TEMPERATURE
top_p Nucleus sampling. provider default project-ok KIN_TOP_P
top_k Top-k sampling (via extra_body). provider default project-ok KIN_TOP_K
enable_thinking Qwen3-style thinking soft switch (false hard-disables thinking). unset (model decides) project-ok KIN_ENABLE_THINKING
reasoning_effort OpenAI-proper reasoning-effort hint (real OpenAI / OpenRouter / Z.ai OpenAI-compat on GLM-5.2+). Top-level wire field on chat.completions.create — NOT inside extra_body. Per-serve vocab (3-value OpenAI vs 7-value Z.ai) is dispatched by the picker (see Models & providers); the resolver itself is opaque. Not for Qwen vLLM (use enable_thinking above). Cross-wire knob for the picker is effort, so this key is not in the model-writable set — reach it via effort=... which goes through the human-approval gate. unset project-ok KIN_REASONING_EFFORT
strict_tools Strict tool schemas on the streaming registry path (OpenAI-compat wire only). Each tool spec is normalized at request-build time (additionalProperties: false, all-required, optionals as ["type","null"] unions — the registry's canonical schemas are never mutated) and stamped strict: true, so endpoints that honor it (OpenAI-proper; vLLM ≥ 0.24 auto tool choice) grammar-enforce arguments. A no-op on vLLM 0.23 auto calls; forced tool calls (the workflow schema= path) are strict-normalized unconditionally regardless of this key. Human-only (not model-writable). See Strict decoding. false project-ok KIN_STRICT_TOOLS

Fleet safety

Governance knobs for a shared, self-hosted endpoint — see Fleet safety in the headless guide.

Key Meaning Default Scope Env
token_budget Per-run cumulative token budget: once a run's summed prompt+completion tokens (across every model round, subagent rounds included) cross this, the agent loop stops cleanly at the next model-round boundary — done reason token_budget, headless exit 1. A "run" is one root turn plus everything it fans out; the next turn starts fresh. Project-ok: the default is unlimited, so a project file can only impose a tighter cap (fail-safe). Human-only — deliberately not model-writable: the budget exists to stop a runaway model, so the model can never raise its own leash. 0 = off. 0 (off) project-ok KIN_TOKEN_BUDGET
max_turns Per-turn model-round cap: the maximum model↔tool round-trips one user turn may run before it ends with done reason turn_cap (headless exit 1). Independent of token_budget — the two limits are checked at the same round boundary. 0 = unlimited (the default) — the doom-loop guard (3× identical call+result) is the real no-progress backstop, so an unbounded cap is safe for large-model, hours-long runs. Project-ok: the default is unlimited, so a project file can only impose a tighter cap (fail-safe). Human-only — not model-writable (an operator leash, like token_budget). 0 (unlimited) project-ok KIN_MAX_TURNS
request_priority vLLM priority-scheduling passthrough (OpenAI-compat wire only — the Anthropic /v1/messages protocol has no priority field, so the Anthropic wire silently ignores this). Rides extra_body["priority"] on every request; lower = scheduled earlier, with genuine KV-swap preemption. Serve-gated: only meaningful when the server runs --scheduling-policy priority — vLLM errors on any non-zero priority otherwise, which is why the default is absent from the request, not 0. Human-only (not model-writable). See Models & providers. unset (absent) project-ok KIN_REQUEST_PRIORITY

Media and caching

Key Meaning Default Scope Env
image_detail OpenAI vision tier for tool-returned images (low / high / auto). low project-ok KIN_IMAGE_DETAIL
effort Anthropic adaptive-thinking effort. high project-ok KIN_EFFORT
thinking_type Anthropic-wire thinking.type knob — z.ai / MiniMax / Fable honor this as their canonical reasoning control (NOT output_config.effort). Common values: adaptive (default), enabled (force on), disabled (off — avoid on serves that 400 on it). adaptive project-ok KIN_THINKING_TYPE
cache_ttl Anthropic system-prompt prefix-cache TTL (1h opts into the 1-hour cache). 5 minutes project-ok KIN_CACHE_TTL

Permissions and OS sandbox

Key Meaning Default Scope Env
mode Permission mode at launch (auto / strict; the legacy default / accept-edits / plan still resolve via the alias map). auto global-only KIN_MODE
sandbox OS sandbox backend for auto-mode shell (auto / seatbelt / bwrap / off / container). container trusts an external boundary — auto-mode shell runs unconfined instead of asking (see the auto-mode guide). auto global-only KIN_SANDBOX
sandbox_strict Opt strict mode's shell into the OS sandbox (so an un-vetted command runs contained instead of prompting). false global-only KIN_SANDBOX_STRICT
sandbox_default Legacy (pre-two-mode) name, still honored as a fallback for sandbox_strict. Prefer sandbox_strict. false global-only KIN_SANDBOX_DEFAULT
sandbox_always_allow List of fnmatch command patterns (["uv *", "task *"]) that skip the OS-sandbox wrap in auto mode — the persistent tier of the ask_sandbox_override flow's "Always allow" choice. Empty = every auto-mode shell is sandboxed. Writable only through the override tool's human-approved always-allow path (NOT model-writable); hand-edit to manage it directly. [] global-only
shell_allowlist When true, provably read-only shell commands auto-allow; false sends every command to the approval modal. true global-only KIN_SHELL_ALLOWLIST

Planning

Key Meaning Default Scope Env
persist_plans Retired, no-op. Plans are now saved to <workdir>/.kin/plans/<date>-NN-<slug>.md unconditionally on every write_plan call — this key no longer gates anything; kept only so an existing settings.toml doesn't error. true project-ok KIN_PERSIST_PLANS

Sessions and persistence

Key Meaning Default Scope Env
session_dir Where session journals are written. ~/.kin/projects global-only KIN_SESSION_DIR
no_save Run ephemerally (write no journal; not resumable). false global-only KIN_NO_SAVE

Notifications

Key Meaning Default Scope Env
notify The terminal bell / OSC 9 walk-away notification — a bare BEL always, plus a native desktop notification on a verified OSC-9-capable terminal (Ghostty / iTerm2 / WezTerm / kitty). Fires 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). Default on; opt-out kill switch. Project-ok (it only toggles whether a static-string escape sequence is written; carries no model/server text). true project-ok KIN_NOTIFY

Appearance

Key Meaning Default Scope Env
spinner The busy-spinner style name (bloom · braille · arc · toggle · line — the vibe table lives in Identity). Unknown names fall back to the default; KIN_ASCII forces line. Pick interactively with /spinner (which persists here). Project-ok (pure display — no egress, secret, or containment impact). bloom project-ok KIN_SPINNER

Context and compaction

Key Meaning Default Scope Env
env_context Include the Environment + git-state blocks in the system prompt. true project-ok KIN_ENV_CONTEXT
compact_threshold Auto-compact history once usage crosses this fraction of the window (0.10.98). unset (off) project-ok KIN_COMPACT_THRESHOLD
compact_keep_turns Minimum recent turns to preserve when compacting. 4 project-ok KIN_COMPACT_KEEP_TURNS

Skills and web

Key Meaning Default Scope Env
strict_skills Raise on malformed skill / agent frontmatter instead of graceful-degrading. false project-ok KIN_STRICT_SKILLS
brave_api_key Brave Search key; enables the web_search / web_context tools. none global-only BRAVE_API_KEY / KIN_BRAVE_API_KEY
search_enabled Register the search_workspace tool — a ranked, chunk-aware full-text search over workspace content (stdlib SQLite FTS5; the complement to grep). The index DB lives outside the workspace under ~/.kin/index/. Project-ok (a local index only — no network/egress/secret). false project-ok KIN_SEARCH_ENABLED
run_code_enabled Register the run_code / run_code_reset interpreter tools — the stateful per-session Python kernel. Default on; the tools ride the full shell permission gate (sandboxed in auto, asks in strict), so this is an opt-out kill switch. Project-ok (it only unregisters tools; it grants nothing the gate doesn't). true project-ok KIN_RUN_CODE
diagnostics_after_edit Append a lint pass's output to write_file/edit_file results on a nonzero exit (ruff check, v1 — shutil.which-gated, never blocks or fails the write). Default on; opt-out kill switch. true project-ok KIN_DIAGNOSTICS
diagnostics_ty Also run an opt-in ty typecheck pass inside diagnostics-after-edit. Default off — ty is slow and typed-project-specific. false project-ok KIN_DIAGNOSTICS_TY
snapshots The file snapshot-before-write safety net — a git commit-tree checkpoint under refs/kin-snapshots/ taken before the first edit of every turn, restorable via /rewind files/both. Default on; opt-out kill switch. A no-op outside a git workspace. Project-ok (only toggles whether the checkpoint runs; never touches the real index/HEAD/worktree). true project-ok KIN_SNAPSHOTS
paste_file_mentions Convert Finder drag-drops / terminal pastes of absolute file paths into @-mentions in the Composer (default on). Off → pastes insert verbatim, identical to pre-Rock-3 behavior. Project-ok (it only re-routes a paste from raw-text-insert to mention-insert — no egress / secret / containment surface beyond what a manual paste would carry); human-only (a UX toggle, NOT model-writable). true project-ok KIN_PASTE_MENTIONS
browser_enabled Register the browser tool — the text-only headless browser (Playwright + Chromium, one per session). Default on, but the tool only registers when the optional browser extra is installed (uv sync --extra browser + uv run playwright install chromium); this key is the opt-out kill switch. Project-ok (it only unregisters the tool; it grants nothing the browser permission gate + the tool's scheme/SSRF boundary don't). true project-ok KIN_BROWSER
browser_allow_private Let the browser tool navigate to private/loopback/link-local addresses (local dev servers) — its SSRF guard refuses them by default. Global-only for the same reason ssh_hosts is: it grants network reach, and a cloned repo's project file must not be able to point your browser at the cloud metadata endpoint or an internal admin panel. false global-only KIN_BROWSER_PRIVATE
memory_enabled Register the memory tool + the recall injections (the stable index block and per-turn top-5 recall). Default on; this is the opt-out kill switch. Project-ok (it only unregisters/disables; containment lives in the tool's path guard). true project-ok KIN_MEMORY
memory_reflect Run the end-of-run reflection pass — a bounded extra turn over the live memory tool, fired automatically on a clean kin -p stop and at TUI quit. Project-ok (writes ride the same guarded store + containment as the tool). true project-ok KIN_MEMORY_REFLECT
memory_dir The memory root — where the memory tool reads and writes, and where the memory recall index lives. Global-only: memory mutations auto-apply in auto because they're contained to this root, so a cloned repo's project file must never be able to repoint that contained write surface at an arbitrary directory. ~/.kin/memory global-only KIN_MEMORY_DIR
ssh_hosts Allowlist of hosts (or ~/.ssh/config aliases) the opt-in ssh tool may reach. Both the opt-in switch (empty = the tool isn't registered) and the per-host gate. A TOML list; KIN_SSH_HOSTS is comma-separated. [] global-only KIN_SSH_HOSTS
outpost_url The origin of your Outpost (e.g. https://outpost.kinra.ai) — the outpost/outpost-send tools' target. Both tools register only when this AND outpost_token are set. Global-only for the same reason ssh_hosts is: a cloned repo's project file must never be able to repoint the tool at a hostile endpoint. none global-only KIN_OUTPOST_URL
outpost_token The bearer token (svc_<id>.<secret>) authenticating the outpost/outpost-send tools against your Outpost's v1 API. A credential — masked to [SET]/[NOT SET] wherever settings render, same as api_key. none global-only KIN_OUTPOST_TOKEN

Observability

Key Meaning Default Scope Env
spans_enabled Write OTel-GenAI-shaped JSONL spans — one invoke_agent per turn, a chat per model round, an execute_tool per tool call — to <session_id>.spans.jsonl next to the journal. Metadata only (timing / names / token counts; never prompt or tool text). Project-ok (a local file, no network/egress/secret) and human-only (not model-writable). false project-ok KIN_SPANS
pricing_enabled Display a running USD cost total alongside the /tokens counts (verbose breakdown) and as a recessive cell on the StatusBar ($0.04). Sourced from a stdlib-only pricing table keyed by (provider, model id) — see Cost display. Default off (opt in) — the primary endpoint is local vLLM (no cost) and the subscription providers (MiniMax/z.ai) make per-token cost noise; turn it on with KIN_PRICING=1 / pricing_enabled = true / the /cost on slash command (which also persists the choice). An unpriced serve (local vLLM, an id not in the table) shows nothing rather than a misleading $0.00. Project-ok (a local computation + display only; no network, no secret, no containment impact) and human-only (observability, never a sampling knob). false project-ok KIN_PRICING

Background subagents

Key Meaning Default Scope Env
bg_completion_reminders Inject the metadata-only <system-reminder> for completed bg subagents on the next depth-0 turn (true / false). The agent panel still shows completions when this is off. true project-ok KIN_BG_REMINDERS

Editing settings from inside kin

Two ways to change this file without leaving the TUI, both gated on a human diff-approval:

  • /edit-settings (or /config → settings) — you ask a scoped, read-only editor subagent to draft the whole file; you approve the diff. It may set any non-secret key.
  • /settings — turns on a per-turn settings guide so the model can help tune settings mid-conversation via the read_settings / propose_settings tools. The model is held to a tighter boundary than /edit-settings:

    Tier Keys the model may propose
    Model-writable temperature, top_p, top_k, max_tokens, context_window, enable_thinking, effort, thinking_type, cache_ttl, model
    Human-only (refused, hand-edit this file) mode, sandbox, sandbox_strict, sandbox_always_allow, shell_allowlist (containment); api_key, base_url, brave_api_key (secrets/endpoints); provider, provider_preset, providers, model_favorites (presets); reasoning_effort (cross-wire conflict — use effort which the picker translates per-serve)

    The model-writable list is an explicit positive allowlist — a key is refused until it's deliberately added, so a future setting can't silently become model-writable. read_settings masks every credential to [SET]/[NOT SET]. A proposed change goes through the same diff modal and applies to new sessions only (the live session's mode/model are human-only — use /mode and /model). See Model-writable settings.

Global-only keys

These keys are honored from the global ~/.kin/settings.toml, the environment, or a CLI flag — but are stripped (with a one-line warning) from any project .kin/settings.toml:

base_url, api_key, mode, sandbox, sandbox_strict, sandbox_default,
sandbox_always_allow, shell_allowlist, session_dir, no_save, brave_api_key,
provider_preset, providers, provider_keys, model_favorites, ssh_hosts,
browser_allow_private, outpost_url, outpost_token

The reason is the threat model of a cloned repository. A project file you didn't write could otherwise repoint your wire and leak your key (base_url + api_key), launch you straight into autonomous mode (mode), weaken or disable OS containment (sandbox, sandbox_strict, the legacy sandbox_default, shell_allowlist), grant itself a sandbox bypass (sandbox_always_allow), add a deploy target for the out-of-sandbox ssh tool (ssh_hosts), point the browser tool at your private network (browser_allow_private), redirect where sessions land (session_dir, no_save, brave_api_key), route your global api_key through a third-party endpoint (provider_preset + providers + provider_keys), or repoint the outpost/outpost-send tools at a hostile endpoint that would then receive your bearer token (outpost_url + outpost_token). Keeping them global-only means a checkout can't silently retarget your endpoint, route your key through an attacker-controlled host, or weaken your safety posture. The exact denylist and the layering rules are documented in the repo's REFERENCE.md § Settings & config layering.

Secrets (api_key, brave_api_key) belong only in the global file, which lives in your $HOME and isn't committed — chmod 600 ~/.kin/settings.toml, like ~/.aws/credentials.