Skip to content

Configuration

All configuration is in a single TOML file at ~/.config/caic/config.toml. See contrib/config.toml for a documented template.

Quick start

The install script creates a default config.toml automatically. To customize:

bash
$EDITOR ~/.config/caic/config.toml

caic watches config.toml for changes and restarts automatically when the file is saved.

Without a config file, caic starts with sensible defaults: listens on localhost:2242, uses the current directory as root, and auto-detects the GitHub token from gh auth token.

CLI flags

FlagDefaultDescription
-config-dir~/.config/caicOverride the config directory.
-print-urlPrint the server URL and exit. Verifies the port is available.
-versionPrint version and exit.

Directories

caic uses two directories, following the XDG Base Directory convention:

DirectoryDefaultEnv overrideContents
Config~/.config/caic/XDG_CONFIG_HOMEconfig.toml, settings.json, users.json, preferences.json, PEM keys, MMDB files
Cache~/.cache/caic/XDG_CACHE_HOMETask logs, CI cache, harness model cache

Relative paths in the config file (e.g. geo_db, app_private_key_pem) are resolved against the config directory.

Config reference

[core]

KeyDefaultDescription
root"."Parent directory containing git repositories managed by caic. Tilde (~) is expanded to the user's home directory
auto_update"50 4 * * *"Cron schedule for auto-update (checks GitHub Releases). Set to "" to disable
runtimeauto-detectContainer runtime: "docker" or "podman". When unset, caic detects the installed runtime. Podman runs rootless

[core.env]

Environment variables inherited by the server process. Falls back to the host environment when not set.

KeyPurpose
TAILSCALE_API_KEYTailscale API key for ephemeral container nodes. Obtain from Tailscale admin
GEMINI_API_KEYGemini API key for voice agent (WebRTC bridge) and title generation. Obtain from Google AI Studio
HTTP_PROXY / HTTPS_PROXY / NO_PROXYProxy settings for forge API calls (GitHub, GitLab) when the server is behind a corporate proxy
ANTHROPIC_API_KEY / OPENAI_API_KEY / etcOptional API keys for LLM generated commit description
toml
[core]
root = "~/projects"
runtime = "podman"

[core.env]
TAILSCALE_API_KEY = "tskey-api-..."
GEMINI_API_KEY = "AIza..."

Auto-update

When enabled, caic checks GitHub Releases on the given cron schedule and replaces the binary in place when a new version is found. The binary self-update triggers the config watcher, causing a restart with the new version.

toml
[core]
# Disable auto-update:
auto_update = ""

Preferences

~/.config/caic/preferences.json stores per-user settings (resource limits, cache configuration, auto-fix behavior, per-repository preferences) independent of config.toml. Edit it directly or through the settings UI.

[server]

KeyDefaultDescription
http":2242"HTTP listen address. Port-only addresses (:2242) bind to localhost. Use "0.0.0.0:2242" to listen on all interfaces
external_url"auto"Public base URL. "auto" locks from the first FQDN request. Set explicitly for OAuth and webhooks
webrtc_port0UDP port for WebRTC ICE. 0 = enabled with ephemeral port; -1 = disabled. Requires GEMINI_API_KEY in core.env. Open this port for UDP traffic if using a static port
geo_dbPath to a MaxMind GeoLite2 MMDB file for country-code resolution. If unset and GeoLite2-Country.mmdb exists in the config directory, it is used automatically
allow_origins["local", "tailscale", "github"]Allowlist for incoming HTTP requests. Unmatched IPs get HTTP 403

external_url rules

  • "auto" (default): hostname locked from the first request with a fully qualified domain name
  • Explicit value: must be a valid URL with a host and no path (e.g. https://caic.example.com). Trailing slashes are stripped
  • When OAuth is configured and explicit: must use https://

allow_origins values

ValueMatches
"local"Loopback and RFC 1918 private addresses
"tailscale"Tailscale CGNAT range (100.64.0.0/10)
"github"GitHub webhook IPs (fetched live from api.github.com/meta)
CIDR rangee.g. "203.0.113.0/24"
Country codeISO 3166-1 alpha-2 (e.g. "CA", "US"); requires geo_db
toml
[server]
geo_db = "GeoLite2-Country.mmdb"
allow_origins = ["local", "tailscale", "github", "CA"]

[ai]

LLM provider for title generation and commit descriptions.

KeyDefaultDescription
providerauto-detectProvider name. When unset, probes in this order: codex, opencode, claudecode, gemini, then any other available provider
modelcheapestModel name or alias. Uses the provider's cheapest model when unset

Available providers: see the genai providers package.

When provider is gemini, the GEMINI_API_KEY from [core.env] is used automatically.

toml
[ai]
provider = "gemini"
model = "gemini-2.5-flash"

[harness]

Per-harness environment variables injected into containers. Each harness has its own [env] table of KEY = "VALUE" pairs. These supplement the automatic *_API_KEY forwarding and are also used when refreshing model lists at startup.

toml
[harness.claude.env]
ANTHROPIC_API_KEY = "sk-..."

[harness.codex.env]
# Codex configuration is primarily via its own config file:
# https://developers.openai.com/codex/config-reference

[harness.opencode.env]
# OpenCode configuration: https://opencode.ai/docs/config/

[harness.pi.env]
DEEPSEEK_API_KEY = "sk-..."
GEMINI_API_KEY = "AIza..."
OPENROUTER_API_KEY = "sk-or-..."

Available harness names: claude, codex, gemini, kilo, opencode, pi.

[github]

See GitHub Integration for full setup instructions.

KeyDefaultDescription
tokenPersonal access token. Mutually exclusive with oauth_client_id. Falls back to gh auth token when unset and OAuth is not configured
oauth_client_idOAuth app client ID. Mutually exclusive with token
oauth_client_secretOAuth app client secret. Required when oauth_client_id is set
oauth_allowed_usersGitHub usernames permitted to log in. Required when OAuth is configured
app_idGitHub App ID. Independent of PAT/OAuth
app_private_key_pemPath to GitHub App PEM private key file. Relative to the config directory
app_allowed_ownersGitHub orgs/users allowed to install the app. Installs from other accounts are rejected
webhook_secretHMAC-SHA256 secret for webhook verification. Generate with openssl rand -hex 32

[gitlab]

See GitLab Integration for full setup instructions.

KeyDefaultDescription
tokenPersonal access token (scope: api). Mutually exclusive with oauth_client_id
oauth_client_idOAuth app client ID. Mutually exclusive with token
oauth_client_secretOAuth app client secret. Required when oauth_client_id is set
oauth_allowed_usersGitLab usernames permitted to log in. Required when OAuth is configured
url"https://gitlab.com"GitLab instance URL. Must be a valid URL with no path
webhook_secretShared secret for webhook verification. Generate with openssl rand -hex 32

[debug]

KeyDefaultDescription
log_level"info"Log verbosity: debug, info, warn, error
no_log_timefalseOmit timestamps from log output. Useful under systemd
pproffalseExpose /debug/pprof/* profiling endpoints
cpuprofileWrite CPU profile to this file path
memprofileWrite heap profile on shutdown
traceWrite execution trace to this file path

Environment variables

VariablePurpose
GEMINI_API_KEYFallback when [core.env] GEMINI_API_KEY is not set
TAILSCALE_API_KEYFallback when [core.env] TAILSCALE_API_KEY is not set
XDG_CONFIG_HOMEOverride the config base directory (default: ~/.config)
XDG_CACHE_HOMEOverride the cache base directory (default: ~/.cache)

HTTPS exposure

Setting external_url explicitly is recommended for OAuth login and webhooks so redirect URIs and callback URLs are stable. Webhooks additionally require the forge (GitHub/GitLab) to reach caic from the internet.

Tailscale Serve (private, tailnet only)

bash
tailscale serve --bg 2242

Tailscale Funnel (public, webhooks supported)

bash
tailscale funnel 2242

With Tailscale, set external_url to your tailnet hostname:

toml
[server]
external_url = "https://<hostname>.<tailnet>.ts.net"

Caddy + DDNS (home server)

<your-domain> {
    reverse_proxy localhost:2242
}
toml
[server]
external_url = "https://<your-domain>"

For dynamic DNS, ddns-updater works well with Caddy.