Configuration¶
kata configuration is split between environment variables, committed workspace bindings, local per-machine overrides, and daemon config.
Environment variables¶
| Variable | Meaning |
|---|---|
KATA_HOME |
Data directory. Defaults to ~/.kata. |
KATA_DSN |
Explicit database DSN. Production storage currently accepts a bare SQLite path or sqlite://.... Postgres URLs are recognized but rejected by normal store opening until backend domain methods land. |
KATA_DB |
Legacy explicit SQLite database path. Used when KATA_DSN is unset. |
KATA_AUTHOR |
Default actor for mutations. |
KATA_SERVER |
Remote daemon URL. Skips local discovery and auto-start. |
KATA_AUTH_TOKEN |
Bearer token for daemon API auth. |
KATA_TRUST_PRIVATE_NETWORK |
Set to 1 to permit trusted plaintext bearer use on private non-loopback HTTP. |
KATA_ALLOW_UNAUTHENTICATED_PRIVATE_NETWORK_WRITES |
Set to 1 to permit tokenless writes and event streams on a literal private-IP daemon bind. |
KATA_ALLOW_INSECURE |
Set to 1 or true to allow a configured remote daemon hostname over plain HTTP. Federation uses kata federation enroll --allow-insecure and kata federation join --allow-insecure instead because enrollment credentials are stored separately. |
KATA_TELEMETRY_ENABLED |
Set to 0 to disable anonymous PostHog telemetry. |
KATA_HTTP_TIMEOUT |
Per-request CLI timeout for non-streaming daemon calls, such as 30s or 2m. Defaults to 5s; raise it for bulk imports. |
KATA_GITHUB_TOKEN |
Default explicit token source for GitHub sync when no matching [[github_sync.app]] credential is configured. It is scoped to github.com unless [github_sync].token_host names a different host. [github_sync].token_env can name a different env var. |
KATA_GITHUB_SYNC_ALLOWED_HOSTS |
Comma-separated exact GitHub Enterprise hostnames trusted for GitHub sync and git-remote inference. github.com is always trusted. |
KATA_FEDERATION_PULL_INTERVAL_MS |
Federation runner poll interval for tests or latency-sensitive private deployments. |
PORT |
Hosted-mode listener port when no explicit listener is configured and the daemon is not an auto-start child. |
XDG_RUNTIME_DIR |
Runtime socket parent on Unix when applicable. |
Database selection¶
kata resolves its database in this order:
KATA_DSNKATA_DB[storage].dsnin<KATA_HOME>/config.toml<KATA_HOME>/kata.db
Bare paths and sqlite:// DSNs select SQLite. postgres:// and
postgresql:// DSNs are reserved for the incomplete Postgres backend and are
not selectable by normal daemon/CLI store opening yet. KATA_DB stays ahead of
[storage].dsn so existing shells and scripts keep using their explicit
database path after the config-file key is introduced.
KATA_DSN and [storage].dsn are shape-validated before use. Unknown schemes
are rejected, and common Postgres-only query parameters on a bare path or
sqlite:// DSN are treated as likely formatting mistakes. Validation is local:
it does not dial Postgres or stat SQLite paths.
Workspace binding¶
.kata.toml is committed with the project:
It should stay secret-free.
Local override¶
.kata.local.toml is gitignored. Use it for machine-specific daemon routing:
KATA_SERVER wins over the local file unless a command passes
--daemon <name>.
Daemon target resolution order is:
--daemon <name>KATA_SERVER.kata.local.toml[server].urlactive_daemonin<KATA_HOME>/config.toml- local daemon discovery or auto-start
Committed .kata.toml files bind the project name only; do not put daemon
routing or tokens there.
For trusted private-network hostnames that cannot be represented as literal non-public IP addresses, opt in per target:
Daemon config¶
<KATA_HOME>/config.toml can configure storage, listener, auth behavior, and
named daemon targets:
listen = "100.64.0.5:7777"
active_daemon = "shared"
[[daemon]]
name = "shared"
url = "http://100.64.0.5:7777"
token_env = "KATA_SHARED_TOKEN"
[storage]
dsn = "/var/lib/kata/kata.db"
[auth]
token = "change-me"
trust_private_network = true
[github_sync]
token_env = "KATA_GITHUB_TOKEN"
token_host = "github.com"
[[github_sync.app]]
host = "github.com"
owner = "example-org"
app_id = 12345
installation_id = 67890
private_key_path = "/var/lib/kata/github-app.pem"
The kata daemon start --listen <host:port> flag wins over the config file.
Plain kata daemon start starts the daemon in the background and returns after
startup is confirmed; use kata daemon start --foreground for service-manager
and hosted deployments. Auto-started daemons also read the config-file listener
value.
An empty [storage].dsn means "no storage override"; env vars or the default
database path still apply.
[github_sync] controls daemon-side GitHub credentials. The recommended shared
daemon path is [[github_sync.app]], matched exactly by normalized (host,
owner). The GitHub App needs only Metadata read and Issues read permissions.
If no App matches a binding, kata reads the environment variable named by
[github_sync].token_env (default KATA_GITHUB_TOKEN) only when the binding
host matches [github_sync].token_host (default github.com). If no host-bound
env token matches, kata falls back to gh auth token --hostname <host> for
local/single-user deployments. GitHub Enterprise hosts still must be listed in
KATA_GITHUB_SYNC_ALLOWED_HOSTS, and Enterprise env-token deployments should
set both token_env and token_host.
For a single-user private network where the private IP itself is the access
boundary, omit token and use:
This permits writes and event streams without bearer auth, with client-supplied
actor attribution. It requires a literal private-IP bind and cannot be combined
with token, require_token_identity, or --insecure-readonly; token
administration endpoints remain blocked.
Postgres DSNs may carry credentials. Although they are not selectable yet, runtime redaction handles both URL and libpq keyword forms defensively; userinfo and query parameters are stripped before display or hashing.
Token identity mode¶
For a shared daemon where each user should have stable attribution:
Create per-user tokens before requiring token identity:
export KATA_AUTH_TOKEN=bootstrap-admin-token
kata tokens create --actor wesm --name laptop
kata tokens list
kata tokens revoke 1
tokens create prints plaintext once. The daemon stores only a SHA-256 hash.
Lost tokens must be revoked and recreated.
In identity mode, the bootstrap/admin token can manage tokens and perform reads, but attributed writes require a DB-backed token. The daemon derives the actor from that token.
Close throttle¶
kata refuses structurally dangerous close patterns. The parent-completeness guard always refuses closing an issue while it has open children. Normal CLI and API close paths also require close evidence and a substantive message.
By default, kata does not throttle sibling close bursts. Operators who want stricter pacing can enable two additional guards daemon-wide:
- sibling-burst: closing more than three sibling issues within the configured window is refused;
- repeated-message: closing a second sibling with an identical
doneoraudit-no-changemessage within thirty minutes is refused.
Enable the optional throttles with:
enabled defaults to false. window controls only the sibling-burst lookback
and defaults to "60s"; use Go duration syntax such as "30s", "2m", or
"1h". When a sibling-burst close is refused, the error message reports the
resolved window.
Normal CLI and API close paths still run the parent-completeness refusal, message-substance checks, and evidence checks. The TUI close path skips the message-substance and evidence checks because an interactive human confirms each close; the structural guards still apply.
Semantic search¶
This section is the field reference; see the Semantic search guide for setup and behavior.
Semantic (vector) search is opt-in. With no [search.embeddings] section,
kata search behaves exactly as before — lexical FTS only — and the daemon
makes no embedding network calls. Adding the section enables hybrid search: the
daemon embeds each issue's title and body through an OpenAI-compatible
/embeddings endpoint and fuses vector results with the lexical leg.
[search.embeddings]
base_url = "http://localhost:11434/v1" # any OpenAI-compatible /embeddings
model = "nomic-embed-text"
# api_key = "..." # or api_key_env = "SOME_VAR"; mutually exclusive
# fingerprint_salt = "" # bump to force re-embed when model weights change
# dims # expected vector dimensionality (default 768)
# batch_size # inputs per request (default 64)
# timeout_seconds # per-request timeout (default 30)
# trust_private_network = false # allow plaintext HTTP to literal non-public IPs
base_url and model are both required once the section exists; setting only
one is a startup error rather than a silent disable. api_key and api_key_env
are mutually exclusive. The embedding API key is attached only to requests whose
origin matches base_url, following the same bearer-token trust ladder as
daemon catalog tokens: HTTPS is always allowed, HTTP to loopback is allowed, and
HTTP to other private IPs needs trust_private_network = true.
Privacy: configuring an endpoint sends issue titles and bodies to it on every embed. That is the consent boundary — the operator who writes this section authorizes the data flow. For sensitive projects, prefer a local endpoint (for example Ollama on loopback) so issue text never leaves the host. Embeddings are local derived state and do not federate: each daemon embeds only what it stores, and no vectors are sent to or pulled from federated hubs.
The daemon keeps the index fresh on its own: a background reconciler embeds new
and edited issues within seconds, and kata reports its state under
embeddings in the /health response (configured, last_success_at,
last_error_status, embedded, skipped, and backlog). During a backfill it also
reports started_at and last_progress_at, then adds a smoothed
rate_per_second and eta_seconds after two positive progress samples. Search
never blocks on embedding lag — an issue is findable lexically the instant it
is created, and gains semantic recall once the reconciler catches up.
Issue text is chunked before embedding rather than embedded as a single truncated vector, so long issues get full semantic coverage instead of losing everything past a fixed length cutoff.
Embeddings live in a SQLite sidecar database the daemon creates next to the
main database the first time this section is configured, named after it —
kata.vectors.db for the default kata.db. It holds only derived state and
is safe to delete at any time — the daemon rebuilds it by re-embedding on
the next reconcile — so exclude it from backups; back up kata.db as usual.
Upgrading to a kata version that changes embedding storage re-embeds every
issue from scratch on the first daemon start after the upgrade. The rebuilt
index starts serving immediately, so search returns partial semantic results
while the backfill drains; the embeddings backlog in /health reports the
remaining coverage. An ordinary reconciler backlog with an active index does
not degrade search — fresh or edited issues simply lack semantic recall
until they are embedded. Search degrades (labeled in auto mode, 503 for
explicit --hybrid/--semantic) only when the vector leg is unavailable:
no index has been activated yet (a fresh sidecar before the first reconcile
cycle) or the model changed and its replacement index is still backfilling.
Changing model, dims, or fingerprint_salt builds a new index generation
in the background and cuts over automatically once it finishes filling.
During that backfill the vector leg is unavailable — queries embedded under
the new model cannot be scored against the old generation's vectors — so
auto searches degrade to labeled lexical results and explicit
--hybrid/--semantic requests return 503 until the cutover.
Telemetry¶
kata sends limited anonymous telemetry to PostHog when the daemon starts, and
then emits an in-process daemon_active heartbeat once per UTC day while the
daemon keeps running. Restarting the daemon may send another heartbeat; kata
does not store heartbeat state in the database.
The events are daemon_started and daemon_active with project_count,
application=kata, build version, commit, OS/arch, source, and the database's
stable anonymous instance_uid as the distinct ID. They do not send project
names, issue refs, issue content, comments, labels, paths, or actor names. GeoIP
collection is disabled and PostHog person-profile processing is explicitly
turned off. Use distinct daemon_active counts for active-install reporting;
daemon_started is only for startup-volume diagnostics.
Disable telemetry with:
Federation credentials¶
Federation enrollment tokens are separate from daemon API tokens. The hub stores only token hashes. A spoke stores the plaintext enrollment token in its local federation credentials file so it can call hub federation transport routes.
Do not put federation enrollment tokens in .kata.toml.
Hosted mode¶
When PORT is set and no explicit listener is configured, a foreground daemon
binds 0.0.0.0:$PORT. Hosted mode still requires daemon API auth and explicit
private-network trust. See Hosted mode.