Skip to main content

Configuration Reference

Digitorn loads configuration from (in order of increasing priority):

  1. Built-in defaults (hardcoded)
  2. System config: /etc/digitorn/config.yaml
  3. User config: ~/.digitorn/config.yaml
  4. Environment variables: prefixed with DIGITORN_

Nested env vars use double underscore as separator:

DIGITORN_SERVER__PORT=8000
DIGITORN_DATABASE__URL=postgresql+asyncpg://user:pass@localhost/digitorn

server (13 params)

ParameterTypeDefaultDescription
hoststring"127.0.0.1"Server bind address
portint8000Server port (1024-65535)
workersint1Uvicorn worker count (1-16)
reloadboolfalseAuto-reload on code changes
rate_limit_rpmint100000Default requests per minute per app (1-100000). Effectively disabled - set to the upper bound. Specific buckets (auth, admin, deploy) still have their own tighter caps enforced at the route layer.
expose_docsboolfalseExpose Swagger UI (/docs), ReDoc (/redoc), and /openapi.json. Automatically true when auth_enabled is false (dev mode). Leave off in production.
kv_backendstringnullKV backend URL. redis://host:6379/0 for production. Default (null) uses DiskCache (SQLite-backed, single-host).
auth_enabledbooltrueEnable JWT/API-key authentication on all API endpoints
turn_workersint32Thread pool size for agent turns (1-512)
io_workersint64Thread pool size for blocking I/O (1-1024)
sandboxbooltrueEnable OS-level sandbox for deployed apps (Landlock/seccomp on Linux, Seatbelt on macOS, Job Objects on Windows)
node_auto_installbooltrueAuto-download Node.js LTS runtime if missing (PATH / nvm / fnm / volta are checked first). Disable in air-gapped or CI environments.
cors_originslist[str]localhost variantsAllowed CORS origins. Wildcard * is rejected.

database (3 params)

ParameterTypeDefaultDescription
urlstring"sqlite+aiosqlite:///digitorn.db"SQLAlchemy async database URL (SQLite, PostgreSQL, MySQL)
echoboolfalseEcho SQL statements to stdout (debug only)
pool_sizeint5Connection pool size (1-50, ignored for SQLite)

auth (9 params)

ParameterTypeDefaultDescription
access_token_ttlint0Access token lifetime in seconds. 0 = never expires (no exp claim). Default is 0 for local-dev ergonomics - set to a positive value (e.g. 900 for 15 min) in production.
refresh_token_ttlint0Refresh token lifetime in seconds. 0 = never expires. See access_token_ttl for rationale.
max_login_failuresint5Lock account after N failed login attempts (1-100)
lockout_windowint900Lockout window in seconds (60-86400)
approval_timeoutfloat3600.0Time to wait for user approval before auto-deny (10-7200s). Override per-app via the compiled security_profile.approval_timeout.
modestring"embedded"Must be set to "remote" when auth_enabled=true. The schema default "embedded" is rejected at startup - the daemon never signs tokens, only verifies.
service_urlstring""Base URL of the central digitorn-auth service (e.g. https://auth.digitorn.ai). Required when mode='remote'.
accept_issuerslist[str][]Extra iss claim values the daemon accepts (cluster + edge proxy + dev loopback).
enable_local_deviceboolfalseLoad LocalDeviceAuth secrets at daemon start and run the device revalidator background task. Requires the daemon to have been paired via digitorn install-local. Only meaningful in mode='remote'.

session (6 params + queue sub-section)

ParameterTypeDefaultDescription
idle_ttlint1800Session expires after N seconds of inactivity (default: 30 min). 0 = never expire.
absolute_ttlint86400Session expires after N seconds regardless of activity (default: 24h). 0 = never expire.
max_events_per_turnint500Safety cap on events emitted per turn (50-5000)
max_sessions_per_appint100Max active sessions per deployed app (1-10000)
lock_timeoutfloat600.0Seconds a new turn waits for the session lock before returning session_busy (5-3600). When the queue is enabled, incoming messages queue instead of erroring out.
approval_timeout_sfloat300.0How long an agent waits for a user to resolve an approval request before auto-denying (5-86400s). Apps with a compiled security_profile.approval_timeout override this default.

Disabling session expiry: Setting idle_ttl: 0 or absolute_ttl: 0 disables the respective timeout - sessions become permanent until explicitly deleted. The built-in defaults are idle_ttl: 1800 (30 min) and absolute_ttl: 86400 (24h). Set both to 0 in your ~/.digitorn/config.yaml if you want permanent sessions.

session.queue (6 params)

Controls the per-session message queue. When enabled, messages sent while a turn is running are enqueued in a persistent FIFO instead of returning session_busy.

ParameterTypeDefaultDescription
enabledbooltrueFeature flag. When false, falls back to the legacy lock-based flow.
max_depthint20Max queued messages per session. Over the cap, POST /messages returns 429.
ttl_secondsint3600Queued messages auto-expire after N seconds (default: 1h).
auto_mergeboolfalseConcatenate consecutive user messages sent within auto_merge_window_s into a single turn (saves LLM calls on rapid follow-ups).
auto_merge_window_sfloat2.0Window in seconds for auto_merge (0.5-30).
default_modestring"async"How POST /messages behaves: "async" = enqueue + return 202 (recommended); "wait" = block until turn finishes (legacy compat).

runtime (8 params)

ParameterTypeDefaultDescription
max_consecutive_failuresint8Consecutive tool failures before warning (1-30)
max_repeat_windowint20Sliding window size for duplicate tool-call detection (2-100)
max_repeatsint8Max identical calls within window before warning (1-30)
max_consecutive_same_toolint30Max consecutive calls to the same tool before warning (1-100)
tool_timeoutfloat3600.0Default per-tool execution timeout in seconds (1-7200)
context_pressure_thresholdfloat0.75Token pressure ratio that triggers compaction (0.1-0.99)
specialist_context_windowint50000Default context window size for specialist agents (4000-2000000)
watch_poll_intervalint5File watch trigger polling interval in seconds (1-300)

agent_spawn (4 params)

ParameterTypeDefaultDescription
max_workersint3Max parallel sub-agents per session (1-50)
max_turnsint100Default max turns per sub-agent (10-10000)
timeoutfloat3600.0Default sub-agent timeout in seconds (30-7200)
cleanup_agefloat300.0Remove completed sub-agents after N seconds (30-86400)

mcp (4 params)

ParameterTypeDefaultDescription
health_intervalint60Health check interval for MCP servers in seconds (10-600)
process_timeoutfloat60.0MCP subprocess execution timeout in seconds (5-600)
max_reconnect_attemptsint4Max reconnect attempts for failed MCP servers (0-20)
tool_call_timeoutfloat3600.0Timeout for individual MCP tool calls in seconds (5-7200)

sandbox (4 params)

ParameterTypeDefaultDescription
pool_sizeint2Number of warm sandbox workers (1-20)
idle_timeoutfloat60.0Idle sandbox worker cleanup timeout in seconds (10-600)
max_processesint10Max processes per sandbox (1-100)
drain_timeoutfloat30.0Shutdown drain timeout in seconds (5-120)

websocket (2 params)

ParameterTypeDefaultDescription
rate_limit_windowfloat10.0Rate limit window in seconds (1-60)
rate_limit_max_connectionsint5Max WebSocket connections per IP within the window (1-100)

default_model (8 params)

Default LLM model for built-in apps. These values are injected into built-in app YAMLs at deploy time.

ParameterTypeDefaultDescription
providerstring"anthropic"LLM provider: anthropic, deepseek, openai, ollama, etc.
modelstring"claude-sonnet-4-5"Model name/ID
backendstring""Backend override: openai_compat, etc. Empty = auto-detect.
api_keystring"claude-code"API key. Special: claude-code (OAuth token), env:VAR_NAME (env var), or literal key.
base_urlstring""Base URL override for the API
temperaturefloat0.7Sampling temperature (0.0-2.0)
max_tokensint4096Max output tokens (256-65536)
context_windowint200000Context window size (4000-2000000)

discovery (6 params)

Tool discovery and semantic search settings (for discovery mode).

ParameterTypeDefaultDescription
embedding_modelstring"sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2"FastEmbed model ID
embedding_dimint384Embedding vector dimension (64-4096)
skip_embeddingsboolfalseSkip semantic index (saves ~900MB RAM, keyword search only)
search_top_kint5Default number of results for tool search (1-50)
search_min_scorefloat0.2Minimum similarity score for search results (0.0-1.0)
models_cache_dirstring""Cache directory for embedding models. Empty = ~/.local/share/digitorn/models/

modules (4 params)

ParameterTypeDefaultDescription
pathslist[str]["modules"]Directories to scan for modules
enabledlist[str][]Module IDs to load. Empty = load all discovered.
disabledlist[str][]Module IDs to exclude (overrides enabled)
load_allbooltrueLoad all discovered modules with enabled=true in their TOML

app (3 params)

ParameterTypeDefaultDescription
yaml_pathstringnullApp YAML to compile and bootstrap at startup
stop_on_errorboolfalseStop bootstrap if any setup step fails
hot_reloadboolfalseDev mode - watch each deployed app's prompts/, skills/, and assets/ directories and auto-redeploy on change. Keep false in production.

images (8 params)

ParameterTypeDefaultDescription
max_per_messageint10Max images per message (0 = unlimited)
max_size_bytesint10485760Max size per image (10MB)
max_per_sessionint100Max images per session (0 = unlimited)
storage_dirstring""Image storage directory. Empty = ~/.digitorn/images/
low_res_sizeint512Resize dimension for aged images (px)
aging_full_turnsint1Turns an image stays at full resolution
aging_low_turnsint2Turns at low resolution before text-only
cleanup_after_daysint7Auto-delete images after N days

logging (2 params)

ParameterTypeDefaultDescription
levelstring"info"Log level: debug, info, warning, error, critical
formatstring"console"Output format: json or console

transcribe (11 params)

Voice-to-text pipeline. Two providers:

  • local - faster-whisper in-process. Install with pip install digitorn[transcribe]. Model weights downloaded + cached on first use (~150 MB for base, ~500 MB for small).
  • openai - OpenAI Whisper API. API key is read from the credentials system (provider=openai, field=api_key), NOT from config.yaml. See Credentials.

The local model is a singleton shared across all apps and sessions - one copy in RAM/VRAM, not N × apps. Two loading strategies are selectable:

  • preload: true (default) - model loaded eagerly during daemon startup in a background task. The daemon still starts serving HTTP immediately; the first transcribe request is instant once preload completes. Recommended for production.
  • preload: false - lazy-load on the first transcribe request. Startup memory is lower but the first call waits 2–10 s (model download/load).
ParameterTypeDefaultDescription
enabledbooltrueIf false, endpoint returns 404 (client falls back to attaching audio to the next message).
providerstring"local""local" (faster-whisper) or "openai" (Whisper-1 API).
modelstring"base"faster-whisper size: tiny, base, small, medium, large-v3. Ignored when provider=openai.
devicestring"auto""cpu", "cuda", or "auto". Local provider only.
compute_typestring"int8"faster-whisper compute: int8 (CPU), int8_float16/float16 (CUDA), float32.
max_audio_bytesint26214400Hard upload cap (25 MB). Requests above this return 413.
min_audio_bytesint500Below this, the audio is rejected as empty/truncated (422).
timeout_secondsfloat120.0Max inference time for a single upload.
preloadbooltrueLoad the model eagerly at daemon startup (instant first request). Set false for lazy-load. Ignored when provider=openai.
shared_instancebooltrueOne model instance for all apps/sessions. Leave true unless you need per-session isolation (memory cost scales linearly if false).
max_concurrencyint1Max simultaneous transcriptions per model instance. Extra requests queue. Bump on a GPU with multi-stream inference.

hub (3 params)

Remote Digitorn Hub integration. When url is empty (the default), hub integration is disabled and source_type: hub package installs return 501.

ParameterTypeDefaultDescription
urlstring""Base URL of the remote hub (e.g. https://hub.digitorn.ai). Empty = disabled.
verify_sslbooltrueVerify TLS certificates when connecting to the hub.
timeout_secondsfloat60.0HTTP timeout for hub requests in seconds (1-600).

Example config.yaml

server:
host: "0.0.0.0"
port: 8000
workers: 4
auth_enabled: true
sandbox: true
kv_backend: "redis://localhost:6379/0"
cors_origins:
- "https://myapp.example.com"

database:
url: "postgresql+asyncpg://digitorn:secret@localhost/digitorn"
pool_size: 10

auth:
access_token_ttl: 3600
approval_timeout: 600.0

session:
idle_ttl: 3600
max_sessions_per_app: 200

runtime:
context_pressure_threshold: 0.80
tool_timeout: 180.0

agent_spawn:
max_workers: 5
timeout: 1800.0

default_model:
provider: anthropic
model: claude-sonnet-4-5
api_key: "claude-code"
context_window: 200000

logging:
level: info
format: json

transcribe:
enabled: true
provider: local # or "openai" + export OPENAI_API_KEY=...
model: base # tiny | base | small | medium | large-v3
device: auto # cpu | cuda | auto
compute_type: int8 # int8 (CPU) | int8_float16 (CUDA) | float16 | float32
max_audio_bytes: 26214400
timeout_seconds: 120.0

Environment variable overrides

All non-secret fields honour the DIGITORN_<SECTION>__<FIELD> convention (double underscore between section and field):

export DIGITORN_TRANSCRIBE__PROVIDER=openai
export DIGITORN_TRANSCRIBE__MODEL=small
export DIGITORN_TRANSCRIBE__ENABLED=false

Restart the daemon after changes: digitorn service restart. Verify with the transcribe health-check (admin reference) - ready: true means the provider is loaded and the endpoint is serving.

OpenAI API key for transcribe

Secrets never go in config.yaml or env vars. Digitorn has a dedicated encrypted credentials store (credentials table, AES at rest, 4-scope resolution). Use it:

# Via CLI - stores at system scope (available to all users)
digitorn credentials set openai api_key sk-... --scope system

# Or per-user (only this user's sessions can transcribe)
digitorn credentials set openai api_key sk-... --scope user

# Programmatically: use the Python testing SDK or the
# CLI; the REST endpoints are not documented publicly.

Resolution order at request time (first hit wins):

  1. per-user + per-app
  2. per-user
  3. per-app (shared)
  4. system-wide
  5. OPENAI_API_KEY env var - dev/CI fallback only

Verify by querying the transcribe health surface (admin reference). It returns {enabled, provider, ready, error}. ready:false with "OpenAI API key not configured..." means no credential in any scope - add one and restart.