Files
kandev/docs/public/configuration.md
T
2026-07-16 08:32:40 +01:00

6.4 KiB

title, description
title description
Configuration Configure Kandev workspaces, runtimes, settings, and environment behavior.

Configuration

Kandev's backend reads configuration from three sources, in this order of precedence (later sources override earlier ones):

  1. Built-in defaults (apps/backend/internal/common/config/config.go).
  2. A YAML config file (config.yaml).
  3. Environment variables (KANDEV_*).

Both the file and env vars are optional; the backend boots with sensible defaults out of the box. See docker.md and k8s.md for deployment-specific tables; this page is the full reference.

Config file

The backend looks for config.yaml in the following order:

  • An explicit path passed at startup (used in tests).
  • The current working directory.
  • /etc/kandev/.

A missing file is not an error - defaults plus env vars take over.

Environment variables

Backend configuration normally uses the KANDEV_ prefix. Nested keys map by replacing . with _ and uppercasing; camelCase becomes one uppercase run (no underscore inserted), because Viper does not synthesize a snake_case form. A small set of explicitly bound compatibility aliases is also supported, including the unprefixed AGENTCTL_PORT.

YAML key Env var
server.port KANDEV_SERVER_PORT
server.webInternalUrl KANDEV_SERVER_WEBINTERNALURL (or alias KANDEV_WEB_INTERNAL_URL)
database.dbName KANDEV_DATABASE_DBNAME
logging.maxSizeMb KANDEV_LOGGING_MAXSIZEMB
homeDir KANDEV_HOME_DIR (alias)
logging.level KANDEV_LOG_LEVEL (alias)
agent.standalonePort AGENTCTL_PORT or KANDEV_AGENT_STANDALONE_PORT (aliases)

The aliases on the right are explicit bindings - see LoadWithPath in config.go for the full list. New keys should follow the deterministic rule (KANDEV_<SECTION>_<KEYUPPERCASE>) unless compatibility requires an explicit alias.

Full config.yaml example

Every key shown here has a default - copying the whole file changes nothing. Use it as a starting point and delete what you don't need to override.

# Kandev root directory. Empty = ~/.kandev (or KANDEV_HOME_DIR if set).
# All workspace artifacts (data, tasks, worktrees, repos, sessions) live here.
homeDir: ""

server:
  host: "0.0.0.0"
  port: 38429              # API + WebSocket + Web UI
  readTimeout: 30          # seconds
  writeTimeout: 30         # seconds
  webInternalUrl: ""       # internal URL the backend uses to call the web app

database:
  driver: "sqlite"         # "sqlite" or "postgres"
  path: ""                 # sqlite: empty = $homeDir/data/kandev.db

  # postgres-only fields below (ignored when driver=sqlite)
  host: "localhost"
  port: 5432
  user: "kandev"           # required when driver=postgres
  password: ""             # required when driver=postgres in most setups
  dbName: "kandev"         # required when driver=postgres
  sslMode: "disable"       # disable | require | verify-ca | verify-full
  maxConns: 25
  minConns: 5

nats:
  url: ""                  # empty = use in-memory event bus
  clusterId: "kandev-cluster"
  clientId: "kandev-client"
  maxReconnects: 10

events:
  namespace: ""            # empty = derive from runtime data identity

docker:
  enabled: true            # disables Docker-based executors when false
  host: ""                 # empty = platform default (unix:///var/run/docker.sock, etc.)
  apiVersion: ""           # empty = auto-negotiate
  tlsVerify: false
  defaultNetwork: "kandev-network"
  volumeBasePath: ""       # empty = /var/lib/kandev/volumes (Linux/macOS)

agent:
  standaloneHost: "localhost"
  standalonePort: 39429    # agentctl control port

auth:
  jwtSecret: ""            # empty = auto-generate a random dev secret on boot
  tokenDuration: 3600      # seconds

logging:
  level: "info"            # debug | info | warn | error
  format: "text"           # accepted values: text | json; omit for environment-based default
  outputPath: "stdout"     # stdout | stderr | /path/to/file.log

  # Rotation - only applied when outputPath is a file path.
  # Active log files are created with mode 0600 (owner-only).
  maxSizeMb: 100           # rotate at this size; 0 = lumberjack default (100MB)
  maxBackups: 5            # 0 = unlimited
  maxAgeDays: 30           # 0 = unlimited
  compress: true           # gzip rotated files

repositoryDiscovery:
  roots: []                # absolute paths to scan for local git repos
  maxDepth: 5

worktree:
  enabled: true
  defaultBranch: "main"
  cleanupOnRemove: true
  fetchTimeoutSeconds: 60
  pullTimeoutSeconds: 60

repoClone:
  basePath: ""             # empty = $homeDir/repos

debug:
  pprofEnabled: false      # enables /debug/pprof and /api/v1/debug/memory

Required vs optional

Almost every field has a default and is optional. The exceptions:

Field When required What happens otherwise
database.user database.driver=postgres Startup fails with database.user is required for postgres driver
database.dbName database.driver=postgres Startup fails with database.dbName is required for postgres driver
database.password database.driver=postgres in most setups (some Postgres configs allow passwordless local auth) Connection fails at runtime
auth.jwtSecret Never strictly required, but in production set an explicit value A random secret is generated on boot - tokens become invalid on restart

Validated value sets (any other value is a startup error):

Field Allowed values
server.port 1-65535
database.driver sqlite, postgres
database.port 1-65535 (only validated when driver=postgres)
database.sslMode disable, require, verify-ca, verify-full (only validated when driver=postgres)
logging.level debug, info, warn, error
logging.format json, text

Tips

  • Env vars override the file. Useful for secrets (KANDEV_DATABASE_PASSWORD) and per-environment knobs (KANDEV_LOG_LEVEL).
  • K8s / Docker: prefer env vars for everything; skip the YAML file entirely.
  • Local dev: drop a config.yaml next to where you run the backend; viper picks it up from the current working directory.
  • Format auto-detection: when logging.format is omitted, Kandev defaults to json if KANDEV_ENV is production/prod or KUBERNETES_SERVICE_HOST is set; otherwise it defaults to text. The literal value auto is not accepted.