Skip to content

Configuration Wizard

Daniel Ellison edited this page Sep 3, 2026 · 1 revision

Configuration Wizard

make config (which runs python -m kai install config) is an interactive question-and-answer that gathers every setting Kai needs and writes them to install.conf in the project root. In protected mode a separate sudo make install step then reads that file and lays the deployment down on disk; in single-user mode the wizard writes the runtime files directly and there is no apply step. This page explains every prompt the wizard asks: what it controls, what to enter, and when each prompt appears or is skipped.

The wizard is re-runnable. If install.conf already exists from a previous run, its values become the new defaults, so re-running only asks about changes. Hit Enter at any prompt to accept the shown default.

How prompts are gated

A handful of prompts only appear under specific conditions. Five gates account for almost all the conditional behavior:

  • Deployment mode. The first prompt selects protected (root-owned install, sudo make install apply step) or single_user (run from the cloned repo, no root). The Installation paths section only appears in protected mode, protected mode makes the per-user OS isolation prompts required rather than optional, and the wizard's closing instructions differ per mode.
  • Client mode. The second prompt selects which client surfaces the install serves: hybrid, workshop-only, or telegram-only. Everything Telegram-specific (the bot token, the Telegram user setup, the transport prompts, voice, and TTS) is skipped when Telegram is disabled, and the Workshop LAN address prompt is skipped when Workshop is disabled. A fresh workshop-only install additionally gets the Initial Workshop admin block.
  • users.yaml exists. When the canonical users.yaml is present (/etc/kai/users.yaml in protected mode, ${XDG_CONFIG_HOME:-~/.config}/kai/users.yaml in single-user mode), the wizard skips the Telegram user setup block and leaves the file untouched. A stray users.yaml in the project root is ignored with a note telling you to move or remove it.
  • Default backend. Backend-specific prompts appear only for the selected backend: Codex auth mode, reasoning effort, and turn deadline override on codex; the LLM provider on the multi-provider backends (goose, opencode, pi); the provider API key on goose; autocompact and effort level on claude. There is no binary-path prompt for any backend; the install step discovers binaries and records them in /etc/kai/backends.yaml.
  • Memory enabled and extraction enabled. Memory tunables are nested two layers deep: most appear only when semantic memory is turned on, and the extraction tunables appear only when extraction is also turned on.

Each section below notes the gate that controls it.

Sections, in order

  1. Deployment mode
  2. Client mode
  3. Installation paths
  4. Telegram
  5. User setup
  6. Initial Workshop admin
  7. Telegram transport
  8. Default backend
  9. Agent
  10. Webhook server
  11. Workspaces
  12. Model catalogue
  13. PR review agent
  14. Optional features
  15. Semantic memory
  16. External services

Deployment mode

Deployment mode

Which installation shape to configure.

  • Default: protected
  • Valid: protected, single_user
  • Guidance: protected is the production shape: root-owned install at the install location, secrets under /etc/kai/, a service definition, and a sudo make install apply step. single_user runs Kai directly from the cloned repo under your own account: the wizard writes .env to the project root and users.yaml under ${XDG_CONFIG_HOME:-~/.config}/kai/, and you start the daemon with make run. Pick single_user to evaluate Kai or for a personal dev setup; pick protected for an always-on service.

If you pick single_user on a host that still has a readable /etc/kai/env from a previous protected install, the wizard refuses and tells you to remove the protected leftovers first (sudo rm -rf /etc/kai and sudo rm -f /etc/sudoers.d/kai). The runtime would otherwise keep booting from the protected files and silently ignore the single-user ones.


Client mode

Enabled clients

Which client surfaces this install serves. Writes KAI_ENABLED_ADAPTERS.

  • Default: derived from the existing KAI_ENABLED_ADAPTERS value; hybrid on a fresh install
  • Valid: hybrid, workshop-only, telegram-only
  • Guidance: hybrid serves both the Workshop browser client and Telegram. workshop-only drops the Telegram application entirely; the wizard notes that the bot token will be omitted, and no Telegram prompts appear. telegram-only disables the Workshop client routes. Changing modes later means re-running make config; see the Workshop Operator Guide for what each mode serves.

This answer gates large parts of the rest of the wizard: everything under Telegram, User setup, Telegram transport, and the voice prompts requires Telegram; the Workshop LAN address prompt requires Workshop.


Installation paths

Protected mode only. In single-user mode the install and data directories are the project root and the service user is your own account; none of these prompts appear.

Install location

Where Kai's source code, virtual environment, and launcher script live after sudo make install. Owned by root and read-only to the service user.

  • Default: /opt/kai
  • Valid: any absolute path
  • Guidance: the default is fine on both macOS and Linux. The only reason to change it is if /opt is on a small partition or you have a site convention putting third-party services elsewhere. Whatever you pick, make install writes there as root.

Data directory

Where runtime data lives: the SQLite database (which holds the canonical Workshop event store), logs, conversation history, per-user memory and preference files, per-user home workspaces, file uploads.

  • Default: /var/lib/kai
  • Valid: any absolute path
  • Guidance: the default follows the FHS convention for service data on Linux and works equally well on macOS. The data directory is intentionally separate from the install directory so reinstalls cannot destroy your conversation history or memory. If you change it, make sure the chosen path is on a volume with enough room for logs and the database to grow.

Service user

The OS user the daemon runs as.

  • Default: kai
  • Valid: any non-empty username
  • Guidance: use a dedicated, low-privilege account. Create it ahead of time (dscl . -create on macOS, adduser on Linux) and let sudo make install set ownership of the install and data directories accordingly. In protected mode every interactive user's agent must run under a different account than this one; the wizard enforces that below.

Platform

Which service definition to install: a launchd plist on macOS, or a systemd unit on Linux.

  • Default: auto-detected from sys.platform
  • Valid: darwin, linux
  • Guidance: accept the auto-detected value unless you are deliberately preparing a config for a different host. Cross-platform configs do not transplant cleanly because path conventions and service tooling differ.

Telegram

Telegram-enabled modes only.

Telegram bot token

The auth token Telegram issues when you create a bot.

  • Default: none (required)
  • Valid: the token string from BotFather, in the form 1234567890:ABC...
  • Guidance: create a bot by messaging @BotFather and running /newbot. Paste the token here. The token is a secret; the wizard writes it to install.conf with mode 0600 and the install step redeploys it to the runtime env file. In workshop-only mode this prompt does not appear and no token is stored.

User setup

Telegram-enabled modes, first run only. The wizard checks for the canonical users.yaml (/etc/kai/users.yaml in protected mode, ${XDG_CONFIG_HOME:-~/.config}/kai/users.yaml in single-user mode); when it exists the wizard skips this block and leaves the file untouched.

Admin Telegram ID

The numeric Telegram user ID of the admin who will be the first user authorized to talk to the bot.

  • Default: none (required)
  • Valid: a positive integer
  • Guidance: message @userinfobot on Telegram to find your numeric ID. The wizard rejects anything that is not a positive integer; usernames are not accepted.

Admin display name

A short label for the admin entry in users.yaml.

  • Default: admin
  • Valid: letters, digits, spaces, hyphens, underscores
  • Guidance: any short name works. It shows up in listings and some log lines; it is not used for authentication.

OS user for subprocess isolation

Which OS account the admin's agent subprocess runs under. The shape of this prompt depends on deployment mode:

  • Protected mode: required, no default. The wizard prints "Protected mode requires a distinct OS account for each interactive user" and loops until you supply a valid username that differs from the service account. The service account can read exact protected Kai files through its sudoers rules; an agent running as that identity would inherit those capabilities, so protected mode has no same-user path. The account must exist by the time sudo make install runs; the apply step validates it and aborts before making any change if it does not.
  • Single-user mode: optional, behind a "Configure advanced user options" yes/no (default No). If you opt in, the default is your own $USER and empty skips isolation entirely (the agent spawns in-process with no sudo wrap).

There is no prompt for home_workspace; every user lands in a per-user directory under the data directory, and an admin who wants a different home adds home_workspace: /absolute/path to their entry by hand.

Where the first-time users.yaml is written depends on deployment mode: protected mode stages it under ~/.cache/kai-install/ so sudo make install can copy it into /etc/kai/users.yaml; single-user mode writes the XDG path directly.


Initial Workshop admin

Fresh workshop-only installs only (Workshop enabled, Telegram disabled, no runtime policy yet). This block replaces the Telegram user setup as the way the first human comes to exist.

Admin display name

  • Default: your $USER
  • Valid: letters, digits, spaces, hyphens, underscores

OS user for subprocess isolation

  • Protected mode: required, defaults to your $USER, must differ from the service account; same rules as the Telegram path above.
  • Single-user mode: not prompted; the agent runs as the service user.

The wizard then records an initial-provisioning plan and prints what it means: the first human, their direct channel, and a protected runtime assignment will be created canonically at apply time, and Telegram can be linked later without creating another human. After install, the first enrollment token prints once; copy it before it scrolls away. You provision additional people with the workshop CLI, not the wizard.


Telegram transport

Telegram-enabled modes only. How the bot receives updates from Telegram.

  • Default: polling
  • Valid: polling, webhook
  • Guidance: polling is the right choice for almost every deployment. The bot opens a long-poll connection to Telegram and receives updates over it; no inbound port is exposed to the public internet. Choose webhook only if you have a publicly-routable HTTPS endpoint (with a valid certificate) that Telegram can reach, and you specifically want push delivery instead of pull. See Exposing Kai to the Internet for the reverse proxy setup.

When webhook is selected, two more prompts follow:

Telegram webhook URL

The URL Telegram should POST updates to.

  • Default: none (required when transport is webhook)
  • Valid: an HTTPS URL ending in a path you control
  • Guidance: must be HTTPS with a real certificate (Telegram refuses self-signed). Typically this is https://your-domain/webhook/telegram proxied via Cloudflare Tunnel or a public reverse proxy.

Telegram webhook secret

A secret that Telegram includes in the X-Telegram-Bot-Api-Secret-Token header on each delivery, used to verify the request is from Telegram.

  • Default: empty
  • Valid: any string
  • Guidance: set a long random string. Left empty, the runtime generates a fresh one per process. Whatever you set must differ from the GitHub webhook secret below; the runtime refuses to start when any two ingress secrets match.

Default backend

Which agent runtime drives the inner conversation.

  • Default: the existing configured backend; with no prior value, Enter is only accepted when exactly one backend is installed
  • Valid: whichever of the five supported backends (claude, codex, goose, opencode, pi) are actually installed; the choice list comes from the installed backend registry, or from discovered binaries on a fresh host
  • Guidance: claude uses the Claude Code CLI and benefits from Anthropic's subscription auth. codex uses the OpenAI Codex CLI, also subscription-capable. opencode and goose are multi-provider runtimes driven over ACP; pi is a multi-provider runtime with its own RPC transport and the widest provider list. See Multiple Backends for the trade-offs. If no supported backend is installed at all, the wizard exits with an error naming all five; install one and re-run.

The follow-up prompts depend on the chosen backend. None of them collects a binary path: the install step discovers binaries and writes /etc/kai/backends.yaml, the command-path authority for every backend, whether selected globally or per-user.

Codex auth mode

Codex backend only.

  • Default: subscription
  • Valid: subscription, api_key
  • Guidance: subscription uses the ChatGPT plan login stored by codex login; no API key is collected, and the wizard reminds you to run codex login after install as each target os_user (as that user directly, not via sudo from another account). api_key prompts for OPENAI_API_KEY (required) and bills per token.

LLM provider

Multi-provider backends only (goose, opencode, pi).

  • Default: none (must be selected)
  • Valid: the chosen backend's provider list: anthropic, deepseek, google, ollama, openai, openrouter for goose and opencode; pi adds github-copilot and openai-codex
  • Guidance: pick the provider whose credentials you have. This drives the per-role model registry lookup at runtime. openrouter and ollama are open-ended (any model ID works); ollama needs no API key because it runs locally.

<PROVIDER>_API_KEY

Goose backend only; the variable name shown matches the chosen provider. Skipped for ollama (no key) and skipped entirely for opencode and pi, whose credentials live in their own auth stores (opencode auth login; pi /login as each target OS user, which the wizard reminds you about after install).

  • Default: none (required for paid providers on goose)
  • Valid: the secret string the provider issued
  • Guidance: generate the key in the provider's console. The wizard stores it in install.conf with mode 0600 and the install step writes it into the runtime env file.

If users.yaml contains per-user goose entries on other keyed providers, the wizard also prompts for each of those provider keys here (goose has no own auth store, so the daemon env must carry them; keys added to the env file by hand are wiped on regeneration).


Agent

Installation-wide agent defaults. There is no conversational default-model prompt anymore: the conversational role resolves through the model registry for the chosen backend and provider, per-user models: entries and runtime settings override it, and the retired DEFAULT_MODEL env var is dropped from regenerated configs.

Customize per-role models (PR review, triage, memory, eval)

Optional walk through the six non-conversational roles: PR review, issue triage, memory extraction, memory episode, behavioral judge, behavioral gen.

  • Default: No on a fresh install; Yes when overrides were captured on a previous run
  • Valid: y/n, then one model per role (a curated numbered choice on claude, codex, and goose with a curated provider; free text on opencode and the open-ended providers)
  • Guidance: answer No to use the registry defaults, which are tuned per backend (background roles generally run on a cheaper tier than chat). If you answer Yes, accepting the shown default for a role leaves it on the registry value; only values that differ from the registry default are persisted (as DEFAULT_MODELS_JSON), which sits below per-user models: entries and above the registry in the resolution chain.

Agent timeout (seconds)

How long the inner agent subprocess can go without producing output on one response before Kai gives up on it.

  • Default: 120
  • Valid: any positive integer
  • Guidance: 120 seconds is a sensible starting point for chat. Long-running tool use routinely needs more; bumping to 240-300 is reasonable on a fast machine. Going below 60 risks aborting the model mid-thought on legitimate work. Per-user timeout in users.yaml or runtime settings override it.

Agent turn deadline (seconds)

Total bound on one turn for every backend: the backstop that ends a turn trickling output without completing, since the idle guards reset on any output.

  • Default: 3600
  • Valid: any positive integer
  • Guidance: the generous default exists so legitimate long agentic turns never hit it. Lower it if you want a harder ceiling on how long any single turn can run.

Max session age in hours (0 = no limit)

Recycles a user's agent subprocess once the session is older than this, regardless of activity. Applies to every backend.

  • Default: 0 (no limit)
  • Valid: any non-negative number
  • Guidance: long-lived CLI processes can accumulate memory; a 4-8 hour cap is a reasonable guard on memory-constrained machines. 0 disables age-based recycling entirely. Recycling ends the session; the next message starts fresh.

Idle eviction timeout in seconds (0 disables)

Evicts a user's agent subprocess after this much inactivity. Applies to every backend.

  • Default: 1800
  • Valid: any non-negative integer
  • Guidance: 30 minutes keeps the pool small without making users pay a cold start on every message. Raise it if cold starts annoy you and RAM is plentiful; set 0 to keep subprocesses alive indefinitely.

Autocompact threshold (% of context window, 0 = default ~83%)

The fraction of the active context window at which Claude Code automatically compacts conversation history into a summary. Claude backend only.

  • Default: 80
  • Valid: 0 to 100
  • Guidance: 80 is a good default. Lower values (60-70) compact sooner, which reduces token usage at the cost of losing raw context earlier in long sessions. Values above ~83 are silently clamped by Claude Code. Setting 0 falls back to Claude Code's own default; pin a value here if you want predictable behavior across upstream changes.

Inner Claude effort level

Maps to Claude Code's --effort flag, which trades reasoning depth against latency and token spend. Claude backend only.

  • Default: high
  • Valid: low, medium, high, xhigh, max
  • Guidance: high is the recommended default for everyday work. xhigh and max produce noticeably better answers on hard problems but are slower and burn more tokens. The wizard's allow-list mirrors the runtime allow-list, so it cannot accept a value the daemon would later reject. Claude Code's upstream default has changed over time, so pinning a value here insulates you from future shifts.

Codex reasoning effort

Codex backend only. Empty is a valid answer.

  • Default: empty (codex default)
  • Valid: minimal, low, medium, high, xhigh, or empty
  • Guidance: empty passes no override, so codex falls back to the per-OS-user codex config or the model default; that is usually right because codex config is per OS user and the highest tier is model-dependent. Set a value to pin the reasoning effort install-wide.

Codex turn deadline override (seconds, empty = shared)

Codex backend only.

  • Default: empty (follows the shared agent turn deadline)
  • Valid: a positive integer, or empty
  • Guidance: set only if the codex lane needs a different ceiling than every other backend.

Webhook server

These settings configure Kai's own HTTP server, which serves the /webhook/* and /api/* endpoints and the Workshop client. It always binds the loopback address; nothing here exposes it publicly.

Webhook port

The TCP port the embedded HTTP server binds to.

  • Default: 8080
  • Valid: 1 to 65535
  • Guidance: 8080 works for almost every deployment because the public surface is fronted by Cloudflare Tunnel or a reverse proxy. Ports below 1024 require root, which Kai cannot bind, so anything in the 1024-65535 range is safe.

Workshop LAN address (optional; client routes only)

Workshop-enabled modes only. One private, non-loopback IPv4 address for a second listener carrying only the Workshop client routes, on the same port.

  • Default: empty (loopback only)
  • Valid: a private IPv4 address on this host; loopback, public, multicast, wildcard, and IPv6 addresses are rejected
  • Guidance: set this to reach the Workshop from other devices on a trusted LAN. The wizard warns: Workshop bearer sessions will use plain HTTP on this trusted LAN address; use a TLS terminator for untrusted networks. Webhook ingress and the internal APIs stay on loopback regardless. See the Workshop Operator Guide.

GitHub webhook secret

The secret GitHub signs webhook deliveries with (HMAC-SHA256, verified on /webhook/github).

  • Default: a freshly generated 64-hex-char random value (or the existing stored value on a re-run)
  • Valid: any non-empty string that differs from the Telegram webhook secret
  • Guidance: accept the generated value and paste the same string into the GitHub webhook configuration. The wizard re-rolls the default and re-prompts if it matches the Telegram secret; the runtime exits when any two ingress secrets are equal. If a legacy unified WEBHOOK_SECRET is present, the wizard notes it is no longer supported and omits it from the generated configuration.

The generic webhook secret (GENERIC_WEBHOOK_SECRET, for POST /webhook) is generated automatically with no prompt; read it from the generated env file when configuring generic webhook callers.


Workspaces

Installation-wide defaults; both prompts fire on every wizard run. users.yaml entries can override workspace_base per user.

Workspace base directory

A directory whose immediate subdirectories become valid workspace names. With this set, /workspace foo resolves to <base>/foo without needing the absolute path.

  • Default: empty
  • Valid: any path (absolute or starting with ~; the wizard echoes the expansion)
  • Guidance: point this at your projects parent directory. Leave it blank if you always use absolute paths.

Allowed workspaces (comma-separated paths, optional)

Pinned absolute paths that are always valid workspace destinations even if outside the base.

  • Default: empty
  • Valid: comma-separated absolute paths
  • Guidance: use this for repos under non-standard locations. Each path becomes a one-tap option in the workspace picker. Leave it blank if the base directory covers everything you need.

Model catalogue

Tunables for the durable model catalogue behind runtime model pickers; discovery adapters fetch model metadata per backend.

Periodic refresh interval in seconds (0 disables)

  • Default: 0 (disabled)
  • Valid: any non-negative integer
  • Guidance: 0 means the catalogue refreshes only when asked (from Workshop Settings or python -m kai workshop model-catalogue refresh). Set an interval if you want newly released models to appear in pickers without manual refreshes.

Per-backend refresh timeout in seconds

  • Default: 30
  • Valid: any positive integer
  • Guidance: the cap on one backend's discovery call during a refresh. Raise it only if a backend's model listing is genuinely slow on your host.

PR review agent

There is no enable prompt here: whether reviews run at all is per person (pr_review in users.yaml, the Workshop Settings GitHub section, or /github reviews on|off), and the wizard prints a reminder saying so. Issue triage is likewise per person and has no wizard prompts.

Review cooldown in seconds (prevents spam from rapid pushes)

  • Default: 300
  • Valid: any positive integer
  • Guidance: the wizard still prompts for and stores this setting, but it currently has no runtime effect; Kai dedupes duplicate webhook deliveries by GitHub delivery ID instead. Accept the default.

Review subprocess timeout in seconds

Hard cap on how long a single PR review run may take.

  • Default: 900
  • Valid: any positive integer
  • Guidance: 900 (15 minutes) accommodates large PRs without prematurely cutting off real work. If your PRs are typically small, 300-600 keeps a stuck process from running too long; if they are very large, 1200-1800 may be needed.

Optional features

Voice transcription

Telegram-enabled modes only. Enables inbound voice-message handling: voice notes get transcribed via whisper.cpp and the text is fed into the conversation as if you typed it.

  • Default: No
  • Valid: y/n
  • Guidance: turn this on if you talk to Kai from your phone and want voice input. Requires ffmpeg on the host and the whisper model (gitignored; the wizard does not download it). See Voice Setup.

Text-to-speech

Telegram-enabled modes only. Enables outbound voice replies via Piper TTS.

  • Default: No
  • Valid: y/n
  • Guidance: complement to voice transcription. Off by default because most replies are long enough that text is more useful. See Voice Setup for the Piper model files.

After these prompts the wizard prints a reminder that per-user OS isolation lives in users.yaml (os_user); there is no global subprocess-user prompt.


Semantic memory

Kai's semantic memory layer indexes facts and episodes in Qdrant via Mem0 and surfaces them on every turn. This whole section toggles that subsystem.

Enable semantic memory (Mem0 + Qdrant)

Master switch.

  • Default: No
  • Valid: y/n
  • Guidance: turn it on if you want long-term memory of facts the user shares, prior decisions, and episodes (compact narratives of completed tasks). Off, the bot is purely conversational and forgets everything outside its rolling conversation context. See Memory for how retrieval works.

When memory is enabled, the prompts below appear.

Enable memory extraction (proactive memory writes)

Whether the bot runs a background one-shot model call after each turn to identify and store new facts. Appears when the chosen backend ships a one-shot reasoner (all five do).

  • Default: No
  • Valid: y/n
  • Guidance: turn it on. Without extraction, memory only contains facts saved explicitly; with it, the bot proactively maintains its own memory and quality climbs over time. The extraction reasoner and model resolve per person from each person's effective backend via the model registry; there are no global reasoner or model prompts. The remaining prompts in this section all hang off this answer.

Per-extraction timeout in seconds

Hard cap on a single stage-1 extraction call.

  • Default: 10
  • Valid: any positive integer
  • Guidance: the default of 10 is too aggressive for production. Real extractions routinely take 20-30 seconds, especially on the first call after a cold start, and silently abort at the boundary. Set this to 60 or higher unless you know your extractions complete quickly.

Consolidation candidate count (0 disables consolidation)

How many existing similar facts to show the extractor as context, so it can decide whether a new observation is genuinely new, an update, or redundant.

  • Default: 8
  • Valid: any non-negative integer
  • Guidance: 8 is the validated default. Lower values shrink the extraction payload at the risk of duplicate facts. 0 is a valid kill-switch: the extractor falls back to all-new outputs, useful for debugging the consolidation path.

Episode classifier context turns

How many prior conversation exchanges are shown to the episode classifier as background.

  • Default: 3
  • Valid: 0 to 10
  • Guidance: 3 is enough context for the classifier to recognize multi-turn workflows without ballooning the per-call payload. The 0-10 cap exists so a typo cannot blow past the model's per-call token limit.

Per-episode timeout in seconds (minimum 10)

Hard cap on a single stage-2 episode call.

  • Default: 120
  • Valid: integer of at least 10
  • Guidance: 120 seconds accommodates the model generating all seven episode fields without rushing. Bump to 180-300 if you see persistent timeouts. The 10-second floor exists because model warm-up alone routinely runs several seconds.

Paraphrase-dedup threshold (cosine; 1.0 effectively disables, 1.01 unambiguously)

Write-time duplicate gate: a new fact whose cosine similarity to an existing fact meets this threshold is treated as a paraphrase and not stored again.

  • Default: 0.9
  • Valid: 0.3 to 1.01
  • Guidance: 0.9 catches near-identical rephrasings while letting genuinely new variants through. 1.01 is the unambiguous disable sentinel (no cosine similarity can reach it).

Memory context token budget per turn

Cap on how many tokens of retrieved memory are injected into each conversation turn.

  • Default: 2000
  • Valid: any positive integer
  • Guidance: 2000 balances useful background against displacing the actual conversation. Lower it if memory injection crowds out tool results and recent history; raise it if the bot keeps missing facts that should be in scope.

Memory search result limit per query

Maximum number of results returned by the vector search before the token-budget filter applies.

  • Default: 10
  • Valid: any positive integer
  • Guidance: 10 is the validated default. Increase to 15-20 only if you find specific facts are getting buried.

External services

Perplexity API key (optional)

Lets the inner agent call Perplexity via the /api/services/perplexity proxy for web search and synthesis.

  • Default: empty (Perplexity calls disabled)
  • Valid: the key string from the Perplexity dashboard
  • Guidance: add the key if you want web-search grounded answers with citations. Remember that each person who should reach a service also needs it in their allowed_services list in users.yaml; see External Services.

After the wizard

The wizard writes install.conf to the project root with mode 0600 and prints a closing message that depends on deployment mode.

Protected mode:

Configuration written to <project>/install.conf
Review the file, then run: sudo python -m kai install apply

The next step is sudo make install, which reads install.conf, validates user isolation before touching anything, lays out the file system, generates the runtime env file under /etc/kai/, writes the backend registry, configures sudoers, generates the launchd plist or systemd unit, and starts the service. See Protected Installation for what that step does in detail. On backends with their own auth stores, the wizard's closing notes remind you to log in as each target OS user (codex login, opencode auth login, or pi then /login).

Single-user mode: the wizard additionally writes .env (mode 0600) to the project root and reports where users.yaml lives, then prints:

Single-user mode does not require 'sudo make install'.
Start the daemon with: make run

In both modes you can review install.conf before proceeding, but the right way to change a setting is to re-run the wizard so its validation logic gets to vet the new value.

Clone this wiki locally