Skip to main content

Configuration

Daimon is configured entirely through environment variables. Every variable resolves in the same order: the process environment wins, and anything not set there falls back to the env file at ~/.daimon/env. Override the file's location with DAIMON_ENV_FILE.

The env file exists because hooks run in whatever environment the host process happened to inherit — a GUI-launched agent has no shell profile, so shell exports are not a reliable channel. Its format is KEY=VALUE lines; a leading export , surrounding quotes, blank lines, and # comments are tolerated. Keep it chmod 600 — it can hold API keys.

daimon configure manages the LLM backend knobs (see LLM backend) and writes them to ~/.daimon/env. Everything else you set by editing that file or exporting the variable.

Boolean variables accept 1, true, yes, or on as truthy (matched case-insensitively where noted). A handful use different conventions — kill switches that are on unless set to 0, or presence-based flags — and those are called out in the "What it does" column.

Core

VariableDefaultWhat it does
DAIMON_DISABLEoffKill switch. When truthy, every hook becomes a no-op — no capture, no briefing.
DAIMON_ENV_FILE~/.daimon/envPath to the env file that backs every other variable. Read from the process env only (it names the file, so it can't live inside it).
DAIMON_PROJECT_DIRunsetWorking directory of the session being briefed or serialized, used to route per-project checkpoints. Hooks pass the host's cwd through it; unset means the project is unknown and daimon falls back to the global pointer.
DAIMON_MIN_MESSAGES10Minimum message count before a session is worth serializing. Shorter sessions are skipped.
DAIMON_TIMEOUT420Total serialize budget in seconds, shared across retry attempts (per-attempt socket timeouts are capped to the remaining budget). Real serialize/merge calls on gateway and CLI backends run 74s–25min; keep ≥420 or slow calls and retries cannot fit.
DAIMON_HUNG_AFTER1800Seconds past which a serialize spawn that produced no result line is treated as hung/killed rather than still running. Default 30 min sits safely beyond a slow run (production serializes take 4–25 min).

Checkpoint store & GC

VariableDefaultWhat it does
DAIMON_CHECKPOINT_DIR~/.daimon/checkpointsRoot of the per-session checkpoint store.
DAIMON_CHECKPOINT_KEEP100How many per-session checkpoint files to retain (newest-N). Older files are garbage-collected after a successful write. 0 disables GC entirely (keep forever).
DAIMON_CHECKPOINT_HISTORY3How many checkpoint pointers to retain per directory (latest.json plus prev-1prev-(N-1)), so a failed serialize can fall back to a prior pointer. Minimum 1 (latest only).
DAIMON_GC_PIN_IMPORTANCE9Item-importance threshold that pins a checkpoint file against GC: a file whose max item importance reaches this survives outside the newest-N window. 0 disables pinning (pure recency window); values above 10 are clamped to 10.

Carry

Deterministic cross-session carry-over of unresolved items.

VariableDefaultWhat it does
DAIMON_CARRYonMaster switch for carry. On unless set to exactly 0 (any other value keeps it on).
DAIMON_CARRY_FLOOR0.05Minimum effective weight for a carried item to keep carrying. At the default, decisions expire in ~5–6 weeks (importance-graded) and escalated open questions live ~3–4 months.
DAIMON_CARRY_MAX8Cap on carried items per kind (native items never count against it or drop). Minimum 1.

Briefing

VariableDefaultWhat it does
DAIMON_BRIEF_MAX_TOKENS3000Token budget for the injected briefing, estimated at len(text)//4 (no tokenizer dependency). 0 = unbounded.
DAIMON_MAX_BRIEFING_DECISIONS10Cap on decisions shown in the briefing (render-time view only — the checkpoint keeps all of them). 0 = unbounded.
DAIMON_BRIEF_GLOBAL_FALLBACKheader-onlyControls the cross-project global-pointer fallback when a project has no checkpoint of its own. Default shows a header only; set to full (or 1) to inject the full foreign body.
DAIMON_STALE_DAYS7.0Age threshold (days) past which a carried item's effective last-verified stamp (its last_verified, else the latest resolutions.jsonl event, else first_seen) is stale enough for brief to warn about it. 0 warns on every carried item.
DAIMON_PLAINoffWhen truthy (case-insensitive), forces plain-text output — disables the rich tables/panels in status, brief, and --help.
NO_COLORunsetPresence-based, per the NO_COLOR convention: if the variable is set to any value (even empty), rich output is disabled.

Recall

VariableDefaultWhat it does
DAIMON_RECALL_DB~/.daimon/recall.dbLocation of the derived recall index (SQLite FTS). Never a source of truth — safe to delete at any time; recall rebuilds it by scanning the checkpoint and team dirs.
DAIMON_RECALL_SEEN_DIR~/.daimon/recall_seenPer-session suggestion-cooldown state so a repeated topic never re-injects. Disposable — deleting it only resets cooldowns.

Team memory

Opt-in shared-memory mirror. See docs/team.md for the full workflow.

VariableDefaultWhat it does
DAIMON_TEAMoffWhen truthy, mirror each checkpoint into the shared team dir so brief --team can surface teammates. Gates writes only — reads of the team dir are always allowed. A synced remote additionally requires the project to be in its scope allowlist (see team.md); out-of-scope projects mirror to the local dir only.
DAIMON_AUTHORgit user.name, then OS userTeam author identity used to namespace your checkpoints. Falls back to git config user.name, then the OS username, then unknown.
DAIMON_TEAM_DIR~/.daimon/teamRoot of the shared team-memory mirror.
DAIMON_TEAM_PROJECTunsetExplicit logical project path for this machine's sessions (relative, e.g. core/api-gateway). Overrides the sidecar's daimon-team.toml mapping and the origin-derived fallback when routing checkpoints under projects/.
DAIMON_TEAM_RETENTION_DAYS365Read-time age window: teammates' checkpoints older than this many days are skipped when reading. 0 = keep all. Never physically deletes from the shared append-only branch.
DAIMON_TEAM_APPLY_FORGEToffStanding consent for a TEAMMATE's published forget tombstone to rewrite this machine's own checkpoints. NOT sufficient alone — the apply also requires the typed daimon team sync --apply-forget, because a bare daimon team sync is spawned detached at SessionStart. Default off: a foreign tombstone always suppresses the value on read and in the index, but deleting local belief state from someone else's hash is a decision to make knowingly — the shared branch is append-only, so there is no undo.

Receipts

Opt-in signed provenance receipts (#204). When enabled, each checkpoint is paired with a vitni local-binding receipt: an Ed25519-signed statement that binds the checkpoint's exact on-disk bytes (outputs_hash) to its source transcript (inputs_hash), written to a <session>.receipt sidecar. This makes a post-hoc edit to a checkpoint file detectable. Receipts are fully valid offline — nothing leaves the machine.

Every step is fail-open: a missing CLI, missing openssl, timeout, or bad output logs one line to serialize.log and proceeds without a receipt — a receipts failure never blocks or fails a serialize or a briefing. Verify a checkpoint on demand with daimon verify-receipt [session]; at briefing time a receipt-era checkpoint whose receipt is missing or no longer matches its bytes has its ✓ verbatim labels degraded with a visible note.

Public-key derivation prefers the vitni CLI's keygen command (vitni 0.5.0+) and falls back to openssl on older CLIs or a failed probe — so on macOS, where Apple's LibreSSL has no Ed25519 in openssl pkey, receipts work once vitni ≥ 0.5.0 is installed, with no openssl-with-Ed25519 required.

VariableDefaultWhat it does
DAIMON_RECEIPTSoffWhen truthy, mint a signed receipt beside each checkpoint. Default off — a new subprocess per serialize is opt-in.
DAIMON_VITNI_CLIvitni-verify (on PATH)The vitni verifier CLI used to sign/verify. A path or a name resolved on PATH. Contract: <cli> <command> with one JSON object on stdin and one JSON line on stdout.
DAIMON_KEYS_DIR~/.daimon/keysWhere the Ed25519 signing seed (signing.seed, mode 0600, auto-created on first mint) and cached public key (signing.pub.json) live.

Host hooks

Serialize-throttle knobs for hosts that lack a clean session-end event. See docs/hosts/ for per-host setup.

VariableDefaultWhat it does
DAIMON_CODEX_SERIALIZE_ON_STOPonWhether the Codex Stop hook serializes at all. On unless set to 0, false, no, or off (case-insensitive).
DAIMON_CODEX_MIN_SERIALIZE_INTERVAL300Minimum seconds between Codex serialize spawns. 0 serializes on every Stop.
DAIMON_WINDSURF_MIN_SERIALIZE_INTERVAL300Minimum seconds between Windsurf serialize spawns (Windsurf has no session-end event, so capture runs on this throttle). 0 serializes every turn.
DAIMON_WINDSURF_FINALIZER_QUIET_SECONDS600Quiet period after the last Windsurf activity before a debounced finalizer serializes the trajectory's final transcript state — covers sessions whose last turns land inside the throttle window. Fractional values accepted; 0 disables the finalizer.
DAIMON_WINDSURF_DIR~/.daimon/windsurfWhere the Windsurf adapter keeps the transcripts it accumulates. Read by both the hook that writes them and the forget/heal paths that delete them — change it in one place only, or the writer and the deleter stop agreeing.
DAIMON_WINDSURF_STATE_DAYS7Age window for daimon-authored Windsurf transcripts and unparsed payload dumps, reaped by daimon heal. A privacy bound: a forgotten value cannot be located inside prose, so this limits how long the source conversation lingers between forget runs. Clamped to at least 1 — unlike the other Windsurf knobs, 0 does not disable it.

Ops & diagnostics

VariableDefaultWhat it does
DAIMON_LOG_DIR~/.daimon/logsLog directory. serialize-crash.log honors this on both sides — the hooks that spawn the serialize child read it (process env and this file) exactly as the CLI does, because daimon forget deletes that file and writer and deleter must agree on where it is. serialize.log is the exception: the hooks still write it to ~/.daimon/logs unconditionally, and this override only moves where the CLI (and tests) look for it.
DAIMON_CLAUDE_PROJECTS_DIR~/.claude/projectsWhere host transcripts live (<slug>/<session>.jsonl). Read-only — the quote-reverification audit reads them to re-check stored quotes against their source.
DAIMON_SCAR_HARVESToffWhen truthy, draft scar (negative-knowledge) candidates from the transcript at session-end.

LLM backend

Serialization needs an LLM endpoint. daimon configure is the intended way to set these. The URL, key, and model each fall back to a LITELLM_* variable if the DAIMON_* form is unset.

VariableDefaultWhat it does
DAIMON_LLM_BACKENDautoTransport: auto (litellm if credentials exist, else a named command CLI if one resolves), litellm, command, or claude-cli. claude-cli is the zero-config option: it runs a claude found on PATH with a built-in preset and needs nothing else set. command requires DAIMON_LLM_COMMAND.
DAIMON_LLM_BASE_URLhttp://localhost:4000OpenAI-compatible endpoint URL (trailing slash trimmed). Falls back to LITELLM_BASE_URL.
DAIMON_LLM_API_KEYunsetAPI key for the endpoint. Falls back to LITELLM_API_KEY.
DAIMON_LLM_MODELunsetModel name to send. Falls back to LITELLM_MODEL.
DAIMON_LLM_TEMPERATURE0.0Sampling temperature for every chat call. 0.0 for deterministic extraction; some upstreams reject anything but a fixed value.
DAIMON_LLM_FALLBACKonWhen the primary backend fails, auto-fall-back to the rescue command (DAIMON_LLM_COMMAND_FALLBACK). Applies to both a litellm and a command primary. Set to 0 to disable.
DAIMON_FALLBACK_MIN_SECONDSDAIMON_TIMEOUTMinimum budget the rescue command is guaranteed on entry. The primary may have drained the shared serialize deadline retrying the very failure the rescue exists to fix, which would kill the rescue on arrival; a healthy remaining budget is never shrunk.
DAIMON_LLM_STREAMonStream the litellm response so the socket timeout bounds the inter-frame gap rather than the whole completion. Without it, a long completion trips the timeout and retries from scratch. Set to 0 to disable.
DAIMON_LLM_NO_CACHEoffWhen truthy, bypass gateway response caching per request — needed when a cached bad response pins a failure or runs must be statistically independent.
DAIMON_LLM_BRIEFINGoffWhen truthy, render the briefing via the LLM instead of the deterministic template.
DAIMON_LLM_COMMANDunsetFull CLI invocation for the command backend (binary + model + flags). Required for command, and required for a claude on PATH to be used by any backend other than claude-cli.
DAIMON_LLM_COMMAND_OUTPUTunsetHow to extract assistant text from the command's stdout: text (raw stdout) or json:<key> (parse JSON, read <key>).
DAIMON_LLM_COMMAND_INPUTstdinHow the prompt reaches the command backend: stdin (piped), arg (appended as the final argv element), or file:<flag> (written to a tempfile, then <flag> <path> appended). An unrecognized value logs a warning and falls back to stdin.
DAIMON_LLM_COMMAND_FALLBACKunsetThe one rescue CLI, used when the primary backend fails. Works for both a litellm primary and a command primary, which previously had no rescue direction at all. One fallback, never a chain: if the primary and this both fail the cause is almost always environmental, and a third CLI spends budget reaching the same error while making the install look better protected than it is. When unset, a litellm primary still falls back to DAIMON_LLM_COMMAND as before.
DAIMON_LLM_COMMAND_FALLBACK_OUTPUTunsetOutput spec for the rescue CLI, same grammar as DAIMON_LLM_COMMAND_OUTPUT. Carried separately because the rescue is a different binary.
DAIMON_LLM_COMMAND_FALLBACK_INPUTstdinInput spec for the rescue CLI, same grammar as DAIMON_LLM_COMMAND_INPUT.
Which process receives your transcript

A claude binary merely present on PATH is not adopted automatically. Serializing sends the full session transcript to whichever CLI is configured, so that CLI has to be named: either DAIMON_LLM_COMMAND, or DAIMON_LLM_BACKEND=claude-cli to opt into the built-in preset.

Previously an unset DAIMON_LLM_COMMAND plus a claude anywhere on PATH was enough for auto installs and for the litellm rescue path. If you relied on that, set one of the two variables above. daimon configure names the resolved binary and its path so you can see exactly which one is in use.

Serializer chunking

Long sessions are serialized in overlapping chunks whose partial checkpoints are merged hierarchically. The defaults come from field measurements; they only matter if your sessions routinely run very long.

VariableDefaultWhat it does
DAIMON_CHUNK_LINES1200Rendered-transcript line count above which serialization switches to chunked mode.
DAIMON_CHUNK_OVERLAP100Lines of overlap between adjacent chunks, so an item straddling a boundary is seen whole by at least one chunk.
DAIMON_CHUNK_CONCURRENCY4Parallel chunk-serialize LLM calls. Minimum 1 (sequential).
DAIMON_MERGE_GROUP_SIZE3Max partial checkpoints merged per hierarchical merge call. Minimum 2. Lower to 2 if merge calls die on a gateway with a server-side request ceiling (reasoning models generating 3-way merges can exceed it; raising DAIMON_TIMEOUT won't help — the kill is server-side).