arizuko

arizukoreference › Environment variables

environment variables

Every env var read by an arizuko Go or TypeScript daemon, with the file:line that reads it, type, default, and one-line effect. Generated from a grep of os.Getenv, chanlib.EnvOr/EnvInt/EnvBool/EnvBytes/EnvDur/MustEnv, and process.env[] across the repo. Test-only env vars omitted.

Conventions. chanlib.EnvOr(k, d) returns d when the env var is empty or unset. chanlib.MustEnv(k) calls os.Exit(1) if unset. chanlib.EnvDur(k, d) reads integer milliseconds (legacy encoding) — not Go duration strings. Adapter LISTEN_ADDR code-defaults vary per daemon, but every service fragment in template/services/ pins :8080; the multi-daemon local-dev numbers (9001–9010) appear here only because that's what the source defaults to.

core — consumed by every Go daemon via core.LoadConfig

These are read in core/config.go through chanlib.EnvOr / EnvInt / EnvDur and the resolveTimezone() helper. Every daemon that calls core.LoadConfig() (routd, onbod, webd, …) inherits this surface.

API_PORT

Listening port for routd's HTTP API.

Read bycore / core/config.go:135 → routd
Typeint
Default8080
Example8080

ARIZUKO_DEV

Dev mode — bind-mounts ant/src into spawned agent containers for live-reload of the in-container runner.

Read bycore / core/config.go:168, container / container/runner.go:498
Typebool ("true" or "1")
Defaultunset = production mode
Example1

ASSISTANT_NAME

Bot display name and mention trigger; also baked into the data-dir basename and compose container_name. Must contain no whitespace or shell metachars.

Read bycore / core/config.go:102, webd / webd/main.go:42, teled / teled/main.go:63, discd / discd/main.go:70, whapd / whapd/src/main.ts:41
Typestring
DefaultAndy (core); assistant in webd; empty in teled/discd
ExampleAndy

AUTH_BASE_URL

Public base URL used to build OAuth redirect callbacks and onboarding invite links. HTTPS prefix toggles secure-cookie flag.

Read bycore / core/config.go:115
TypeURL
Default""
Examplehttps://krons.arizuko.com

AUTH_SECRET

At-rest sealing key. Comma-separated to rotate: the first key seals new writes, the rest decrypt-only (retired keys kept so values sealed under an old key still read during rotation). This is not the JWT signing key — JWTs are signed with ES256 via authd’s keypair, not HMAC.

Read bycore / core/config.go:173
Typestring (hex/random)
Default""
Examplea3f1...c0de

CONTAINER_IMAGE

Docker image used to spawn per-group agent containers.

Read bycore / core/config.go:107
Typestring
Defaultarizuko-ant:latest
Examplearizuko-ant:v0.35.0

CONTAINER_TIMEOUT

Hard kill timeout per agent run, in milliseconds.

Read bycore / core/config.go:108
Typeint (milliseconds, via EnvDur)
Default3600000 (60 min)
Example1800000

DATA_DIR

Root of this instance's data directory (store/, groups/, ipc/, web/). When set in compose, also passes through to dashd, timed, and several adapters as their working/storage root.

Read bycore / core/config.go:99, dashd / dashd/main.go:67, timed / timed/main.go:26, teled / teled/main.go:54, bskyd / bskyd/main.go:60, reditd / reditd/main.go:75, emaid / emaid/main.go:66, linkd / linkd/main.go:68, whapd / whapd/src/main.ts:42, twitd / twitd/src/main.ts:28
Typepath
Defaultcwd (core); /srv/data/<daemon> per adapter
Example/srv/data/arizuko_krons

DEX_ISSUER

OIDC issuer URL of a Dex instance. With DEX_CLIENT_ID it mounts /auth/dex on authd: Dex authenticates the person against its connectors, authd reads federated_claims off the ID token and mints the session for <connector_id>:<user_id> — the principal the native callback for that provider would mint. The folder claim and scope snapshot stay authd's. Unset leaves the login page as it is.

Read byauthd / core/config.go
TypeURL
Default""
Examplehttps://auth.example.com/dex

DEX_CLIENT_ID

The static client id authd presents to Dex; the ID token's audience must equal it. Pair with DEX_CLIENT_SECRET for a confidential client; a public client with PKCE needs no secret.

Read byauthd / core/config.go
Typestring
Default""
Examplearizuko

DEX_CLIENT_SECRET

Secret for DEX_CLIENT_ID, sent on the code exchange. Optional.

Read byauthd / core/config.go
Typestring
Default""
Examplea-long-random-secret

DISCORD_CLIENT_ID

OAuth client id for the Discord login provider in proxyd's auth flow (distinct from the bot token used by discd).

Read bycore / core/config.go:118
Typestring
Default""
Example1234567890

DISCORD_CLIENT_SECRET

OAuth client secret for the Discord login provider.

Read bycore / core/config.go:119
Typestring
Default""
Exampleabc...def

EGRESS_IMAGE

Image holding the egress binary. This is the master switch — name an image and runed starts one proxy container per spawn from it with that folder’s allowlist baked in, killing it with the turn; leave it empty and spawns run unfiltered. There is no separate enable flag. Build it with make images.

Read bycore / core/config.go:263, runed / container/egress.go
Typestring (docker image ref)
Default"" (egress isolation off)
Examplearizuko-egress:latest

EGRESS_NETWORK_PREFIX

Prefix for the per-folder docker networks runed creates at spawn (<prefix>_<folder>). Each is created --internal, so a spawn on it has no route out except its own proxy. Must be unique per instance so two instances on one docker host cannot collide.

Read bycore / core/config.go:262, compose generation / compose/compose.go:737
Typestring
Default""; when EGRESS_IMAGE is set, arizuko generate writes <app>_<flavor>
Examplearizuko_krons

EGRESS_SUBNET

Parent CIDR carved into per-folder /24s. Each spawn takes two addresses out of its folder’s /24 — one for the agent, one for its proxy. Must be /8 to /23.

Read bycore / core/config.go:265
TypeCIDR string
Default10.99.0.0/16
Example10.42.0.0/16

The docker network that gives each spawn’s proxy its route to the internet, and gives runed a path to poll that proxy’s /health before starting the agent. The agent is never attached to it. Derived, not hand-set.

Read bycore / core/config.go:264, compose generation / compose/compose.go:744
Typestring
Default""; when EGRESS_IMAGE is set, arizuko generate writes <project>_default
Examplearizuko_krons_default

GITHUB_ALLOWED_ORG

If set, restricts GitHub OAuth sign-in to members of this org.

Read bycore / core/config.go:123
Typestring
Default""
Examplekronael

GITHUB_CLIENT_ID

OAuth client id for the GitHub login provider.

Read bycore / core/config.go:116
Typestring
Default""
ExampleIv1.abc123

GITHUB_CLIENT_SECRET

OAuth client secret for the GitHub login provider.

Read bycore / core/config.go:117
Typestring
Default""
Exampleghs_xxxxx

GOOGLE_ALLOWED_EMAILS

CSV allowlist of email addresses permitted to complete Google OAuth.

Read bycore / core/config.go:122
TypeCSV string
Default""
Examplealice@example.com,bob@example.com

GOOGLE_CLIENT_ID

OAuth client id for the Google login provider.

Read bycore / core/config.go:120
Typestring
Default""
Exampleabc.apps.googleusercontent.com

GOOGLE_CLIENT_SECRET

OAuth client secret for the Google login provider.

Read bycore / core/config.go:121
Typestring
Default""
ExampleGOCSPX-xxx

HOST_APP_DIR

Path on the host that contains the arizuko binaries and ant/src; used when bind-mounting the dev runner.

Read bycore / core/config.go:101, compose / compose/compose.go:461
Typepath
Defaultdirectory of the running executable
Example/home/onvos/app/arizuko

HOST_CODEX_DIR

Host path bind-mounted into agent containers at /home/node/.codex so the oracle skill can reuse the operator's codex login state.

Read bycore / core/config.go:133
Typepath
Default"" (mount disabled; falls back to the CODEX_API_KEY/OPENAI_API_KEY env-profile keys)
Example/home/onvos/.codex

HOST_DATA_DIR

Host-side path used when constructing volume mounts for spawned containers. Differs from DATA_DIR only when arizuko runs inside a container itself.

Read bycore / core/config.go:100
Typepath
DefaultDATA_DIR
Example/srv/data/arizuko_krons

IDLE_TIMEOUT

How long an idle agent container is kept around before recycling, in milliseconds.

Read bycore / core/config.go:109
Typeint (milliseconds)
Default3600000 (60 min)
Example600000

MAX_CONCURRENT_CONTAINERS

Max agent containers running at once before runed queues spawns.

Read bycore / core/config.go:110
Typeint
Default5
Example10

MAX_TURN_RETRY

How many times routd re-runs a turn whose container died without delivering any bot message — SIGKILL, out-of-memory, or the RUNED_RUN_TIMEOUT run ceiling. Each attempt waits 10s, then spawns a fresh container with a <system-note> telling the agent it is retry N of M and to be conservative with resources. A turn that already replied is never retried, even partially. Set 0 to disable. Instance-wide — no per-folder override. See retries.

Read bycore / core/config.go:250 → routd
Typeint
Default3
Example5

MEDIA_ENABLED

Enables inbound media download and forwarding to the agent. Adapters fall back to URL-only references when off.

Read bycore / core/config.go:143
Typebool ("true")
Defaultfalse
Exampletrue

MEDIA_MAX_FILE_BYTES

Per-attachment byte cap on inbound media; adapter ProxyFile streams up to this size before truncation.

Read bycore / core/config.go:144, teled / teled/main.go:65, discd / discd/main.go:71, bskyd / bskyd/main.go:61, reditd / reditd/main.go:76, emaid / emaid/main.go:67, slakd / slakd/main.go:63
Typeint (bytes)
Default20971520 (20 MiB)
Example52428800

ONBOARDING_ENABLED

Master switch for the onboarding flow. Affects both routd behaviour and whether compose generates the onbod service.

Read bycore / core/config.go:137, onbod / onbod/main.go:55 ("0" → exit 0), compose / compose/compose.go:326
Typebool (core: "true"; onbod: "0" disables)
Defaultfalse
Exampletrue

ONBOARDING_PLATFORMS

CSV of platforms (e.g. telegram,discord) for which onboarding admissions are enabled.

Read bycore / core/config.go:138
TypeCSV string
Default""
Exampletelegram,whatsapp

OBSERVE_WINDOW_MESSAGES

How many trailing #observe-mode messages routd folds into context when a trigger turn fires. Per-route override via routes.observe_window_messages.

Read bycore / core/config.go:151, routd
Typeint
Default10
Example25

OBSERVE_WINDOW_CHARS

Character cap on the #observe context window for a single trigger turn. Per-route override via routes.observe_window_chars.

Read bycore / core/config.go:152, routd
Typeint (chars)
Default4000
Example8000

ENGAGEMENT_TTL

How long a (chat, topic) stays “engaged” after the bot’s last reply. Engaged pairs fire a turn on every inbound message without needing a fresh @mention, and override #observe routing. Each bot reply pushes the deadline out again; user messages do not. See engagement.

Read byroutd / routd/cmd/routd/main.go:203
Typeduration (e.g. 10m, 30m)
Default30m
Example30m

SECRETS_KEY

AES-256-GCM key for the secrets table — secrets are encrypted at rest. Required: routd refuses to start without it, and there is no plaintext mode and no AUTH_SECRET fallback. The value is a comma-separated keyring: the first key seals new writes, the rest are decrypt-only (retired keys kept around so values sealed under an old key still read during rotation). On boot routd migrates any legacy-plaintext rows in place under the active key. arizuko create generates a random key into the new instance’s .env; the arizuko secret CLI uses the same keyring. Stored values carry a v2: prefix.

Read bycore / core/config.go:123 → routd, arizuko secret CLI
Typestring (comma-separated keyring; first = active seal key)
Defaultnone — routd exits if unset; arizuko create generates one
Example9d4f...new,2a17...retired

SEND_DISABLED_CHANNELS

CSV of channel names where outbound sends are dropped (read-only mode).

Read bycore / core/config.go:140
TypeCSV string
Default""
Exampleslack,bluesky

SEND_DISABLED_GROUPS

CSV of group folders where outbound sends are dropped (read-only mode).

Read bycore / core/config.go:141
TypeCSV string
Default""
Examplesolo/inbox,corp/eng

TELEGRAM_BOT_TOKEN

Bot token for the Telegram channel adapter.

Read bycore / core/config.go:106, teled / teled/main.go:58 (MustEnv)
Typestring
Default"" (teled refuses to start)
Example12345:ABC-DEF1234ghIkl-zyx57W2v1u123ew11

TTS_BASE_URL

OpenAI-compatible /v1/audio/speech base URL the agent's send_voice path hits.

Read bycore / core/config.go:151
TypeURL
Defaulthttp://ttsd:8880
Examplehttp://ttsd:8880

TTS_ENABLED

Enables TTS rendering of agent replies as voice messages.

Read bycore / core/config.go:150
Typebool ("true")
Defaultfalse
Exampletrue

TTS_MODEL

Default model name passed in the TTS request body.

Read bycore / core/config.go:153
Typestring
Defaultkokoro
Examplekokoro

TTS_TIMEOUT

Per-request timeout when calling the TTS backend, in milliseconds.

Read bycore / core/config.go:154
Typeint (milliseconds)
Default15000 (15 s)
Example30000

TTS_VOICE

Instance-default voice id; agent may override per-call via send_voice args or per-group via PERSONA.md frontmatter.

Read bycore / core/config.go:152
Typestring
Defaultaf_bella
Exampleaf_sky

TZ

IANA timezone for log timestamps, cron evaluation in timed, and Config.Timezone consumers.

Read bycore / core/config.go:192, timed / timed/main.go:36, compose / compose/compose.go:490
Typestring (IANA name)
DefaultUTC
ExampleEurope/Bratislava

VIDEO_TRANSCRIPTION_ENABLED

Enables Whisper transcription of inbound video.

Read bycore / core/config.go:147
Typebool ("true")
Defaultfalse
Exampletrue

VOICE_TRANSCRIPTION_ENABLED

Enables Whisper transcription of inbound voice messages.

Read bycore / core/config.go:146
Typebool ("true")
Defaultfalse
Exampletrue

WEB_HOST

Public hostname the instance serves; used to build chat-link, webhook, and onboarding URLs in agent prompts.

Read bycore / core/config.go:114
Typestring
Default""
Examplekrons.arizuko.com

WHISPER_BASE_URL

Base URL of the Whisper-compatible transcription endpoint.

Read bycore / core/config.go:145
TypeURL
Defaulthttp://localhost:8080
Examplehttp://whisper:9000

WHISPER_MODEL

Model name passed to Whisper.

Read bycore / core/config.go:148
Typestring
Defaultturbo
Examplelarge-v3

container — agent spawn (read by runed when building runs)

Model keys are env-profile keys. ANTHROPIC_API_KEY, CLAUDE_CODE_OAUTH_TOKEN, OPENAI_API_KEY, and CODEX_API_KEY pick which model a spawn talks to, so they are user-scoped credentials, not folder secrets — the store rejects them at folder scope. A user sets their own in a dedicated dashboard section at /dash/me/env, and that value overrides the operator default for their spawns. The host .env value below is the instance-wide default forwarded when a user has set nothing. See secrets. With the litellm package the forwarding stops: the gateway reads the credential from .env and the container gets MODEL_GATEWAY_KEY instead.

ANTHROPIC_API_KEY

Instance default forwarded into every spawned agent container so Claude Code can authenticate, unless the triggering user has set their own at /dash/me/env.

Read bycontainer / container/runner.go:617
Typestring
Scopeuser (env-profile key; rejected at folder scope)
Defaultnot forwarded if unset
Examplesk-ant-...

CLAUDE_CODE_OAUTH_TOKEN

Alternative auth for Claude Code; forwarded into the container alongside ANTHROPIC_API_KEY, same user-override rule.

Read bycontainer / container/runner.go:617
Typestring
Scopeuser (env-profile key; rejected at folder scope)
Defaultnot forwarded if unset
Examplecc-oauth-...

LOG_LEVEL

Sets the stderr slog level (debug < info < warn < error) for every daemon, applied by obs.Setup at startup. Additionally, in runed debug/trace dumps full container stderr + mounts after every spawn.

Read byevery daemon via obs.Setup; container-run verbose dump / container/runner.go:891
Typestring (debug/info/warn/error/trace)
Defaultinfo
Exampledebug

chanreg

CHANNEL_REGISTER_ALLOW_PUBLIC

Dev override that lets channel adapters register with public IPs. By default chanreg rejects non-private adapter URLs as SSRF risk.

Read bychanreg / chanreg/chanreg.go:222
Typebool ("1")
Defaultunset = enforce private-only
Example1

arizuko CLI (cmd/arizuko)

ARIZUKO_DATA_DIR

Override the base directory used to construct instance data paths. When set, instance dir is $ARIZUKO_DATA_DIR/arizuko_<name>.

Read bycli / cmd/arizuko/main.go:151
Typepath
Default"" (falls back to PREFIX)
Example/var/lib/arizuko

PREFIX

Filesystem prefix for instance data dirs; final path is $PREFIX/data/arizuko_<name>.

Read bycli / cmd/arizuko/main.go:154
Typepath
Default/srv
Example/srv

arizuko run (compose generation)

Read by compose/compose.go at arizuko run time when it generates the docker-compose YAML. These are not consumed by any running daemon — only by the generator that decides which services to emit, which ports to expose, and which proxyd routes to gate.

DAV_PORT

Host port to expose for davd. Empty ⇒ davd not exposed at the docker level.

Read bycompose / compose/compose.go:564
Typestring (port)
Default""
Example8096

COMPOSE_PROFILES

Comma-separated docker compose profiles that decide which optional daemons run. Generated, not hand-set: activeProfiles derives it from the instance's feature flags (WEB_PORTweb, WEBDAV_ENABLEDdavd, ONBOARDING_ENABLEDonbod; timed is always on) and writes it into the compose-managed block of .env. Every optional service fragment carries a matching profiles: [<name>], so this list is the single gate docker reads.

Read bydocker compose (written by compose/compose.go:411)
TypeCSV string
Defaulttimed (always on)
Exampledavd,onbod,timed,web

WEB_PORT

Host port the proxyd service is published on; the public entry point for the instance.

Read bycompose / compose/compose.go:530
Typestring (port)
Default8095
Example443

WEB_PORT_ALIASES

CSV of additional host ports also published for proxyd (e.g. expose 80 alongside 443).

Read bycompose / compose/compose.go:536
TypeCSV string
Default""
Example80,8080

WEBDAV_ENABLED

Whether to emit the davd service and gate its /dav/ proxyd route.

Read bycompose / compose/compose.go:323 (and as a route gate at :186)
Typebool ("true")
Defaulttrue
Examplefalse

routd

Apart from the PROACTIVE_* set below, routd takes every value from core.LoadConfig above. The egress vars are runed’s, since runed owns the docker spawn: it refuses to start if the retired CRACKBOX_ADMIN_API is still set while EGRESS_IMAGE is empty, so an upgraded instance cannot spawn unfiltered while looking healthy.

The PROACTIVE_* vars tune proactive interjection — the agent speaking without being addressed. They are read once at startup by routd.LoadProactiveConfig, called from routd/cmd/routd/main.go:165. All of them do nothing unless PROACTIVE_ENABLED is on. Per-group opt-in is separate: a proactive: block in the group’s CLAUDE.md frontmatter, not an env var.

PROACTIVE_ENABLED

Master switch for proactive interjection. Unset or false and routd builds no scanner at all — the whole feature is absent, not idle. No shipped template sets it, so every instance is off until an operator opts in. Turning it on starts the scan; each group still has to declare mode: lurk before anything fires.

Read byroutd / routd/proactive.go:39
Typebool (1, true, yes, on)
Defaultunset — off
Exampletrue

PROACTIVE_SCAN_INTERVAL

Minimum gap between proactive sweeps. The sweep is driven by routd’s own loop, not a timer, so a long turn simply delays the next one — missed ticks are dropped, never replayed as a burst.

Read byroutd / routd/proactive.go:40
Typeduration (Go syntax, e.g. 30s, 2m)
Default30s
Example1m

PROACTIVE_SILENCE_MIN

How long a chat must have been quiet before an interjection is considered. Below this the conversation is still live and cutting in is rude. Measured from the last real inbound — bot replies and prior proactive messages do not reset the clock.

Read byroutd / routd/proactive.go:41
Typeduration
Default90s
Example5m

PROACTIVE_SILENCE_MAX

Upper edge of the same band. Past this the chat is dormant — nobody is there to read the message — so the scan skips it.

Read byroutd / routd/proactive.go:42
Typeduration
Default12h
Example4h

PROACTIVE_COOLDOWN

How long a chat is barred from a second interjection after one fires. Mandatory — state-triggered firing without a cooldown loops. Recorded per chat in routd.db’s chat_proactive table, written in the same transaction that queues the turn, so a crash mid-dispatch costs at most one missed turn and never a double-fire. There is no per-group override.

Read byroutd / routd/proactive.go:43
Typeduration
Default24h
Example48h

PROACTIVE_BOT_QUIET

How long after its own last message the bot stays out of a chat. Stops a proactive turn from landing on the heels of a reply the agent just made.

Read byroutd / routd/proactive.go:44
Typeduration
Default15m
Example30m

PROACTIVE_RECENT_ACTIVITY_MIN

How many inbound messages must have arrived in the last hour for the room to count as busy enough to be worth speaking into. Below the threshold the scan skips the chat.

Read byroutd / routd/proactive.go:45
Typeint (messages per hour)
Default3
Example5

proxyd

PROXYD_HMAC_SECRET retired

Retired. The HMAC identity-header model is gone. proxyd no longer signs an X-User-Sig header; it proves the channel to each backend with an authd-minted ES256 bearer pinned to service:proxyd, verified by auth.ProxydTransit in auth/middleware.go. No shared secret to set. See auth concept.

PROXYD_LISTEN

Port proxyd binds to. Plain numbers get a : prefix.

Read byproxyd / proxyd/main.go:42
Typestring (port or :port)
Default8080
Example8080

PUB_REDIRECT_URL

If set, proxyd redirects /pub/* requests to this base URL instead of serving them locally — lets a CDN front the static docs.

Read byproxyd / proxyd/main.go:57
TypeURL
Default"" (proxyd serves /pub/ itself)
Examplehttps://docs.arizuko.com

TRUSTED_PROXIES

CSV of CIDRs (or bare IPs) trusted to set X-Forwarded-For. Empty ⇒ no client trusted, XFF always replaced with the connection peer.

Read byproxyd / proxyd/main.go:60
TypeCSV string (CIDRs / IPs)
Default""
Example10.0.0.0/8,172.16.0.0/12

VITE_ADDR

Backend address proxyd forwards /pub/* (and chat widget) traffic to.

Read byproxyd / proxyd/main.go:56
TypeURL
Defaulthttp://vited:8080
Examplehttp://vited:8080

webd

ROUTER_URL

Base URL of routd; webd posts inbound web chat and webhook messages to $ROUTER_URL/v1/messages.

Read bywebd / webd/main.go:38 — see also ROUTER_URL in adapters
TypeURL
Defaulthttp://routd:8080
Examplehttp://routd:8080

WEBD_LISTEN

Address webd binds to.

Read bywebd / webd/main.go:36
Typelisten addr (:port or host:port)
Default:8080
Example:8080

WEBD_URL

Public URL webd advertises to routd when registering as a channel.

Read bywebd / webd/main.go:37
TypeURL
Defaulthttp://webd:8080
Examplehttp://webd:8080

onbod

ONBOARD_POLL_INTERVAL

Cadence at which onbod scans for unprompted users / admission queue entries.

Read byonbod / onbod/main.go:147
TypeGo duration string (time.ParseDuration)
Default10s
Example30s

ONBOARDING_GREETING

Custom greeting string injected into onboarding prompts in place of the default copy.

Read byonbod / onbod/main.go:142
Typestring
Default""
ExampleWelcome to krons.

ONBOD_LISTEN_ADDR

Address onbod binds to.

Read byonbod / onbod/main.go:144
Typelisten addr
Default:8080
Example:8080

onbod additionally reads ONBOARDING_ENABLED ("0" → clean exit) and ROUTER_URL via core. It trusts X-User-* headers only behind the proxyd transit bearer (auth.ProxydTransit); on its mixed public/authed invite routes an unproven request is treated as anonymous rather than rejected.

dashd

DASH_PORT

Port dashd binds to. Plain numbers get a : prefix.

Read bydashd / dashd/main.go:79, compose / compose/compose.go:523
Typestring
Default:8080
Example:8080

DB_PATH

The file dashd opens for routd's tables when the instance keeps its owners in files. Ignored once DYNAMODB_URL names an endpoint — dashd takes routd's tables from there and opens nothing. Falls back to $DATA_DIR/store/routd/routd.db; ONBOD_DB_PATH is the same for onbod's. Pointing it at a retired database is refused, not served stale.

Read bydashd / dashd/main.go:453
Typepath
Default$DATA_DIR/store/routd/routd.db (refuses to start if both unset)
Example/srv/data/arizuko_krons/store/routd/routd.db

SURROGATE_<NAME>_CLIENT_ID

OAuth app client id for the surrogate “Connect <name>” flow at /dash/me/connections — arizuko authenticating as the user against a third-party API, not a user signing in to arizuko. <NAME> is the provider name upper-cased (-_); a pair exists for every registered provider, built-in or dropped in at <datadir>/surrogate/*.toml (see how-to: add an OAuth provider). SURROGATE_GITHUB_CLIENT_ID feeds the built-in GitHub connector; it is distinct from GITHUB_CLIENT_ID, the login provider. Unset hides that provider's connection option.

Read byroutd + dashd / auth/surrogate/engine.go (NewEngine)
Typestring
Default""
ExampleIv1.def456

SURROGATE_<NAME>_CLIENT_SECRET

OAuth app client secret paired with SURROGATE_<NAME>_CLIENT_ID. One pair per provider.

Read byroutd + dashd / auth/surrogate/engine.go (NewEngine)
Typestring
Default""
Exampleghs_yyyyy

timed

ROUTER_URL

routd's address. timed opens no database — it reads due tasks and records runs over routd's HTTP API, so scheduled_tasks has exactly one writer path.

Read bytimed / timed/main.go
TypeURL
Defaultnone — required, timed refuses to start without it
Examplehttp://routd:8080

timed also reads AUTHD_URL + AUTHD_SERVICE_KEY (exchanged at boot for the service:timed token routd's gate requires) and TZ (for cron evaluation).

ttsd

TTSD_ADDR

Address ttsd binds to.

Read byttsd / ttsd/main.go:31
Typelisten addr
Default:8880
Example:8880

TTS_BACKEND_URL

Upstream Kokoro/OpenAI-compatible TTS server ttsd proxies to.

Read byttsd / ttsd/main.go:32
TypeURL
Defaulthttp://kokoro:8880
Examplehttp://kokoro:8880

ttsd also reads LOG_LEVEL.

litellm (model gateway package)

A third-party image, so it has no generated env file: template/services/litellm.yml names the .env keys docker interpolates into it, and compose/fragments_test.go pins that set. Component page: components/litellm.

MODEL_GATEWAY_KEY

The virtual key. litellm accepts it as its master key; runed hands it to every spawn, where the claude harness sends it as ANTHROPIC_AUTH_TOKEN. packages add litellm mints it into .env (the package's manifest declares it generate), and a later generate mints a new one if the line is gone. The fragment still interpolates it as required (${MODEL_GATEWAY_KEY:?}), so a hand-copied fragment with no key refuses to start rather than start a gateway that accepts every caller.

Read bylitellm via template/services/litellm.yml (LITELLM_MASTER_KEY); runed for the spawn env
Typestring
Defaultnone — required once the package is installed
Example$(openssl rand -hex 24)

MODEL_GATEWAY_URL

Where runed points every spawn’s model client (ANTHROPIC_BASE_URL for claude). Unset means the container keeps the credential and talks to the vendor directly, which is the default.

Read byruned for the spawn env
TypeURL
Default"" = no gateway
Examplehttp://litellm:4000

litellm also reads ANTHROPIC_API_KEY (or, when that is empty, CLAUDE_CODE_OAUTH_TOKEN) as the credential it forwards upstream, TZ, and the three OTLP keys under observability.

Adapter common surface

Every channel adapter shares the same set of plumbing env vars:

CHANNEL_NAME

Name the adapter registers with routd; routing uses this verbatim. Has a per-daemon default.

Read byteled :55, discd :64, bskyd :52, reditd :64, emaid :55, linkd :59, slakd :56
Typestring
Defaultmatches the platform (telegram, discord, slack, …)
Exampletelegram-prod

LISTEN_ADDR

Address the adapter binds for its outbound-send HTTP server (routd → adapter).

Read byteled :61 (:9001), discd :68 (:9002), whapd :156 (:9002), emaid :64 (:9003), bskyd :58 (:9005), reditd :73 (:9006), linkd :66 (:9010), slakd :61 (:8080), twitd :43 (:8080)
Typelisten addr
Defaultvaries (see column above; :8080 when pinned by the service fragment)
Example:8080

LISTEN_URL

URL the adapter advertises to routd on registration so routd can reach it.

Read byteled :62, discd :69, whapd :157, emaid :65, bskyd :59, reditd :74, linkd :67, slakd :62, twitd :44
TypeURL
Defaulthttp://<daemon>:<port>
Examplehttp://teled:9001

ROUTER_URL

Base URL of routd where the adapter posts inbound messages.

Read byteled :59 (MustEnv), discd :66 (MustEnv), whapd :154, emaid :62 (MustEnv), bskyd :56 (MustEnv), reditd :71 (MustEnv), linkd :64 (MustEnv), slakd :59 (MustEnv), twitd :41, webd :38, onbod :143
TypeURL
Defaultrequired in most adapters (MustEnv); webd/onbod default to http://routd:8080
Examplehttp://routd:8080

All adapters additionally read AUTHD_SERVICE_KEY and AUTHD_URL — they exchange that key for a service:<daemon> ES256 token and present it on every routd call. Most also read MEDIA_MAX_FILE_BYTES.

teled (Telegram)

Reads TELEGRAM_BOT_TOKEN (MustEnv), ASSISTANT_NAME, DATA_DIR, plus the adapter common surface. No teled-specific env vars beyond these.

discd (Discord)

DISCORD_BOT_TOKEN

Bot token. Required unless DISCORD_USER_TOKEN is set instead.

Read bydiscd / discd/main.go:52
Typestring
Default"" (refuses to start if both bot/user tokens empty)
ExampleMTAxNTM4...

DISCORD_USER_TOKEN

User-account token; selects user-mode operation, bypassing bot intents. Mutually exclusive with the bot token.

Read bydiscd / discd/main.go:53
Typestring
Default""
Examplemfa.xxxxx

whapd (WhatsApp)

WHATSAPP_AUTH_DIR

Directory where Baileys multi-file auth state (creds, keys) is persisted.

Read bywhapd / whapd/src/main.ts:44
Typepath
Default$DATA_DIR/store/whatsapp-auth or /srv/data/store/whatsapp-auth
Example/srv/data/arizuko_krons/store/whatsapp-auth

whapd also reads ASSISTANT_NAME, DATA_DIR, ROUTER_URL, LISTEN_ADDR, LISTEN_URL.

bskyd (Bluesky)

BLUESKY_IDENTIFIER

AT Protocol handle or DID the adapter logs in as.

Read bybskyd / bskyd/main.go:53 (MustEnv)
Typestring
Defaultrequired
Examplearizuko.bsky.social

BLUESKY_PASSWORD

App password for the Bluesky account.

Read bybskyd / bskyd/main.go:54 (MustEnv)
Typestring
Defaultrequired
Examplexxxx-xxxx-xxxx-xxxx

BLUESKY_SERVICE

PDS endpoint to authenticate against.

Read bybskyd / bskyd/main.go:55
TypeURL
Defaulthttps://bsky.social
Examplehttps://bsky.social

reditd (Reddit)

REDDIT_CLIENT_ID

OAuth client id of the registered Reddit app.

Read byreditd / reditd/main.go:65 (MustEnv)
Typestring
Defaultrequired
Exampleabc123

REDDIT_CLIENT_SECRET

OAuth client secret of the registered Reddit app.

Read byreditd / reditd/main.go:66 (MustEnv)
Typestring
Defaultrequired
Examplexyz789

REDDIT_PASSWORD

Password for the bot account (script OAuth flow).

Read byreditd / reditd/main.go:68 (MustEnv)
Typestring
Defaultrequired
Examplehunter2

REDDIT_POLL_INTERVAL

How often reditd polls subreddits for new posts/comments.

Read byreditd / reditd/main.go:77
TypeGo duration string
Default5m
Example2m

REDDIT_SUBREDDITS

CSV of subreddit names to monitor.

Read byreditd / reditd/main.go:58
TypeCSV string
Default""
Exampleselfhosted,homelab

REDDIT_USER_AGENT

User-Agent string used in Reddit API calls (Reddit policy requires a descriptive UA).

Read byreditd / reditd/main.go:70
Typestring
Defaultarizuko/1.0
Examplearizuko-krons/1.0 by u/op

REDDIT_USERNAME

Username of the bot account.

Read byreditd / reditd/main.go:67 (MustEnv)
Typestring
Defaultrequired
Examplearizuko_bot

emaid (Email)

EMAIL_ACCOUNT

Email address / IMAP+SMTP login username.

Read byemaid / emaid/main.go:58 (MustEnv)
Typestring
Defaultrequired
Examplebot@example.com

EMAIL_IMAP_HOST

IMAP server hostname.

Read byemaid / emaid/main.go:56 (MustEnv)
Typestring
Defaultrequired
Exampleimap.gmail.com

EMAIL_IMAP_PORT

IMAP server port.

Read byemaid / emaid/main.go:60
Typestring (port)
Default993
Example993

EMAIL_PASSWORD

Login password / app password for IMAP+SMTP.

Read byemaid / emaid/main.go:59 (MustEnv)
Typestring
Defaultrequired
Examplexxxx xxxx xxxx xxxx

EMAIL_SMTP_HOST

SMTP server hostname.

Read byemaid / emaid/main.go:57 (MustEnv)
Typestring
Defaultrequired
Examplesmtp.gmail.com

EMAIL_SMTP_PORT

SMTP server port.

Read byemaid / emaid/main.go:61
Typestring (port)
Default587
Example587

EMAIL_STRICT_AUTH

Reject inbound mail outright when SPF/DKIM/DMARC fails (fail-closed). When unset (default), failed-auth messages still reach the agent but flagged untrusted in the envelope. Spec 11/17.

Read byemaid / emaid/auth.go:64
Typebool (truthy strings: 1, true, yes, on)
Defaultfalse
Exampletrue

EMAIL_TRUSTED_AUTHSERV

Hostname of the upstream MTA whose Authentication-Results header emaid will trust (e.g. mx.google.com for Gmail). When unset, every inbound is classified untrusted (fail-closed default per spec 11/17). Added v0.40.5.

Read byemaid / emaid/auth.go:63
Typestring (hostname, lowercased)
Defaultunset
Examplemx.google.com

EMAIL_TRUSTED_DOMAINS

Comma-separated allowlist of sender domains that count as trusted (matched against the From-address domain after DMARC alignment). Empty entries ignored. Both this and EMAIL_TRUSTED_AUTHSERV must agree for a message to be trusted. Added v0.40.5.

Read byemaid / emaid/auth.go:68
Typecomma-separated list
Defaultunset (no domain allowlist)
Exampleexample.com, partner.org

twitd (X / Twitter)

TWITTER_2FA_SECRET

TOTP shared secret used to mint 2FA codes during automated login.

Read bytwitd / twitd/src/main.ts:38
Typestring (base32 TOTP secret)
Defaultunset (login may fail when 2FA prompted)
ExampleJBSWY3DPEHPK3PXP

TWITTER_AUTH_DIR

Persistent dir for cookies + cursor state across restarts.

Read bytwitd / twitd/src/main.ts:30
Typepath
Default$DATA_DIR/store/twitter-auth or /srv/data/store/twitter-auth
Example/srv/data/arizuko_krons/store/twitter-auth

TWITTER_EMAIL

Email associated with the X account; sometimes required as a fallback identifier during login.

Read bytwitd / twitd/src/main.ts:37
Typestring
Defaultunset
Examplebot@example.com

TWITTER_PASSWORD

Password for the X account.

Read bytwitd / twitd/src/main.ts:36
Typestring
Defaultunset
Examplehunter2

TWITTER_POLL_INTERVAL

Mentions/DM poll cadence. Accepts plain seconds (90), Ns, or Nm.

Read bytwitd / twitd/src/main.ts:45
Typeseconds (int or Ns/Nm)
Default90
Example5m

TWITTER_USERNAME

Username/handle for the X account.

Read bytwitd / twitd/src/main.ts:35
Typestring
Defaultunset
Examplearizuko_bot

linkd (LinkedIn)

LINKEDIN_ACCESS_TOKEN

Pre-acquired OAuth access token; if unset, linkd runs an interactive auth flow.

Read bylinkd / linkd/main.go:62
Typestring
Default""
ExampleAQX...

LINKEDIN_API_BASE

Base URL of the LinkedIn REST API.

Read bylinkd / linkd/main.go:69
TypeURL
Defaulthttps://api.linkedin.com
Examplehttps://api.linkedin.com

LINKEDIN_AUTO_PUBLISH

Allow the agent to publish posts without explicit operator confirmation.

Read bylinkd / linkd/main.go:72
Typebool ("true")
Defaultfalse
Exampletrue

LINKEDIN_CLIENT_ID

OAuth client id of the registered LinkedIn app.

Read bylinkd / linkd/main.go:60 (MustEnv)
Typestring
Defaultrequired
Example77abcde

LINKEDIN_CLIENT_SECRET

OAuth client secret of the registered LinkedIn app.

Read bylinkd / linkd/main.go:61 (MustEnv)
Typestring
Defaultrequired
Examplexyz123

LINKEDIN_OAUTH_BASE

Base URL for the LinkedIn OAuth endpoints.

Read bylinkd / linkd/main.go:70
TypeURL
Defaulthttps://www.linkedin.com
Examplehttps://www.linkedin.com

LINKEDIN_POLL_INTERVAL

Cadence at which linkd polls for new messages.

Read bylinkd / linkd/main.go:71
TypeGo duration string
Default300s
Example60s

LINKEDIN_REFRESH_TOKEN

Refresh token used to mint new access tokens.

Read bylinkd / linkd/main.go:63
Typestring
Default""
ExampleAQR...

slakd (Slack)

SLACK_BOT_TOKEN

Slack xoxb- bot token used by the Web API and Events API client.

Read byslakd / slakd/main.go:57 (MustEnv)
Typestring
Defaultrequired
Examplexoxb-...

SLACK_SIGNING_SECRET

Shared secret Slack uses to sign incoming event webhooks; slakd verifies X-Slack-Signature against it.

Read byslakd / slakd/main.go:58 (MustEnv)
Typestring
Defaultrequired
Example8f742231...

SLAKD_USERS_CACHE_TTL

TTL (seconds) of the Slack user-info cache; lower values cost more API quota.

Read byslakd / slakd/main.go:64
Typeint (seconds)
Default900 (15 min)
Example3600

split daemons (routd / runed / authd)

Three daemons split the work: routd (routing + message loop), runed (container spawn), and authd (auth + identity) — specs 5/E + 5/P. These vars wire them together.

AUTHD_URL

In-network base URL of authd. routd, runed, webd, and proxyd reach it for service-token exchange and JWKS. dashd uses it for both of those and as the backend for its /dash/authd/ page — the signing-key and session tables it reads over HTTP rather than by opening auth.db.

Read bycompose / compose/compose.go:434 → routd, runed, webd, proxyd, dashd
TypeURL
Defaulthttp://authd:8080
Examplehttp://authd:8080

AUTHD_SERVICE_KEY

Per-daemon shared secret a service daemon presents to authd to authenticate. Provisioned once per daemon and persisted to env/<daemon>.env; authd recognises them via AUTHD_SERVICE_KEYS.

Read bycompose / compose/compose.go:428 → routd, runed
Typestring (secret)
Defaultauto-provisioned at compose time
Example<random hex>

AUTHD_SERVICE_KEYS

The principal=secret pairs authd accepts, one per service daemon. Rotating a key here invalidates that daemon's in-flight service tokens.

Read bycompose / compose/compose.go:432 → authd
Typestring (comma-separated principal=secret)
Defaultauto-built from the provisioned service keys
Exampleservice:routd=...,service:runed=...

RUNED_URL

In-network base URL of runed (the container-runner plane). routd dispatches runs to it.

Read byroutd / routd/cmd/routd/main.go:40
TypeURL
Defaulthttp://runed:8080
Examplehttp://runed:8080

ROUTD_SERVICE_TOKEN

Service token routd presents to runed on each run dispatch.

Read byroutd / routd/cmd/routd/main.go:78
Typestring (token)
Defaultminted against AUTHD_URL using AUTHD_SERVICE_KEY
Example<jwt>

RUNED_SERVICE_TOKEN

Service token runed presents to authd when its broker authenticates.

Read byruned / runed/cmd/runed/main.go:74
Typestring (token)
Defaultminted against AUTHD_URL using AUTHD_SERVICE_KEY
Example<jwt>

the store server

Every owner's tables live on one DynamoDB-protocol server per instance — ExtendDB over PostgreSQL, shipped as the extenddb package. Each daemon reads the five keys below and signs as itself, so the server's policy can bound what each one reaches. A daemon without DYNAMODB_URL refuses to start: there is no file to fall back to. Bring-up, including the one-off extenddb init run that mints the keys, is in INSTALL.md § The store server.

DYNAMODB_URL

The endpoint this instance is served from, and the switch: set, every daemon opens its owner there and none opens a file. On an instance whose rows are still in files, set it only after those rows have been copied across — the daemons would otherwise boot onto empty tables and look healthy.

Read byevery daemon / objstore/dynstore/env.go
TypeURL (TLS; the server refuses to start without it)
Defaulthttps://extenddb:18443 once the package is added; unset = files
Examplehttps://extenddb:18443

STORE_CA

The endpoint's certificate, base64-encoded, because a daemon has its environment and no file of its own. extenddb init generates it; a value that is not base64 is refused at boot rather than surfacing later as a handshake failure against a name nobody typed.

Read byevery daemon / objstore/dynstore/env.go
Typestring (base64 PEM)
Default"" = the system roots
ExampleLS0tLS1CRUdJTiBDRVJUSUZJ...

AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY

One key pair per daemon, written into env/<daemon>.env and carried forward by every later arizuko generate. The pair is what the server's policy binds: routd reaches routd.*, dashd reaches routd's, onbod's and runed's, an adapter reaches its own prefix. A shared pair would make that boundary meaningless.

Read byevery daemon / objstore/dynstore/env.go, carried by compose/compose.go
Typestring (secret)
Defaultnone — an endpoint with no credential is refused at boot
Example<minted by extenddb manage>

AWS_REGION

The region the request is signed for. Any value works against a self-hosted server as long as every daemon uses the same one; it matters only if the endpoint is Amazon's own.

Read byevery daemon / objstore/dynstore/env.go
Typestring
Defaultus-east-1
Exampleus-east-1

STORE_DB_PASSWORD / STORE_APP_PASSWORD

The two passwords the package mints: the first owns the instance's PostgreSQL role, the second is the role the server itself connects with. Neither has a meaning a human could supply, so arizuko packages add extenddb generates both into .env.

Read bythe extenddb compose fragment / template/services/extenddb.yml
Typestring (secret)
Defaultgenerated on packages add
Example<random hex>

observability — OTLP export

slog to journald is always on. Setting the OTLP endpoint additionally fans every slog event out to an OpenTelemetry collector (spec 5/O, library obs/). Unset = zero overhead. The litellm gateway reads the same three keys (OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_PROTOCOL, OTEL_EXPORTER_OTLP_HEADERS) and, when the endpoint is set, sends one span per model request to <endpoint>/v1/traces with token counts and cost — message content excluded.

OTEL_EXPORTER_OTLP_ENDPOINT

OTLP/HTTP collector endpoint. When set, every daemon's obs.Setup sends slog events to stderr and the collector; records carrying turn_id get a deterministic TraceID so one turn's events group. When empty, only the stderr JSON handler runs.

Read byobs / obs/obs.go:36 (every daemon's main)
TypeURL
Default"" = OTLP disabled
Examplehttp://collector:4318

Not documented here