Skip to content

Configuration reference

Every environment variable daimon reads. Generated from the settings models themselves by scripts/generate_config_reference.py — edit the Field(description=...) in the model, not this page. CI fails when the two disagree.

Values come from the process environment and, for the daimon processes, from a .env file in the working directory. .env.example lists the same DAIMON_* variables in copy-paste form; this page adds the types, the defaults and the two standalone services. Nested blocks use __ as the delimiter, so DAIMON_MCP__JWT_SECRET is Settings.mcp.jwt_secret.

Unknown DAIMON_* variables are ignored rather than rejected (extra="ignore"), so a typo is silent — check the spelling here.

Contents

Core

Read from daimon.core.config.Settings. Prefix DAIMON_. Every other DAIMON_* section below is a nested block on this model, reached with the __ delimiter.

DAIMON_SECURITY_AUDIT_RETENTION_DAYS

int · optional · default 90

Security audit retention age in days, default 90. Operators must schedule daimon audit prune TENANT_UUID for each tenant (for example daily). The command deletes older events. Set 0 to explicitly retain events forever; privacy erasure and tenant deletion still apply.

DAIMON_COMPLETION_PINGS

dict[UUID, bool] · optional · default {}

Per-tenant completion notification policy, keyed by tenant UUID. True enables accepted/done reactions and posts the final answer as a fresh reply mentioning only the requester on Discord and Slack. On Teams it closes the status card and posts the answer fresh, mentioning the requester in channels (Teams bots cannot react). Missing/false preserves in-place delivery. Configure DAIMON_COMPLETION_PINGS as a JSON object.

DAIMON_BUDGET_NOTICES

dict[UUID, bool] · optional · default {}

Per-tenant switch for the channel budget notice, keyed by tenant UUID. When a channel's budget is used up, its channel admins (else the server admins) get one DM per budget window on Discord, Slack and Teams. Missing/true sends it; false turns it off. Configure DAIMON_BUDGET_NOTICES as a JSON object.

DAIMON_DIRECT_MESSAGE_POLICIES

dict[UUID, DirectMessagePolicy] · optional · default {}

Per-tenant DM recipient policies keyed by tenant UUID (normalized at load; invalid keys rejected). Default is members (live membership required). Set mode=disabled to disable DMs, or mode=allowlist with recipient_ids to restrict delivery to listed members. Configure DAIMON_DIRECT_MESSAGE_POLICIES as a JSON object.

DAIMON_TABLE_RENDERING

dict[UUID, bool] · optional · default {}

Per-tenant table rendering opt-in, keyed by tenant UUID. True renders final Markdown tables as PNG on Discord and native tables on Slack. Missing/false preserves plain text. Set DAIMON_TABLE_RENDERING to a JSON object.

DAIMON_PRIVACY_POLICY_URL

HttpUrl · optional · default https://github.com/pymc-labs/daimon/blob/main/PRIVACY.md

URL rendered on the privacy panels' Policy button. Override via DAIMON_PRIVACY_POLICY_URL if you host your own policy page.

DAIMON_DEFAULTS_ROOT

Path · optional · default defaults

Filesystem path to the seeded defaults/ directory consumed by daimon.core.defaults.apply.apply_defaults. Default Path('defaults') is relative to the process cwd — works for in-repo dev (repo root) and the deployed container layout (working dir contains defaults/ at root). Single source of truth shared by the scheduler, Discord/Slack adapters, CLI session bootstrap, and MCP routine tools. Do NOT add adapter-local defaults_root fields — they invite drift.

Database

Read from daimon.core.config.DatabaseSettings. Prefix DAIMON_DATABASE__.

DAIMON_DATABASE__URL

PostgresDsn · required

Postgres connection string used by the running application (SQLAlchemy async + asyncpg). Required.

DAIMON_DATABASE__TEST_URL

PostgresDsn | None · optional · default unset

Postgres connection string for the test suite. Points at a dedicated database (e.g. daimon_test) so test runs never touch development data. Unset in production.

DAIMON_DATABASE__POOL_SIZE

int · optional · default 5

Persistent Postgres connections per process. Default 5; size against all application processes and the database connection limit.

DAIMON_DATABASE__MAX_OVERFLOW

int · optional · default 10

Temporary Postgres connections above pool_size per process. Default 10; include these in the database connection budget. pool_size + max_overflow must be at least 4; smaller pools are rejected at engine startup to reserve independent preparation and mutation capacity with nested query headroom. Fence contenders release connections and permits between nonblocking attempts, retrying with 25-75 ms jitter for at most 5 seconds before retryable session busy.

DAIMON_DATABASE__POOL_TIMEOUT

float · optional · default 30.0

Seconds to wait for a free Postgres connection before failing. Default 30 seconds.

DAIMON_DATABASE__PREPARATION_CONCURRENCY

int | None · optional · default unset

Maximum concurrent session preparations holding a Postgres advisory-lock transaction per process. Unset uses half of pool_size (at least one), leaving connections for preparation's nested queries and turn outcomes. Keep this below pool_size so nested queries have headroom. Excess preparations wait in memory instead of timing out in the DB pool.

Anthropic

Read from daimon.core.config.AnthropicSettings. Prefix DAIMON_ANTHROPIC__.

DAIMON_ANTHROPIC__API_KEY

SecretStr · required · secret

Anthropic API key used to authenticate all Managed Agents SDK calls. Required.

DAIMON_ANTHROPIC__BASE_URL

HttpUrl · optional · default https://api.anthropic.com

Base URL for the Anthropic API. Override only when routing through a proxy or a non- default API endpoint.

DAIMON_ANTHROPIC__SKILLS_REQUESTS_PER_MINUTE

int · optional · default 80

Maximum Anthropic Skills API requests per minute in this process. Default 80 leaves headroom below the 100 requests/minute organization limit. Other deployments in the same organization share that limit.

CLI

Read from daimon.core.config.CLISettings. Prefix DAIMON_CLI__.

DAIMON_CLI__LOCAL_USER

str · optional · default read from the process environment

Display name used to identify the local operator running the CLI. Defaults to the $USER environment variable, falling back to 'daimon' when unset.

Logging

Read from daimon.core.config.LogSettings. Prefix DAIMON_LOG__.

DAIMON_LOG__LEVEL

'DEBUG' | 'INFO' | 'WARNING' | 'ERROR' · optional · default INFO

Minimum log level emitted by the structured logger.

Observability

Read from daimon.core.config.ObservabilitySettings. Prefix DAIMON_OBSERVABILITY__.

DAIMON_OBSERVABILITY__HEALTH_INTERVAL_S

float · optional · default 30

Seconds between runtime.health structured log lines from each long-running process. Default 30; set DAIMON_OBSERVABILITY__HEALTH_INTERVAL_S=0 to disable.

Ops

Read from daimon.core.config.OpsSettings. Prefix DAIMON_OPS__.

DAIMON_OPS__ALERT_WEBHOOK_URL

SecretStr | None · optional · default unset · secret

Discord webhook URL for short operator alerts about new installs, Stripe top-ups, and Anthropic limits. Unset disables alerts. Keep the URL secret.

MCP Server

Read from daimon.core.config.McpSettings. Prefix DAIMON_MCP__.

MCP adapter config.

Both fields are optional so deployments that don't run the MCP adapter keep working. The create_mcp_app factory re-validates presence at server-boot time (raises BootstrapError on miss); ensure_mcp_vault at session-create time skips silently when public_url is None.

DAIMON_MCP__JWT_SECRET

SecretStr | None · required to run the MCP adapter · default unset · secret

Secret used to sign and verify MCP bearer tokens. Required to run the MCP adapter.

DAIMON_MCP__PUBLIC_URL

HttpUrl | None · required to run the MCP adapter · default unset

Externally reachable base URL of the MCP server (the streamable endpoint, e.g. https://mcp.example.com/mcp). Required to run the MCP adapter — used to build OAuth/CLI/health route URLs and session-create metadata.

DAIMON_MCP__FILE_STORE_DIR

Path | None · optional · default unset

On-disk directory for the media-tool FileStore. When unset, the server uses tempfile.gettempdir() / 'daimon-mcp-files' resolved at startup.

DAIMON_MCP__BUNDLE_MAX_BYTES

int · optional · default 26214400

Per-upload byte cap enforced by the bundle upload route. The default keeps headroom under a 32 MiB proxy request limit; raise it if the front end in front of the mcp service allows larger bodies.

DAIMON_MCP__BUNDLE_UPLOADS_PER_HOUR

int · optional · default 20

Per-token cap on bundle upload route calls per rolling hour. Prevents a compromised or buggy caller from exhausting the Files API upload path. Set to 0 to disable (not recommended in production).

DAIMON_MCP__BUNDLE_TTL_DAYS

int · optional · default 90

How long an uploaded bundle object is retained on the Files API before deletion. Deletion is performed by the scheduler's pending-file sweeper, not by this process directly — a deployment running no scheduler will never reclaim these objects.

DAIMON_MCP__OPERATOR_CALLS_PER_MINUTE

int · optional · default 60

Per-token cap on tool calls an operator token (minted with daimon mcp mint-operator- token) may make per rolling minute, counted in each MCP process. Set to 0 to disable.

Hub

Read from daimon.core.config.HubSettings. Prefix DAIMON_HUB__.

OAuth-login MCP mounts for coding-agent clients.

A platform's mount appears only when both its client id and secret are set; a deployment that sets neither runs exactly as before. The signing key is shared by both mounts and must be a base64url 32-byte key, the same shape as a Fernet key, so the proxy uses it directly rather than deriving one from the client secret (rotating a client secret would otherwise invalidate every issued login).

DAIMON_HUB__SLACK_CLIENT_ID

str | None · optional · default unset

Slack OAuth app client ID for the /slack/mcp login mount. Register <DAIMON_MCP__PUBLIC_URL origin>/slack/auth/callback as a redirect URL on the Slack app.

DAIMON_HUB__SLACK_CLIENT_SECRET

SecretStr | None · optional · default unset · secret

Slack OAuth app client secret for the /slack/mcp login mount.

DAIMON_HUB__DISCORD_CLIENT_ID

str | None · optional · default unset

Discord OAuth app client ID for the /discord/mcp login mount. Register <DAIMON_MCP__PUBLIC_URL origin>/discord/auth/callback as a redirect URI on the Discord app.

DAIMON_HUB__DISCORD_CLIENT_SECRET

SecretStr | None · optional · default unset · secret

Discord OAuth app client secret for the /discord/mcp login mount.

DAIMON_HUB__ALLOWED_CLIENT_REDIRECT_URIS

list[str] · optional · default ['http://localhost:*', 'http://127.0.0.1:*', 'https://claude.ai/*', 'https://claude.com/*']

Redirect URI patterns an MCP client may register with the hub login mounts (wildcards allowed). Defaults cover coding agents on loopback and claude.ai; widen only for a client you operate.

DAIMON_HUB__JWT_SIGNING_KEY

SecretStr | None · optional · default unset · secret

Base64url 32-byte key that signs hub login tokens. Required when any hub mount is configured, and rejected at boot unless it decodes to exactly 32 bytes. Generate with Fernet.generate_key().

Discord

Read from daimon.core.config.DiscordSettings. Prefix DAIMON_DISCORD__.

Discord adapter config.

Optional so non-Discord deployments keep working. The __main__.py entrypoint validates presence at boot time.

This whole block is optional: it stays unset until at least one of its variables is set, and the features that read it are inactive while it is.

DAIMON_DISCORD__BOT_TOKEN

SecretStr · required · secret

Discord bot token. Required to run the Discord adapter.

DAIMON_DISCORD__THREAD_OPEN_NOTICE_AFTER_S

float · optional · default 3.0

Seconds after an admitted opening mention before replying in the parent channel that its Discord thread is still opening. Includes thread naming and Discord rate-limit waits. Set to 0 to reply immediately. The notice is edited with a thread link or retry guidance when creation finishes.

DAIMON_DISCORD__MAX_CONCURRENT_TURNS_PER_TENANT

int · optional · default 3

Maximum number of agent turns a single tenant (Discord guild) may have in flight at once. Caps one noisy guild from starving others on the shared Anthropic key.

DAIMON_DISCORD__MAX_CONCURRENT_TURNS

int | None · optional · default unset

Maximum Discord agent turns running across all guilds and DMs in this process. Unset leaves deployment-wide admission unlimited. Excess turns are refused with a retry notice; continuation wakes keep their existing admission path.

DAIMON_DISCORD__HEALTH_PORT

int · optional · default 8081

Port for the Discord process's liveness endpoint. Must not collide with the mcp process (8080) or the scheduler process (8082) — all process groups share one host.

DAIMON_DISCORD__QA_BOT_USER_IDS

tuple[str, ...] · optional · default unset

Discord user ids of automated QA bots allowed to start turns by mention. Bot-authored mentions are rejected by default; these are allow-listed so a harness can drive the mention path end-to-end without a human. Several are supported because admin-gated tools need a caller holding Manage Server while the refusal paths need one without it. Leave empty outside test deployments -- an allow-listed bot spends real credit. As a tuple field this must be set as a JSON array, e.g. '["123","456"]'. daimon's own id is refused at the gate even if listed.

DAIMON_DISCORD__BOT_DISPLAY_NAME

str · optional · default daimon

The bot's presented name across user-facing Discord render sites (@mentions, setup messages, help text, privacy panel copy). Defaults to 'daimon' so unset deployments render byte-identical output. Set to a distinct name (e.g. 'daimon-staging') so a non- production deployment is visibly distinct in-channel.

Thread Participation

Read from daimon.core.config.ThreadParticipationSettings. Prefix DAIMON_THREAD_PARTICIPATION__.

Organic thread participation: replying in a thread unprompted.

Platform-agnostic settings (the store and tool are keyed by platform); the Discord and Teams adapters read them. mode is the deployment tier of a cascade (deployment, workspace, channel, thread) that the agent's set_thread_participation tool writes the other tiers of. off (the default) changes nothing for anyone: no classifier runs and every server behaves as today until someone asks the agent to follow a thread, or an admin turns a channel or the workspace on. disabled also refuses those requests. on follows every thread unless a lower tier says otherwise.

Replying in threads unprompted. See ThreadParticipationSettings.

DAIMON_THREAD_PARTICIPATION__MODE

ParticipationMode · optional · default off

Deployment default for replying in threads unprompted. off: mention-only until a thread, channel or workspace is turned on. disabled: mention-only and cannot be turned on. on: follow every thread unless turned off below.

DAIMON_THREAD_PARTICIPATION__QUIET_SECONDS

float · optional · default 8.0

How long a followed thread must be quiet after an unprompted message before the agent decides whether to reply. A burst of messages is judged once, at the end.

DAIMON_THREAD_PARTICIPATION__MAX_PER_HOUR

int · optional · default 20

Backstop: maximum unprompted replies per thread per rolling hour.

DAIMON_THREAD_PARTICIPATION__RECENT_MESSAGES_WINDOW

int · optional · default 10

How many earlier thread messages the classifier sees before deciding.

DAIMON_THREAD_PARTICIPATION__CLASSIFIER_MODEL

str · optional · default claude-haiku-4-5

Model that decides whether a burst of unprompted messages deserves a reply. One short call per quiet burst; a small, fast model is the point.

Slack

Read from daimon.core.config.SlackSettings. Prefix DAIMON_SLACK__.

Slack adapter config.

Optional so non-Slack deployments boot unchanged — the block is None when no DAIMON_SLACK__* env vars are present. Mirrors DiscordSettings.

The OAuth/install flow reads these fields: client_id / client_secret for the code-exchange, signing_secret for request verification, app_token for Socket Mode.

This whole block is optional: it stays unset until at least one of its variables is set, and the features that read it are inactive while it is.

DAIMON_SLACK__BOT_DISPLAY_NAME

str · optional · default daimon

The bot's presented name in Slack setup, help, and privacy messages.

DAIMON_SLACK__SIGNING_SECRET

SecretStr · required · secret

Slack request-signing secret used to verify inbound HTTP requests. Required — keeps the whole Slack block None when no DAIMON_SLACK__* vars are set.

DAIMON_SLACK__APP_TOKEN

SecretStr · required · secret

Slack app-level token (xapp-...) used to open the Socket Mode connection.

DAIMON_SLACK__CLIENT_ID

str | None · optional · default unset

Slack OAuth app client ID, used during the 'Add to Slack' install flow.

DAIMON_SLACK__CLIENT_SECRET

SecretStr | None · optional · default unset · secret

Slack OAuth app client secret, used during the 'Add to Slack' install flow.

DAIMON_SLACK__MAX_CONCURRENT_TURNS_PER_TENANT

int · optional · default 3

Maximum number of agent turns a single tenant (Slack workspace) may have in flight at once. Caps one noisy workspace from starving others on the shared Anthropic key.

DAIMON_SLACK__HISTORY_PAGE_LIMIT

int · optional · default 100

Messages requested per conversations.replies call when replaying thread history. Slack clamps this per workspace: an app commercially distributed outside the Marketplace gets 15 whatever it asks for, an internal-app install gets the full page up to 1000, which is also the largest value Slack accepts. The default matches the 100 messages Discord replays; every replayed message is first-turn context the model pays for.

DAIMON_SLACK__HEALTH_PORT

int · optional · default 8083

Port for the Slack process's liveness endpoint. Must not collide with the mcp process (8080), the discord process (8081), or the scheduler process (8082) — all process groups share one host.

Teams

Read from daimon.core.config.TeamsSettings. Prefix DAIMON_TEAMS__.

Microsoft Teams adapter config.

Optional so non-Teams deployments boot unchanged — the block is None when no DAIMON_TEAMS__* env vars are present. Mirrors SlackSettings.

client_id / client_secret / tenant_id are the Entra app registration the Bot Framework posts activities to; port is the HTTP ingress the SDK's FastAPI adapter binds (/api/messages plus the /healthz / /readyz endpoints served by the same listener); enabled gates /api/messages without taking the process down.

This whole block is optional: it stays unset until at least one of its variables is set, and the features that read it are inactive while it is.

DAIMON_TEAMS__CLIENT_ID

str · required

Entra (Azure AD) app registration client ID the Teams bot authenticates as — also the audience inbound Bot Framework JWTs are validated against.

DAIMON_TEAMS__CLIENT_SECRET

SecretStr · required · secret

Entra app registration client secret, used to mint Bot Framework tokens for outbound sends.

DAIMON_TEAMS__TENANT_ID

str · required

Entra tenant ID the app registration lives in. A single-tenant bot only answers activities whose conversation and channel-data tenant both equal this value.

DAIMON_TEAMS__MAX_CONCURRENT_TURNS_PER_TENANT

int · optional · default 3

Maximum number of agent turns a single Teams tenant may have in flight at once. Caps one noisy tenant from starving others on the shared Anthropic key.

DAIMON_TEAMS__PORT

int · optional · default 3978

Port for the Teams process's HTTP ingress and health endpoints (/api/messages, /healthz, /readyz). The Bot Framework messaging endpoint must be configured to reach this listener.

DAIMON_TEAMS__ENABLED

bool · optional · default True

When False, /api/messages answers 503 while the health endpoints stay live — the process keeps running so ingress can be re-enabled without a redeploy.

DAIMON_TEAMS__PUBLIC_URL

HttpUrl | None · optional · default unset

Externally reachable base URL of the Teams service (the Bot Framework messaging endpoint without /api/messages). Enables the admin sign-in that grants daimon a team's SharePoint site; its callback is <public_url>/oauth/teams/files/callback, which must be a Web redirect URI on the app registration.

DAIMON_TEAMS__ADMIN_USER_IDS

tuple[str, ...] · optional · default unset

Entra object IDs of the people who administer this deployment from Teams. Teams exposes no admin role to bots, so this list is the admin check: admins get the admin role in turns, create routines, replace shared keys, top up and see everyone's usage. Everyone else is a regular user.

DAIMON_TEAMS__RESTRICT_GUESTS

bool · optional · default True

When True, guests (Entra B2B guest accounts in this tenant) are treated as people from another organisation: answered only in a channel kept to its own agents, with a few conversation tools and no commands or admin role. The tenant access policy's member guest list exempts some. When False, guests are treated as team members.

DAIMON_TEAMS__RESTRICT_EXTERNAL_PARTICIPANTS

bool · optional · default True

When True, a shared channel's external participants (people from another tenant, via B2B direct connect) are answered only in a channel kept to its own agents, with a few conversation tools and no commands or admin role. When False, they are treated as team members.

GitHub

Read from daimon.core.config.GithubSettings. Prefix DAIMON_GITHUB__.

GitHub repository access config (App-or-PAT; no OAuth flow). All fields are optional so deployments without GitHub App or PAT config keep working.

Cloning via the GitHub App requires only app_id + app_private_key. app_slug is needed only to construct the App's install link; a deployment that never surfaces that link can leave it unset. webhook_secret is optional and required only for the skill-sync push- driven resync webhook.

DAIMON_GITHUB__OAUTH_SCOPES

tuple[str, ...] · optional · default repo,read:user,read:org,workflow

OAuth scopes requested when a GitHub token-broker flow is used. Not consulted for GitHub App or PAT authentication.

DAIMON_GITHUB__APP_ID

str | None · optional · default unset

GitHub App ID used to mint short-lived installation tokens for repo cloning.

DAIMON_GITHUB__APP_PRIVATE_KEY

SecretStr | None · optional · default unset · secret

Private key (PEM) for the GitHub App identified by app_id.

DAIMON_GITHUB__APP_SLUG

str | None · optional · default unset

GitHub App's URL name, used to build the App's install link so members can be pointed at it from chat and from the setup panel. Cloning does not need it, so a deployment that never surfaces the install link can leave it unset.

DAIMON_GITHUB__WEBHOOK_SECRET

SecretStr | None · optional · default unset · secret

Secret used to verify GitHub webhook payload signatures. Required only to enable the skill-sync push-driven resync webhook.

DAIMON_GITHUB__FALLBACK_PAT

SecretStr | None · optional · default unset · secret

Operator-wide personal access token used as the clone credential for public-repo bindings that have no per-agent credential. Needs no scopes — any valid token clones a public repo.

DAIMON_GITHUB__MAX_TARBALL_BYTES

int · optional · default 52428800

Raw (compressed) size cap enforced while streaming a GitHub tarball download, checked against Content-Length when present and against the cumulative streamed byte count regardless. 50 MiB is the operator default. Set to 0 to disable (not recommended in production).

DAIMON_GITHUB__MAX_TARBALL_DECOMPRESSED_BYTES

int · optional · default 209715200

Decompressed (extracted) size cap enforced against the sum of tar member sizes before extraction, guarding against zip bombs. 200 MiB is the operator default. Set to 0 to disable (not recommended in production).

GitHub App

Read from daimon.core.config.GithubAppSettings. Prefix DAIMON_GITHUB_APP__.

Credentials for agent-scoped GitHub App access.

DAIMON_GITHUB_APP__APP_ID

str | None · optional · default unset

GitHub App ID for agent-scoped access.

DAIMON_GITHUB_APP__APP_SLUG

str | None · optional · default unset

GitHub App URL slug used for installation links.

DAIMON_GITHUB_APP__PRIVATE_KEY

SecretStr | None · optional · default unset · secret

GitHub App private key as PEM or base64-encoded PEM.

DAIMON_GITHUB_APP__WEBHOOK_SECRET

SecretStr | None · optional · default unset · secret

Secret for verifying this App's webhook signatures.

DAIMON_GITHUB_APP__CLIENT_ID

str | None · optional · default unset

GitHub App client ID for user authorization.

DAIMON_GITHUB_APP__CLIENT_SECRET

SecretStr | None · optional · default unset · secret

GitHub App client secret for user authorization.

Crypto

Read from daimon.core.config.CryptoSettings. Prefix DAIMON_CRYPTO__.

MultiFernet keys for at-rest token encryption.

A single deployment ships one key; rotation means prepending a new key. Each key must be a Fernet.generate_key()-style base64-urlsafe 32-byte string. A deployment without keys still boots, but refuses to save agent keys unless allow_plaintext opts into plaintext storage for local development.

DAIMON_CRYPTO__KEYS

tuple[SecretStr, ...] · optional · default unset · secret

Ordered Fernet keys used to encrypt/decrypt stored credentials: a single key, a comma- separated list, or a JSON list. Required to save agent keys: without keys, saving an agent environment value is refused unless allow_plaintext is set. The first key encrypts new values; older keys remain valid for decrypting existing ciphertext during rotation. Run daimon crypto verify to confirm no plaintext rows remain.

DAIMON_CRYPTO__ALLOW_PLAINTEXT

bool · optional · default False

Store agent environment values (agent keys) in plaintext when no keys are configured. For local development only: with this off and no keys, every agent key write is refused.

Credentials

Read from daimon.core.config.CredentialsSettings. Prefix DAIMON_CREDENTIALS__.

Tenant-level credentials for the token broker.

Optional — the Google Workspace provider raises a config error when google_sa_json is unset.

DAIMON_CREDENTIALS__GOOGLE_SA_JSON

SecretStr | None · optional · default unset · secret

Full JSON contents of a Google service-account key, used by the token broker to mint delegated Google Workspace credentials.

Gemini

Read from daimon.core.config.GeminiSettings. Prefix DAIMON_GEMINI__.

Optional Gemini API credentials for media MCP tools.

When unset, the media tools skip registration so the mcp process boots without them.

DAIMON_GEMINI__API_KEY

SecretStr | None · optional · default unset · secret

Gemini API key used by media-generation MCP tools. Tools are unregistered when unset.

Notebook Host

Read from daimon.core.config.NotebookSettings. Prefix DAIMON_NOTEBOOK__.

Optional notebook-host client config.

Both fields optional so deployments without a notebook host keep working. The MCP tool raises ToolError when host_url is unset.

DAIMON_NOTEBOOK__HOST_URL

HttpUrl | None · optional · default unset

Base URL of the notebook-host service (e.g. http://notebook-host:8001).

DAIMON_NOTEBOOK__ADMIN_SECRET

SecretStr | None · optional · default unset · secret

Bearer secret used to authenticate admin calls to the notebook-host service.

DAIMON_NOTEBOOK__PUBLISH_RATE_PER_HOUR

int · optional · default 30

Per-principal cap on publish_notebook calls per rolling hour. Prevents a compromised or buggy agent from exhausting the notebook host's process/port pool. Set to 0 to disable (not recommended in production).

DAIMON_NOTEBOOK__MAX_ATTACHMENT_BYTES

int · optional · default 10485760

Per-attachment size cap enforced by attach_notebook_data before uploading to the notebook host. 10 MiB is the operator default. Set to 0 to disable (the host's own ceiling still applies as defense-in-depth).

DAIMON_NOTEBOOK__MAX_SOURCE_BYTES

int · optional · default 1048576

Per-upload byte budget signed into notebook upload tokens. 1 MiB mirrors the notebook host's own ceiling, which is enforced independently as a second layer of defense.

DAIMON_NOTEBOOK__ALLOW_EDITABLE

bool · optional · default False

Let create_notebook_upload_url(editable=True) publish the marimo code editor. Anyone holding an editor link can run arbitrary code on the notebook host, and any member or prompt-injected agent can ask for one, so this stays off unless every notebook on the host belongs to one client. Off: scratch notebooks are always read-only.

Report Host

Read from daimon.core.config.ReportHostSettings. Prefix DAIMON_REPORT_HOST__.

Optional report-host client config.

Both fields optional so deployments without a report host keep working. The publishing MCP tool raises ToolError when host_url is unset.

DAIMON_REPORT_HOST__HOST_URL

HttpUrl | None · optional · default unset

Base URL of the report-host service (e.g. http://report-host:8002).

DAIMON_REPORT_HOST__ADMIN_SECRET

SecretStr | None · optional · default unset · secret

Bearer secret used to authenticate admin calls to the report-host service. Must be the same value the report host itself is configured with (its DAIMON_REPORT__ADMIN_SECRETS) — rotating one without the other breaks publishing.

Sentry

Read from daimon.core.config.SentrySettings. Prefix DAIMON_SENTRY__.

Sentry observability config.

All fields optional so deployments without Sentry keep booting. When dsn is None, Sentry initialization is a no-op.

DAIMON_SENTRY__DSN

SecretStr | None · optional · default unset · secret

Sentry DSN. When unset, error reporting is disabled entirely.

DAIMON_SENTRY__ENVIRONMENT

str · optional · default production

Environment tag attached to every Sentry event (e.g. 'production', 'staging').

DAIMON_SENTRY__TRACES_SAMPLE_RATE

float · optional · default 0.0

Fraction (0.0-1.0) of transactions sampled for Sentry performance tracing.

Billing Policy

Read from daimon.core.config.BillingSettings. Prefix DAIMON_BILLING__.

Money policy: markup multiplier and trial credit seed.

Distinct from BillingConfig (billing.py) which holds Stripe secrets (flat STRIPE_ env vars). BillingSettings is nested DAIMON_BILLING__ policy; BillingConfig is Stripe secrets. Keep both separate.

DAIMON_BILLING__MARKUP

Decimal · optional · default 1.0

Multiplier applied to raw Anthropic usage cost before billing the tenant. 1.0 = pass- through.

DAIMON_BILLING__SIGNUP_CREDIT

Decimal · optional · default 10.00

USD credit automatically seeded when a guild/workspace is provisioned, so a freshly- installed tenant can chat immediately on trial credit before paying. Set to 0 to require payment before use.

Support

Read from daimon.core.config.SupportSettings. Prefix DAIMON_SUPPORT__.

Human-support escalation: where requests land, and how many each user gets.

credits_per_user is a COUNT of human interactions, deliberately not the USD in BillingSettings.signup_credit. Sharing a ledger with billing would let a support request eat the tenant's ability to run turns, and would give a paid-up tenant unlimited support. Different unit, different table.

Discord and Teams requests go to escalation_channel_id (a Teams 19:… channel is posted by the Teams bot, any other id is a Discord channel); Slack requests go only to slack_escalation_channel_id, never to that channel. An unset channel disables the affordance it serves entirely rather than recording requests nobody will ever see. Failing closed is the honest behaviour: an escalate button that reaches no one is worse than no button, because the person believes they have asked for help. Every platform spends the same per-user, per-tenant allowance from one ledger.

DAIMON_SUPPORT__ESCALATION_CHANNEL_ID

str | None · optional · default unset

Channel id where human-support requests from Discord and Teams are posted: a Discord channel id, or a Teams channel id (19:…) that the Teams bot posts in. Teams requests reach a Discord channel only when the Discord bot token is also set. Unset (the default) disables the escalate affordance on Discord and Teams — a request that reaches nobody is worse than no button at all. A channel rather than operator DMs: it survives one person's DMs being closed, and it leaves a shared record anyone on the rota can pick up. The bot must be able to post there.

DAIMON_SUPPORT__SLACK_ESCALATION_CHANNEL_ID

str | None · optional · default unset

Slack channel id where human-support requests from Slack are posted. Unset (the default) disables the Ask a human button on Slack. Slack requests never go to the Discord channel, nor Discord requests here. The bot must be a member of the channel.

DAIMON_SUPPORT__SLACK_ESCALATION_TEAM_ID

str | None · optional · default unset

Slack workspace id (T…) that owns DAIMON_SUPPORT__SLACK_ESCALATION_CHANNEL_ID, for a deployment installed in several workspaces: every workspace's requests are posted with that workspace's bot token. Unset posts with the requesting workspace's own token, which suits a single-workspace install. daimon must be installed in the named workspace.

DAIMON_SUPPORT__CREDITS_PER_USER

int · optional · default 20

How many human-support requests each user gets within a tenant. A COUNT of interactions, NOT the USD in DAIMON_BILLING__SIGNUP_CREDIT — the two are deliberately separate ledgers. 0 disables escalation.

Thread Naming

Read from daimon.core.config.ThreadNamingSettings. Prefix DAIMON_THREAD_NAMING__.

Automatic Discord thread titles, generated by a metered Haiku call.

A top-level feature block (DAIMON_THREAD_NAMING__*), not a DiscordSettings field, per the feature-settings rule. Discord-only in effect: Slack threads have no title (tests/parity/ test_thread_naming_discord_only.py).

DAIMON_THREAD_NAMING__ENABLED

bool · optional · default True

Title bot-created Discord threads from the opening message with a short Haiku-generated name, chosen before the thread is created. The call is metered to the tenant like any other model call. Set false to keep the static 'Chat with <agent>' title.

DAIMON_THREAD_NAMING__MAX_INPUT_CHARS

int · optional · default 2000

Characters of the opening message sent to the naming model; longer messages are cut here. Bounds the per-thread naming cost.

DAIMON_THREAD_NAMING__TIMEOUT_SECONDS

float · optional · default 5.0

Seconds to wait for the naming model before the thread opens under the static title. The thread is created only after this call, so this is the most a mention can wait before anything appears.

Tool Safety

Read from daimon.core.config.ToolSafetyPolicy. Prefix DAIMON_TOOL_SAFETY__.

What the operator decided about attached tools.

Keys name a server (linear) or one tool on it (linear/create_issue); a tool key is more specific than its server key and wins.

Read/write classes and confirmation for attached third-party MCP tools. See ToolSafetyPolicy.

DAIMON_TOOL_SAFETY__ENABLED

bool · optional · default False

Classify attached (third-party) MCP tools as read or write and gate the writes: a write in chat waits for the requester to press Approve on a confirmation card, and a write in a routine or other unattended run is refused unless listed in unattended_writes. Applies to sessions created after it is set; a chat thread keeps its current session until that is replaced. Off keeps every tool auto-approved.

DAIMON_TOOL_SAFETY__EFFECTS

dict[str, 'read' | 'write'] · optional · default {}

Override the read/write class, e.g. {"linear/get_team": "read", "notion": "write"}. Keys are a server name or server/tool. Unlisted tools are classified from their name: a plain get_, list_, search_ ... is a read; a compound name (get_or_create, search_and_replace, run_query) and anything unknown is a write.

DAIMON_TOOL_SAFETY__DENIED

tuple[str, ...] · optional · default unset

Servers or server/tool pairs that are always refused, e.g. ["hubspot/delete_deal"].

DAIMON_TOOL_SAFETY__UNATTENDED_WRITES

tuple[str, ...] · optional · default unset

Servers or server/tool pairs whose writes may run in routines and other unattended runs, e.g. ["linear/create_issue"]. "*" allows every write there. Daimon's own add_skill never confirms unattended.

Artifacts

Read from daimon.core.config.ArtifactsSettings. Prefix DAIMON_ARTIFACTS__.

Optional private object storage for hosted-client artifacts.

This whole block is optional: it stays unset until at least one of its variables is set, and the features that read it are inactive while it is.

Optional private S3-compatible store for presigned chart links. Bounded image embeds still run when this is unset.

DAIMON_ARTIFACTS__ENDPOINT_URL

HttpUrl · required

S3-compatible bucket endpoint; used for uploads and presigned GET URLs.

DAIMON_ARTIFACTS__BUCKET

str · required

Private bucket name. Daimon never applies a public-read ACL.

DAIMON_ARTIFACTS__ACCESS_KEY_ID

SecretStr · required · secret

S3-compatible access key id.

DAIMON_ARTIFACTS__SECRET_ACCESS_KEY

SecretStr · required · secret

S3-compatible secret access key.

DAIMON_ARTIFACTS__REGION

str · optional · default us-east-1

S3 signing region supplied by the bucket provider.

DAIMON_ARTIFACTS__URL_TTL_SECONDS

int · optional · default 600

Lifetime of each presigned artifact GET URL; defaults to ten minutes.

DAIMON_ARTIFACTS__EMBED_IMAGES

bool · optional · default True

Also return bounded MCP image blocks for model vision. Disable independently when a hosted client cannot accept image content.

Scheduler

Read from daimon.adapters.scheduler.settings.SchedulerSettings. Prefix DAIMON_SCHEDULER__.

DAIMON_SCHEDULER__TICK_INTERVAL_S

float · optional · default 30.0

Seconds between scheduler ticks (loop sleep).

DAIMON_SCHEDULER__MAX_AGE_S

float · optional · default 900.0

Freshness window for routines with catch_up_policy=skip. Older slots are recorded as skipped and advanced; run-once routines ignore this window.

DAIMON_SCHEDULER__MAX_CONCURRENT_FIRES

int · optional · default 10

Global cap on simultaneously-dispatched routine fires across all ticks. Conservative against the shared Anthropic key's rate limit; per-tenant caps are enforced separately by the adapters.

DAIMON_SCHEDULER__DISPATCH_TIMEOUT_S

float · optional · default 3000.0

An OUTER PROCESS GUARD (asyncio.wait_for), not the turn's deadline. The core ~45-minute ceiling (daimon.core.turn.ceiling) is enforced inside headless_runner.run_turn and fires first, producing a TurnError(kind='ceiling'). This bound only catches a fire that hangs OUTSIDE the ceiling's two legs (routine row bookkeeping, agent/environment resolution, the usage-recorder factory, record_result), and must stay strictly above TURN_CEILING_S or the core ceiling becomes unreachable for routines. Each routine has its own timeout; continuous scheduler ticks do not await in-flight routines. Missed slots follow the routine's catch_up_policy.

DAIMON_SCHEDULER__ADVISORY_LOCK_KEY

int · optional · default 4918292864457134915

Postgres pg_try_advisory_lock int64 key. Default is the ASCII encoding of 'DAIMONSC'. Two scheduler processes share the key; the second logs that it did not get the lock and exits non-zero.

DAIMON_SCHEDULER__HEALTH_PORT

int · optional · default 8082

Port for the stdlib liveness responder (used by the platform health check). Must not collide with mcp's 8080 or discord's 8081 on the shared host.

Notebook host (standalone service)

Read from notebook_host.config.Settings. Prefix DAIMON_NOTEBOOK__.

A standalone service in apps/notebook-host, deployed and configured separately from the daimon processes. It is not part of docker-compose.yml.

This service shares the DAIMON_NOTEBOOK__ prefix with a block on daimon's own Settings, so DAIMON_NOTEBOOK__ADMIN_SECRET, DAIMON_NOTEBOOK__ALLOW_EDITABLE, DAIMON_NOTEBOOK__MAX_SOURCE_BYTES appear twice on this page — once for the service and once for the daimon side that calls it. They are read by different processes; a single shared env file would set both.

DAIMON_NOTEBOOK__DATA_DIR

Path · optional · default /data/notebooks

DAIMON_NOTEBOOK__ADMIN_SECRETS

list[SecretStr] · optional · default unset · secret

DAIMON_NOTEBOOK__ADMIN_SECRET

SecretStr | None · optional · default unset · secret

DAIMON_NOTEBOOK__HOST_PORT

int · optional · default 8001

DAIMON_NOTEBOOK__MARIMO_PORT_START

int · optional · default 8100

DAIMON_NOTEBOOK__MARIMO_PORT_END

int · optional · default 8160

DAIMON_NOTEBOOK__SUBPROCESS_TTL_SECONDS

int · optional · default 86400

DAIMON_NOTEBOOK__SWEEP_INTERVAL_SECONDS

int · optional · default 300

DAIMON_NOTEBOOK__SPAWN_TIMEOUT_SECONDS

float · optional · default 20.0

DAIMON_NOTEBOOK__VALIDATE_ON_PUBLISH

bool · optional · default True

DAIMON_NOTEBOOK__VALIDATION_TIMEOUT_SECONDS

float · optional · default 60.0

DAIMON_NOTEBOOK__PUBLIC_HOST

str · optional · default localhost

DAIMON_NOTEBOOK__PUBLIC_URL_BASE

str | None · optional · default unset

DAIMON_NOTEBOOK__MAX_SOURCE_BYTES

int · optional · default 1048576

DAIMON_NOTEBOOK__MAX_ATTACHMENT_BYTES_CEILING

int · optional · default 104857600

DAIMON_NOTEBOOK__MARIMO_RLIMIT_AS_BYTES

int · optional · default 4294967296

DAIMON_NOTEBOOK__MARIMO_RLIMIT_CPU_SECONDS

int · optional · default 3600

DAIMON_NOTEBOOK__JAIL_UID_START

int · optional · default 100000

DAIMON_NOTEBOOK__JAIL_UID_END

int · optional · default 100999

DAIMON_NOTEBOOK__ALLOW_UNJAILED_SPAWN

bool · optional · default False

DAIMON_NOTEBOOK__ALLOW_EDITABLE

bool · optional · default False

bool · optional · default False

DAIMON_NOTEBOOK__ORIGIN_BASE

str | None · optional · default unset

DAIMON_NOTEBOOK__ORIGIN_SCHEME

'https' | 'http' · optional · default https

DAIMON_NOTEBOOK__TENANTS

tuple[UUID, ...] · optional · default unset

Tenant UUIDs a public host without DAIMON_NOTEBOOK__ORIGIN_BASE accepts uploads from, comma-separated or as a JSON array of strings. Their notebooks share one browser origin and can reach each other, so list only tenants one operator controls. Empty refuses every upload. Ignored with ORIGIN_BASE (every notebook gets its own origin) and on localhost. An unlisted tenant's 403 names its id; daimon tenants list --json shows every tenant's id.

DAIMON_NOTEBOOK__UIDS_FILE

Path | None · optional · default unset

DAIMON_NOTEBOOK__PIDS_FILE

Path | None · optional · default unset

DAIMON_NOTEBOOK__BLOGS_FILE

Path | None · optional · default unset

DAIMON_NOTEBOOK__CONSUMED_FILE

Path | None · optional · default unset

DAIMON_NOTEBOOK__ALLOWED_ORIGINS

list[str] · optional · default unset

Report host (standalone service)

Read from report_host.config.Settings. Prefix DAIMON_REPORT__.

A standalone service in apps/report-host, deployed and configured separately from the daimon processes. It is not part of docker-compose.yml.

DAIMON_REPORT__DATA_DIR

Path · optional · default /data/reports

Root of the host's persistent volume: SQLite stores, bundles, PDFs.

DAIMON_REPORT__ADMIN_SECRETS

list[SecretStr] · optional · default unset · secret

CSV of bearer tokens accepted on admin routes (DAIMON_REPORT__ADMIN_SECRETS=primary,backup). At least one is required — the host refuses to start without one.

DAIMON_REPORT__MCP_URL

HttpUrl · required

The seam endpoint this host calls to run turns, poll cost, and mint tokens.

DAIMON_REPORT__PUBLIC_URL_BASE

HttpUrl · required

External URL prefix used to build recipient links and the per-turn upload URL handed to the agent.

DAIMON_REPORT__HOST_PORT

int · optional · default 8002

Port the host's uvicorn server binds.

DAIMON_REPORT__RESERVE_USD

Decimal · optional · default 0.60

Amount held against a report's spend cap the moment a turn starts, released and replaced by the real cost once the turn settles. Measured reader turns ran roughly sixteen to sixty-three cents; a revision-with-rebuild came in under this reserve.

DAIMON_REPORT__POLL_INTERVAL_SECONDS

float · optional · default 2.0

How often the host polls the seam for turn progress.

DAIMON_REPORT__TURN_TIMEOUT_SECONDS

int · optional · default 1200

A turn still running past this many seconds is cancelled by the host.

DAIMON_REPORT__MAX_PDF_BYTES

int · optional · default 52428800

Hard ceiling on an uploaded revised-PDF body size.

DAIMON_REPORT__MAX_BUNDLE_BYTES

int · optional · default 26214400

Hard ceiling on a published report bundle. Mirrors the seam's own bundle cap and is enforced independently here as a second layer of defense.

DAIMON_REPORT__MAX_OPEN_THREADS_PER_RECIPIENT

int · optional · default 3

Cap on concurrently open threads a single recipient may hold.

DAIMON_REPORT__MAX_RUNNING_TURNS_PER_REPORT

int · optional · default 4

Cap on concurrently running turns across one report's threads.

int · optional · default 90

How long a per-recipient link remains valid before expiring.

DAIMON_REPORT__THREAD_IDLE_ARCHIVE_HOURS

int · optional · default 24

A thread idle longer than this is archived by the host's sweep.

Billing (Stripe)

Read from the process environment by daimon.core.billing.load_billing_config, not from a settings model — these carry no DAIMON_ prefix. All seven are required together: with any one unset, billing is disabled rather than rejected, and the top-up flow cannot create a checkout session.

STRIPE_SECRET_KEY

str · required for billing · secret

Stripe API secret key used for checkout sessions.

STRIPE_WEBHOOK_SECRET

str · required for billing · secret

Signing secret for the Stripe webhook endpoint.

STRIPE_PRICE_10_USD

str · required for billing

Stripe price id for the $10 top-up.

STRIPE_PRICE_25_USD

str · required for billing

Stripe price id for the $25 top-up.

STRIPE_PRICE_50_USD

str · required for billing

Stripe price id for the $50 top-up.

STRIPE_PRICE_100_USD

str · required for billing

Stripe price id for the $100 top-up.

MCP_PUBLIC_URL

str · required for billing

Origin the checkout return URLs are built from — billing appends /billing/success and /billing/cancel to it. Separate from DAIMON_MCP__PUBLIC_URL, which billing does not read.

Docker Compose

Interpolated by docker-compose.yml itself; no daimon process reads them. They exist so the compose file can build DAIMON_DATABASE__URL for every service from one password.

POSTGRES_USER

str · optional · default daimon

Postgres superuser the postgres service is created with.

POSTGRES_PASSWORD

str · required

Its password. Required — every service interpolates it into DAIMON_DATABASE__URL behind a fail-fast ${VAR:?} guard. Keep it URL-safe (avoid @ : / % #): it is substituted raw into the asyncpg DSN.

POSTGRES_DB

str · optional · default daimon

Database created on first boot.

POSTGRES_PORT

str · optional · default 5432

Host port the container's 5432 is published on, on 127.0.0.1.