Kin / Reference
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…
Read as MarkdownEvery 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 layered TOML files, parsed with the standard-library tomllib (no extra dependency). The kin home (~/.kin, relocatable with KIN_HOME) holds three files with distinct owners:
| File | Path | Role |
|---|---|---|
| Global | ~/.kin/settings.toml |
Your machine-wide baseline — preferences and the provider catalogue. The file this page’s keys normally live in. |
| Credentials | ~/.kin/credentials.toml |
Kin-managed secret store (provider_keys, api_key, brave_api_key, outpost_token, rig_token), created 0600. Written by kin connect, /models, and the key prompts — you never need to edit it. |
| Grants | ~/.kin/grants.toml |
Kin-managed authority stores (sandbox_grants, git_host_grants). Audit it freely; manage it via /grants and the approval modals. |
| Project | <workdir>/.kin/settings.toml |
Per-repo overlay, merged on top of the global layer. |
All layers merge into one view — every key below behaves identically wherever it is stored; the sibling files exist so settings.toml stays a short file that is entirely yours. A secret or grant key found in a legacy settings.toml still works and moves to its sibling file automatically on the next settings write. Run kin settings to see the effective configuration, which file supplies each key, and configuration lint.
The project file overlays the global layer key by key. Every file is 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; a fresh machine’s first interactive run also writes a short comments-only starter.
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 |
Provider family: openai or anthropic. |
openai (or anthropic when a bare base_url is set and neither identity axis is selected) |
project-ok | KIN_PROVIDER |
wire_api |
OpenAI wire shape: public values chat or responses. Either implies provider = "openai" and bypasses the bare-URL Anthropic heuristic. provider = "openai" without this key and the built-in OpenAI preset both remain on Chat. Anthropic Messages is an internal value, not valid settings input. |
chat for OpenAI |
project-ok | KIN_WIRE_API |
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 for the default backend (trailing /v1 trimmed for the Anthropic wire). A selected provider preset owns its endpoint; only an explicit caller URL overrides that preset identity. |
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. Pins/overrides numeric server limits (max_model_len / context_length / max_input_tokens from /v1/models); capability metadata is still discovered. |
200000, then refined from the server’s /v1/models metadata 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 |
Provider preset id (openai, anthropic, minimax, zai, or a [[providers]] id). Bundles wire/endpoint/auth identity; curated rows also supply a default model, while direct OpenAI/Anthropic keep it explicit. |
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) |
— |
provider_tiers |
Per-provider capability tier table. MiniMax uses plus / max / ultra and Z.ai uses lite / pro / max to size ordinary subagent capacity. /providers writes the selected tier. |
{} (provider defaults: MiniMax plus, Z.ai lite) |
global-only | — |
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 | — |
model_routes |
Named route tables ([model_routes.<id>]) that bind a trusted provider preset to an explicit model and optional capability/execution overrides. See Model routes. |
{} |
global-only | — |
model_assignments |
Operator bindings for mca, vision, rig, task, workflow, utility (housekeeping side-calls such as session auto-titles), plus [model_assignments.profiles]. Values are route ids. |
{} |
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"
wire_api = "chat" # or "responses"
base_url = "https://openrouter.ai/api/v1"
default_model = "anthropic/claude-3.7-sonnet"
models = ["anthropic/claude-3.7-sonnet"]
OpenAI custom rows may set wire_api = "chat" (the default) or opt into
wire_api = "responses". Anthropic rows imply Messages and reject an OpenAI
wire value. A row may carry reasoning_effort = "<level>" as the endpoint’s
own default effort (opaque string, serve-owned vocabulary); on a Responses row
this also opts the stream into reasoning-summary deltas — required for
thinking-by-default serves like DS4 (see
Models & providers).
Custom rows may also set reasoning_profile = "poolside". That profile is
valid only on an anthropic row and selects Laguna’s per-request
chat_template_kwargs.enable_thinking control; an unknown profile or an
OpenAI-wire pairing is rejected instead of guessed. See
Laguna S 2.1 on vLLM.
For the qualified text-only Responses shape backed by Paddock-managed
llama.cpp, see Paddock and llama.cpp
Responses.
Add a custom endpoint via /providers → “Custom endpoint…” or by hand.
See Provider presets for the full shape and
which keys are recognized.
modelis an alias fordefault_modelon custom rowsThe one-key
model = "default"shape (nodefault_model, nomodels) is accepted as a convenience for one-line single-model / stable-alias rows — the parser aliasesmodel→default_modeland seedsmodels = [model]so the/modelpicker 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 environment variables / api_key, so a key stored here is the most specific selector. Direct OpenAI consults OPENAI_API_KEY then KIN_API_KEY; direct Anthropic consults ANTHROPIC_API_KEY then KIN_API_KEY, and neither borrows the other vendor’s conventional key. Compatibility/custom presets retain the broad legacy environment chain because their wire does not identify the credential issuer:
# ~/.kin/settings.toml (human-owned, non-secret selection)
provider_preset = "zai" # which preset is "active" for next session
model = "glm-5.2"
[provider_tiers]
minimax = "plus"
zai = "lite"
Kin writes the corresponding secret table to its 0600 credential store:
# ~/.kin/credentials.toml (Kin-managed; shown only to explain storage)
[provider_keys]
zai = "sk-..."
minimax = "sk-..."
/providers writes to this table when you paste a key, so the next session and future routed calls find the key — no /reload, no manual settings.toml editing. For direct OpenAI/Anthropic rows, leaving the exact-model field blank refreshes the catalog for future route dispatch without switching the live MCA; running children keep their prior snapshot. 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.
Model routes
Model routes separate what a call is for from the endpoint wire. Every route
references an existing built-in or custom provider preset; routes never own a
URL or credential. Direct openai and anthropic preset ids are built in, so
they work beside MiniMax, Z.ai, and custom [[providers]] rows. Their
empty preset URL means the vendor SDK endpoint and does not inherit an ambient
KIN_BASE_URL used by the default backend.
# ~/.kin/settings.toml
[provider_keys]
openai = "sk-..."
anthropic = "sk-ant-..."
[model_routes.primary]
provider_preset = "anthropic"
model = "your-text-model-id"
description = "Main collaboration model"
vision = false
effort = "high"
max_tokens = 16000
selectable_for = ["task", "workflow"]
[model_routes.visual]
provider_preset = "openai"
model = "your-vision-model-id"
description = "Isolated image inspection"
vision = true
selectable_for = ["task"]
[model_assignments]
mca = "primary"
vision = "visual"
rig = "visual"
task = "primary"
workflow = "primary"
utility = "visual" # housekeeping side-calls (session auto-titles)
[model_assignments.profiles]
researcher = "primary"
Each [model_routes.<id>] accepts only these fields:
| Field | Required | Meaning |
|---|---|---|
provider_preset |
yes | Built-in or custom preset id. This is the endpoint and credential trust boundary. |
model |
yes | Exact model id sent on that preset’s wire. |
description |
no | Operator description shown to humans and, only when selectable, to the task/workflow model. |
vision |
no | Authoritative true / false semantic-vision override. Omitted starts as unknown; Kin caches a supported or capability-rejected media attempt until reload. |
reasoning_profile |
no | Closed route request contract. qwen-llamacpp enables budget-labelled Qwen choices without applying nonstandard fields to other routes/providers. |
effort |
no | Per-route effort value, validated against that preset/model’s picker vocabulary. |
max_tokens |
no | Positive per-response output cap for this route. |
selectable_for |
no | Explicit model-choice allowlist containing only "task" and/or "workflow". Operator assignments do not need this opt-in. |
Resolution is deterministic: profile assignment, then consumer assignment,
then an allowed requested route, then a requested legacy model, then the
current MCA backend. route and model are mutually exclusive, and an invalid
model clone is an error rather than a silent fallback. Forks retain their
parent’s exact backend. See Models & providers
for media isolation, persistence, usage, and /reload behavior.
For reasoning_profile = "qwen-llamacpp", valid effort values are default,
off, thinking-128, thinking-512, thinking-1024, and thinking-2048.
The route’s max_tokens is a total output allowance and must exceed an enabled
budget. A Utility assignment also requires 512 final-answer tokens beyond the
budget. See Qwen bounded thinking.
utility is assignment-only: it binds kin-internal housekeeping side-calls
(session auto-titles today) to a lightweight route so tiny requests stay off
the main endpoint’s prompt cache. It is never model-selectable, its calls are
best-effort (a busy route skips the call rather than queueing), and a failed
utility call keeps the first-message fallback title instead of retrying on the
main backend. Unassigned, housekeeping stays on the main backend as before.
Sampling and compatible reasoning controls
temperature, top_p, and top_k apply only on the OpenAI-compat wire. The
Anthropic wire ignores per-request sampling, so set it on the server instead.
enable_thinking has the explicit Poolside exception described below.
| 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 |
Chat-template thinking soft switch for Qwen-style OpenAI-compatible serves and an Anthropic custom provider with reasoning_profile="poolside" (false hard-disables thinking). |
unset (model/server decides) | project-ok | KIN_ENABLE_THINKING |
reasoning_effort |
OpenAI-proper reasoning-effort hint (real OpenAI / OpenRouter / Z.ai OpenAI-compat on GLM-5.2+; any custom Responses-wire endpoint). Top-level wire field on chat.completions.create — NOT inside extra_body; on the Responses wire it rides reasoning: {"effort": ..., "summary": "auto"} (the summary opt-in is what makes a thinking-by-default serve stream reasoning deltas). Per-serve vocab (3-value OpenAI vs 7-value Z.ai vs the Responses pass-through) is dispatched by the picker (see Models & providers); the resolver itself is opaque. Not for Qwen vLLM Chat serves (use enable_thinking above). A [[providers]] row may carry its own reasoning_effort default, which wins over this top-level file value when that row is selected; the higher-precedence KIN_REASONING_EFFORT environment override still wins over both. 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 |
Legacy vLLM priority-scheduling passthrough (OpenAI-compat wire only). Rides extra_body["priority"] on every request; lower = scheduled earlier, with KV-swap preemption. Serve-gated: only meaningful when the server runs --scheduling-policy priority — vLLM errors on any non-zero priority otherwise, and current DS4 does not implement the field, 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_network |
Allow outbound networking inside Seatbelt/bubblewrap while retaining workspace write confinement and secret masking. No effect for off/container. |
true |
global-only | KIN_SANDBOX_NETWORK |
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_grants |
Human-approved [[sandbox_grants]] rows written by the typed sandbox-access modal. Each row binds an sbg_… id and exact canonical workspace to write_paths, network, and ssh_agent capabilities. Invalid, sensitive, or mismatched rows are ignored fail-closed. Prefer /grants over hand-editing. |
[] |
global-only | — |
git_host_grants |
Human-approved, secret-free [[git_host_grants]] rows written by the Git credential modal’s Trust host action. Each ghg_… row binds SSH/HTTPS + resolved user/host/port to a route fingerprint and display label; it never stores a token, key, socket path, remote URL, or repository path. A changed SSH/helper route asks again. Invalid rows are inert. Manage with /grants. |
[] |
global-only | — |
sandbox_always_allow |
Inactive migration data. Older Kin versions stored fnmatch command patterns here. Current Kin lists them in /grants as requiring reapproval, but they never skip the OS sandbox. Remove them with /grants or by hand after migration. |
[] |
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 session journal or durable prompt history (not resumable; composer recall remains memory-only for this process). | false |
global-only | KIN_NO_SAVE |
prompt_history_cap |
Number of interactive composer submissions retained per project for ↑/↓ and ++ctrl+r++ across restarts. Includes model prompts, slash commands, and literal ! command text, but never shell output; headless kin -p prompts are excluded. 0 disables durable loading and writes without deleting the existing store, so re-enabling restores retained entries. Negative or malformed values fall back to 100. --no-save, KIN_NO_SAVE, and no_save = true always make recall memory-only. Human-only (prompt retention is a privacy choice, not a model knob). |
100 |
project-ok | KIN_PROMPT_HISTORY_CAP |
detach |
Run interactive launches as background sessions — /detach leaves the session running, kin in the same folder picks it back up. On by default when tmux ≥ 3.2 is on PATH (DR 0097); set false to opt out. A missing/too-old tmux degrades silently. kin --no-detach / --detach override per launch. Project-ok (it only re-hosts the same process locally — no egress, secret, or containment change). |
on (tmux available) | project-ok | KIN_DETACH |
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 |
update_check |
The session-start update-availability check: one best-effort GET of https://get.kinra.ai/version.json (24h-cached) that renders the one-line “Update available … run: kin update” note. Privacy: the request carries only your kin version in its User-Agent. Default on; opt-out. Project-ok (the endpoint is a constant — a project file can only turn the check off). Explicit kin update / kin doctor runs don’t consult it. |
true |
project-ok | KIN_UPDATE_CHECK |
Appearance
| Key | Meaning | Default | Scope | Env |
|---|---|---|---|---|
theme |
TUI theme name. kin inherits the terminal background; kin-graphite is the opaque Graphite+ fallback. Bare /theme cycles that pair, while an explicit registered Textual theme name is also accepted. The command persists the choice here. Project-ok (pure display — no egress, secret, or containment impact). |
kin |
project-ok | KIN_THEME |
spinner |
The busy-spinner style name (rain · 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). |
rain |
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 prompt usage crosses this fraction of the window (0.1–0.98). The effective trigger is capped below the hard input limit after reserving max_tokens output plus framing margin. |
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 — ranked, chunk-aware lexical full-text search over workspace content (stdlib SQLite FTS5; the complement to grep, not semantic/vector search). Default on; set false to remove it. The index DB lives outside the workspace under ~/.kin/index/. Project-ok (a local index only — no network/egress/secret). |
true |
project-ok | KIN_SEARCH_ENABLED |
shelf_enabled |
Enable edge-triggered shelf board hints and the TUI’s fixed-refspec returned-branch watcher. | true |
project-ok | KIN_SHELF_ENABLED |
shelf_watch_interval |
Seconds between TUI probes of refs/heads/shelf/*; read once at mount and clamped to a 30-second minimum. |
120 |
project-ok | KIN_SHELF_WATCH_INTERVAL |
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 |
rig_enabled |
Register the Rig tool family when URL and token are also configured. Project-ok because it can only remove the tools; the endpoint and credential remain global-only. | true |
project-ok | KIN_RIG |
rig_url |
Rig’s semantic API origin. Global-only so a cloned project cannot redirect a bearer-authenticated tool to a hostile endpoint. | none | global-only | KIN_RIG_URL |
rig_token |
Rig bearer credential, masked on every settings surface. Containers normally use KIN_RIG_TOKEN_FILE. |
none | global-only | KIN_RIG_TOKEN |
browser_enabled |
Legacy no-op retained for migration-safe settings validation. | true |
project-ok | KIN_BROWSER |
browser_allow_private |
Legacy no-op retained for migration-safe settings validation. Use the explicit task rig:local operator path for local/private targets. |
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 terminal clean kin -p stop with no pending human gate 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 |
Deprecated no-op retained so existing settings files keep loading. Ordinary SSH uses shell; KIN_SSH_HOSTS is no longer read. |
[] |
global-only | — |
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 |
|---|---|---|---|---|
agent_stall_timeout |
Seconds without model/tool activity before an active, non-paused task agent becomes advisory stale. Staleness regains the MCA’s attention but never cancels or restarts the child. Human-only and clamped to 30–3600 seconds. |
120 |
project-ok | KIN_AGENT_STALL_TIMEOUT |
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 theread_settings/propose_settingstools. 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,modelHuman-only (refused, hand-edit this file) mode,sandbox,sandbox_strict,sandbox_grants,sandbox_always_allow,git_host_grants,shell_allowlist(containment/trust);api_key,base_url,brave_api_key(secrets/endpoints);provider,wire_api,provider_preset,provider_tiers,providers,model_favorites,model_routes,model_assignments(presets/routes);reasoning_effort(cross-wire conflict — useeffortwhich 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_settingsmasks 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/modeand/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_grants, sandbox_always_allow, git_host_grants, shell_allowlist,
session_dir, no_save, brave_api_key,
provider_preset, providers, provider_keys, provider_tiers, model_favorites,
model_routes, model_assignments, sandbox_network, ssh_hosts,
browser_allow_private, rig_url, rig_token, 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, sandbox_network, the
legacy sandbox_default, shell_allowlist), grant itself typed sandbox
authority (sandbox_grants) or trusted Git credential use
(git_host_grants), redirect the bearer-authenticated Rig
or outpost/outpost-send tools to a hostile
endpoint (rig_url / outpost_url), redirect where sessions land
(session_dir, no_save, brave_api_key), or route your global api_key
through a third-party endpoint (provider_preset + providers +
provider_keys), or assign prompts and images to one of those endpoints
(model_routes + model_assignments). Keeping them global-only means a checkout can’t silently
retarget your endpoint, authorize its own remote route, route your key through
an attacker-controlled host, or weaken your safety posture.
sandbox_always_allow and ssh_hosts remain in the set only as inert
migration-compatible data. The exact denylist and the layering rules are
documented in the repo’s
REFERENCE.md § Settings & config layering.
Secrets (api_key, provider_keys, brave_api_key, outpost_token, and
rig_token) belong to Kin’s global credential store at
~/.kin/credentials.toml, which is created mode 0600 and never committed.
Use Kin’s key prompts instead of editing it. A legacy secret in global
settings.toml remains readable and migrates on the next settings write.