Skip to content
Like what we’re building? Star on GitHub

Environment variables

Operational ITERION_* environment variables read directly by the engine and its backends. These are tuning dials and escape hatches — most runs need none of them. For the four launch knobs (compression, auto-memory, permission gate, backend) and their five-level precedence chain, see settings-precedence.md.

Values are read at the point of use; an unset, empty, or unparseable value falls back to the listed default.

Backends and models

VariableEffectDefault
ITERION_DEFAULT_SUPERVISOR_MODELFallback model: compiled into agents, judges, and LLM routers that do not declare one; also the first fallback for iterion supervise. Backend resolution remains independent. An LLM router still empty after this uses anthropic/claude-sonnet-5; other nodes can use the detected backend's suggested model.unset
ITERION_VERIFIED_ACTION_MODELModel spec for the Verified Action recovery agent. Precedence: a node's recovery.model (env-expanded) → this var → package default.package default
ITERION_CONFLICT_RESOLVER_MODELModel for the merge-conflict-resolver agent (review-merge-gate.md). Overrides the auto-detected pick.auto-detected claw model
ITERION_CLAUDE_CODE_MAX_TOOL_ERRORSAborts a claude_code session after this many consecutive tool errors (any success resets the count) — guards against degenerate tool-error loops. 0 disables the guard.25
ITERION_CLAUDE_CODE_THINKING_DISPLAYControls the claude_code thinking-block display flag: unset/other → summarized (readable summary); omitted → the CLI's latency-optimised default; off → stop passing the flag (required for claude CLIs older than the flag).summarized
ITERION_CLAUDE_CODE_STREAM_COLD_TIMEOUTHow long a claude_code session may produce no SDK message at all — an SDK or process deadlock shows up immediately, so this tier fails fast and lets the recovery dispatcher retry instead of burning minutes on a corpse. 0 disables the tier.90s
ITERION_CLAUDE_CODE_STREAM_IDLE_TIMEOUTThe hot tier: how long a session that has already produced a message may go silent. Generous because a sub-agent run commonly takes 5–10 min between visible messages. The name predates the cold/hot split and is kept for back-compat. 0 disables the tier.15m
ITERION_CLAUDE_CODE_ORCH_STALL_TIMEOUTA tighter budget for one specific deadlock: the model blocked on a blocking orchestration tool (TaskOutput / Monitor) it reached with no background work to wait on — no subagent spawned (Agent, or Task on older CLIs) and no run_in_background command started. A blocking call that follows real background work keeps the full hot budget. Once classified, the stall is recovered in place first (next row); only a failed recovery aborts the session, with an error that still carries "session idle for" so the node auto-re-executes on a fresh subprocess. Every classification lands as a delegate_stall event (outcome recovered or aborted) and on the runner's iterion_delegate_idle_deadlock_total{backend,model,outcome} counter.4m
ITERION_CLAUDE_CODE_ORCH_RECOVERY_TIMEOUTThe in-place recovery of that deadlock: the session is interrupted (the CLI's control-protocol interrupt aborts the tool call it is blocked on and closes the turn), then told which wait could never return, and continues on the same session — one tier cheaper than the node restart a kill costs (re-clone, re-provision, replay). This bounds how long the turn may take to close after the interrupt; past it, or when the model blocks the same way again, the session is aborted for retry. 0 disables the recovery (the stall aborts immediately).30s
ITERION_CLAUDE_CODE_DISALLOW_ORCHESTRATION_TOOLSOpt-in: withhold the single-subagent surface (Agent, Task, TaskOutput, Monitor, via --disallowedTools) too — the multi-agent Workflow tool is withheld from every non-ultracode node regardless, since the harness arms it on the word ultracode anywhere in the prompt, content included from claude_code nodes that are not in ultracode mode — for a deployment whose served model family hallucinates task ids and deadlocks on TaskOutput. Off by default: a claude_code node keeps its full native toolset, subagents included. Also removes the reading of background Bash output, which rides TaskOutput. ultracode nodes keep the surface regardless.unset (off)
ITERION_CLAUDE_CODE_NO_PROGRESS_TIMEOUTHow long a session may keep talking without acting. The idle tiers only see silence; they are blind to a model streaming text and thinking in circles (observed after a network outage: 20+ min of reasoning, no tool call, no commit). Only a tool_use, a tool result, or a turn's ResultMessage resets this timer. Deliberately longer than the hot tier so one slow build does not trip it. 0 disables it.25m
ITERION_CLAUDE_CODE_CLOSE_GRACEHow long the claude_code subprocess gets to exit on its own after stdin closes, before the shutdown ladder escalates. Bounds close() so a hung child (the CLI keeping bash background loops alive past the agent's logical end) cannot deadlock the caller's defer sess.Close().3s
ITERION_CLAUDE_CODE_CLOSE_TERMHow long the same subprocess gets after SIGTERM before the ladder resorts to SIGKILL.1s
ITERION_CLAW_COMPACT_THRESHOLD_RATIOContext-window fraction (0 < r ≤ 1) at which the claw router compacts the conversation. Used only when the workflow does not set the field.engine default
ITERION_CLAW_COMPACT_PRESERVE_RECENTNumber of most-recent messages kept verbatim when claw compacts. Used only when the workflow does not set the field.engine default
ITERION_PI_BINAbsolute path to the pi binary — e.g. a bun --compile single-file build on a host with no Node runtime.pi on PATH
ITERION_PI_MODESelects the pi transport. The default is the long-lived --mode rpc session — tool events reach the studio timeline, operator chat is delivered by pi's native steer, accounting comes from get_session_stats, and a pre-flight handshake resolves the model before any token is spent. print rolls back to the one-shot --mode json path.rpc
ITERION_PI_STREAM_COLD_TIMEOUTHow long a pi RPC session may produce no event at all before the node fails transiently.90s
ITERION_PI_STREAM_IDLE_TIMEOUTHow long a started pi RPC session may go with no event of any kind.15m
ITERION_PI_NO_PROGRESS_TIMEOUTHow long a pi RPC session may go without a completed message, tool call or compaction — catches a model looping on streaming deltas, which the idle guard cannot see.25m
ITERION_PI_SETTLE_GRACEHow long to wait for agent_settled after aborting a pi RPC turn, so a partial transcript still lands.30s
ITERION_PI_AGENT_DIRPins PI_CODING_AGENT_DIR for pi. Gives a reproducible pi config (and the only print-mode lever to disable pi's own retry loop), but hides the operator's ~/.pi/agent/auth.json — and with it the OAuth provider breadth that motivates the backend.unset (pi's own dir)
ITERION_PI_OFFLINE0 re-enables pi's model-catalogue refresh inside a sandbox. Off by default there because a network egress policy would stall startup on the refresh.off under sandbox
ITERION_PI_TRUST_PROJECT1 trusts the target repository's .pi/ extensions, skills and settings. pi executes project-local extensions as TypeScript inside the agent process, so this turns prompt injection into code execution — only for a repo you control.refused
ITERION_PI_MCP_CONNECT_TIMEOUT_MSHow long one MCP server gets to handshake and list its tools before the pi extension gives up on it. Servers connect in parallel during pi's session start — which iterion's own RPC handshake is waiting on, bounded by ITERION_PI_STREAM_COLD_TIMEOUT (90s) — so this bounds what an unreachable server can cost: its own tools, never the run.10000
ITERION_PI_NO_CONTEXT_FILES1 stops pi injecting the repo's AGENTS.md / CLAUDE.md into every call. On by default for claude_code parity, but it is the dominant per-call cost: measured at 26,933 vs 448 input tokens on iterion's own tree (103 KB CLAUDE.md) for a one-word prompt.context files loaded
ITERION_FORBID_SUBSCRIPTION_OAUTH1 refuses to spend a Claude Pro/Max subscription OAuth token on the pi and claw backends, which reach the API directly rather than through the vendor's CLI. Permitted by default — Anthropic accepts it, billing against a separate extra-usage balance rather than your plan limits, and iterion warns on each such node. Set this on a shared or cloud instance, where spending an operator's extra-usage balance is a cost decision taken for everyone. claude_code / codex are unaffected.permitted, with a warning
ITERION_CLAUDE_CODE_SETTING_SOURCESComma-separated --setting-sources for claude_code nodes (user, project, local). The default loads the operator's user-level settings and the target repo's project CLAUDE.md / .claude/settings.json, so a node honours the same conventions native Claude Code would. local is left out on purpose: .claude/settings.local.json is machine-specific and can carry absolute paths that do not resolve in a sandbox. "" or none disables it, restoring the CLI's headless no-settings default.user,project
ITERION_CLAUDE_CODE_STRICT_MCP0/false/off/no drops --strict-mcp-config, letting a claude_code node inherit the operator's personal ~/.claude.json MCP servers. On by default so the node's resolved MCP set (mcp_server: / mcp: blocks, the repo's .mcp.json, iterion's own ask-user and board servers) is authoritative — see backends.md.strict (on)

Backend selection and provider routing use ITERION_DEFAULT_BACKEND, ITERION_BACKEND_PREFERENCE, ITERION_OPENAI_USE_OAUTH, and ITERION_CODEX_VERSION — documented in backends.md.

Sandbox

VariableEffectDefault
ITERION_SANDBOX_PULL_TIMEOUTCaps <runtime> pull for the docker driver (Go duration, e.g. 20m) so a stalled registry or blocked DNS cannot pend a run indefinitely.10m
ITERION_SANDBOX_POST_CREATE_TIMEOUTBudget of the post_create snippet, on both drivers — the budget belongs to the phase, so raising it for a slow toolchain install raises it wherever the phase runs. Fails closed: a value that is not a positive Go duration is refused, the default applies, and one stderr line names the variable, the value and the default.30m
ITERION_SANDBOX_WORKSPACE_COPY_TIMEOUTBudget of the kubernetes driver's workspace copy AND of the git fixup that follows, each end-to-end. Same fail-closed parsing.15m
ITERION_SANDBOX_K8S_APPLY_TIMEOUTBudget of ONE kubectl control call on the kubernetes driver — the per-run Secret, the CA Secret, the pod, the NetworkPolicy, the mid-run secret refresh, and every delete (stale-pod eviction, rollbacks, cleanup). Enforced by killing the process; never passed as kubectl's own --request-timeout, which makes kubectl v1.36 discard the in-cluster configuration and dial localhost:8080. Same fail-closed parsing.2m

Every setup phase and how its expiry is classified: sandbox.md § setup phases. The pod-Ready wait has its own knob, ITERION_SANDBOX_K8S_POD_READY_TIMEOUT, documented there with the rest of the kubernetes scheduling family.

The sandbox on/off default, cloud override, host-state mounts, and the default image are ITERION_SANDBOX_DEFAULT, ITERION_SANDBOX_OVERRIDE, ITERION_SANDBOX_HOST_STATE, and ITERION_SANDBOX_DEFAULT_IMAGE — documented in sandbox.md.

Runtime and runner

VariableEffectDefault
ITERION_SKIP_MCP_HEALTHTruthy → do not abort the run when a declared MCP server fails its startup health-check; log a warning and continue. Equivalent to the iterion run --skip-mcp-health flag. Useful when an HTTP/OAuth MCP server is unreachable in this environment but the run does not depend on it.off (abort on failure)
ITERION_BRANCH_CANCEL_GRACEGrace period (Go duration, e.g. 30s) a cancelled fan-out branch is given to unwind before the collector stops waiting on it — raise it for backends that need longer to abort.5s
ITERION_GIT_AUTHOR_NAMECommit-author name seeded into a cloud-runner clone's local git config (no ~/.gitconfig is mounted in the sandbox). The push-token identity is the preferred attributed path; this fires token-less.iterion-runner[bot]
ITERION_GIT_AUTHOR_EMAILCommit-author email for the same cloud-runner clone. The default uses a reserved .invalid domain (RFC 2606) so the commit maps to no real account.iterion-runner@bot.iterion.invalid
ITERION_SHUTDOWN_DELAYLame-duck window on SIGTERM: /readyz answers 503 for this long while the listener still accepts, so a load balancer can stop routing to the pod before its socket closes. A malformed value is a startup error, never a silent 0. See probes-and-graceful-shutdown.md.5s in cloud mode; 0 locally (iterion studio, and iterion server without ITERION_MODE=cloud, which routes to the studio)
ITERION_SHUTDOWN_TEARDOWNWhat follows that window: draining in-flight runs, then letting in-flight HTTP requests finish. The ceiling on a long upload or a streamed response during a deploy. Must be > 0.30s in cloud mode; 60s locally
ITERION_WORKTREE_POOL_MAXHow many per-run worktrees no live run owns a store may park under <store-dir>/worktrees/ before the runtime reclaims the oldest. A worktree is a full checkout of the repository, so the pool is where a long-lived store's disk goes. The bound takes only what a durable ref already holds with nothing uncommitted — never a dirty tree, never a resumable run's checkout — and warns, naming the command, when it cannot get back under. off disables it. See worktree-pool.md.8
ITERION_SCRATCH_RETENTIONHow long an untouched ${PROJECT_SCRATCH_DIR} entry is kept. A run sweeps the workspace's scratch on its way out, and iterion clean sweeps it too; both take only entries nothing has written to for this long — age is the concurrency guard, because scratch is deliberately shared between runs (a subbot writes into its parent's, which is how fan-in works). off disables the automatic sweep.168h (7 days)
ITERION_RUNNER_DRAIN_MODEcomplete (lame-duck: finish the in-flight run before exiting) or interrupt (cancel + checkpoint for auto-resume elsewhere).complete
ITERION_RUNNER_DRAIN_TIMEOUTLame-duck ceiling — the longest a runner pod waits for its in-flight run before capping it for a checkpoint-resume.8h
ITERION_RUNNER_SCHEMA_MISMATCH_DELAYRedelivery delay a runner applies when it rejects a queue message whose schema version it does not speak (mixed fleet during a rolling schema bump). Set it on server pods too: the orphan sweeper uses MaxDeliver × max(AckWait, schema delay, epoch delay). The Helm chart keeps this older knob in the shared ConfigMap. See cloud-queue-schema-rollout.md.30s
ITERION_RUNNER_EPOCHMonotonic generation shared by server and runner. Publishers stamp it on every RunMessage; runners accept message epochs their own and delayed-Nak future epochs before taking a lease. A process below the persistent JetStream high-water mark stays live but reports 503 superseded and cannot publish or consume. In Helm this is a literal PodTemplate env, never a mutable ConfigMap value.0 (bootstrap)
ITERION_RUNNER_EPOCH_MISMATCH_DELAYDelayed-Nak interval for a future-epoch message. Keep delay × (MaxDeliver-1) above the worst cold-readiness time of the replacement fleet. It contributes to the orphan sweeper's redelivery window and is rendered literally in both Helm PodTemplates.2m
ITERION_NODE_MAX_TRANSIENT_RETRIESIn-executor retry budget for a transient backend failure (rate-limit, session-limit, idle watchdog, network/5xx), retried with exponential backoff before the failure becomes a run-level failed_resumable. The value is a RETRY count and excludes the initial attempt, so 8 yields 9 attempts; 0 means fail-fast. A negative or non-numeric value keeps the default rather than silently disabling retries.5 retries (6 attempts)
ITERION_NODE_MAX_RETRIESThe same budget for deterministic-but-retryable errors (a signal kill). Same counting rules as above.2 retries (3 attempts)
ITERION_WORKSPACE_TRACKoff/0/false/no disables workspace versioning globally — the content-addressed capture that backs iterion rewind's file restore for runs with no isolated worktree (workspace-versioning.md). On by default: without it a rewind cannot undo what a node produced. The escape hatch exists because the cost scales with the workspace, not with the run.on
ITERION_WORKSPACE_MAX_FILE_MBLargest single file workspace versioning will capture. A file over the bound is reported (files.overwritten / files.left_in_place), not silently lost — but reporting is not restoring, so raise it for a media pipeline whose deliverable is the artefact a rewind most needs back. A non-numeric or non-positive value keeps the default.32 (MiB)
ITERION_AUTO_MEMORYEnv level of the auto_memory: precedence chain (--auto-memory → node → workflow → this → default). Off by default so a run is hermetic — see memory-and-knowledge.md.off
ITERION_LOOP_BUDGET_GUARDEnv level of the loop_budget_guard: chain (--loop-budget-guard → workflow → this → default). Declines a loop back-edge the remaining budget cannot fund, so the run leaves through its own exit path instead of dying mid-pass on BUDGET_EXCEEDED — see dsl.md.on
ITERION_BUDGET_EXIT_GRACEHow far past a spent cap a run may walk forward to reach a terminal node, as a fraction of the declared cap — so work already paid for gets delivered instead of dying on disk. Accepts a ratio in [0,1]; off/no/false/none/0 make every declared cap absolute (the setting for shared instances and pooled credentials). Fails closed: an out-of-range or unparsable value is treated as 0 with a one-time stderr warning, never as the permissive default. The grace is refused outright when the loop budget guard is off, and on a cap clamped by an outside authority (platform ceiling, credential-pool donor allowance). Each graced node emits a budget_exit_grace event — see dsl.md.0.1 (10%)
ITERION_REPO_DEVBOXEnv level of the repo_devbox: chain (--repo-devbox → workflow → this → default). off skips the target repo's devbox.json; the bot's own is always installed. Worth turning off for a run that reads a repo without building it — see dsl.md.on
ITERION_WEBHOOK_SYNC_DEBOUNCEQuiet window a synchronize (push-to-PR) review launch waits out, so a push volley costs one review of the final head instead of N−1 runs cancelled mid-flight. A Go duration; 0 disables the debounce and every push launches immediately — the kill switch for the whole deferred lane. An unparsable value keeps the default with a stderr warning (failing open would silently restore the waste it exists to cut). PR open, /revi and a re-request click are never debounced. See webhooks.md.3m

Run alerts

The run observer (pkg/alert) watches runtime events plus a per-run liveness heartbeat and fires on stall, budget warning/exceeded, and failure. These variables configure where those alerts go; they are read by both iterion studio and the cloud server. Distinct from the user-addressed web-push notifications of notifications.md, which are per-recipient rather than per-deployment.

VariableEffectDefault
ITERION_ALERTS_WEBHOOK_URLGeneric incoming webhook (Slack / Discord) the alert sink posts to. Empty disables the sink. It is an operator-set destination posted to with a plain 15s-timeout client — unlike the operator-supplied completion webhooks of pkg/notify, it carries no SSRF guard, so point it only at a URL you control.unset (no webhook sink)
ITERION_ALERTS_STALL_TIMEOUTNo-activity window after which a non-terminal run is flagged stalled (Go duration). An unparseable value keeps the default rather than disabling the check.5m
ITERION_ALERTS_BASE_URLOrigin used to build clickable /runs/<id> deep links in webhook payloads. When unset it is derived from the bind address + port; with an OS-assigned (0) port the absolute base is left empty, since a wrong link is worse than none.derived from bind + port
ITERION_ALERTS_DESKTOP_ENABLEDtrue turns on the native desktop-notification sink. Parsed strictly — anything unparseable is false.false

Platform budget ceiling (cloud)

The multitenant safeguard: a hard, tenant-unraisable cap on every run a runner pod executes. Set on the runner Deployment. Each variable is independent — set only the dimensions you want to bound; leaving one unset means "no platform limit on that axis", and setting none at all is a no-op, so a self-hosted or single-tenant deployment keeps its .bot budgets verbatim.

The ceiling is applied after the launch overrides, and it only ever lowers: a tenant cannot raise it with --max-cost-usd, and a bot that declares no budget at all inherits the ceiling rather than running unlimited — which is what bounds an as X(unbounded) loop, whose fuel falls back to max_iterations (dsl-totality-and-tc.md). A clamp that actually changes a limit marks the budget imposed, so the runtime's exit grace is refused and the figure is absolute.

A value that is empty, non-numeric, or ≤ 0 is treated as unset (no ceiling on that dimension), not as zero.

VariableEffectDefault
ITERION_CLOUD_MAX_ITERATIONSCeiling on the workflow's max_iterations.unset (no ceiling)
ITERION_CLOUD_MAX_TOKENSCeiling on max_tokens.unset
ITERION_CLOUD_MAX_COST_USDCeiling on max_cost_usd, in dollars.unset
ITERION_CLOUD_MAX_DURATIONCeiling on max_duration (Go duration, e.g. 4h). Compared by parsed seconds; a workflow value that is unparseable or absent is replaced by the ceiling. Unlike the numeric dials this one is not validated at read time: any non-empty string is accepted, and one that is not a Go duration clamps nothing on this axis — silently, with no log line, since the runner only logs a clamp that changed something.unset
ITERION_CLOUD_MAX_PARALLEL_BRANCHESCeiling on max_parallel_branches.unset
ITERION_CLOUD_RETRY_MAX_ATTEMPTSCeiling on the resolved retry policy's max_attempts, applied last so a tenant cannot reserve a pod for a hundred attempts — see scheduling.md.unset
ITERION_CLOUD_RETRY_MAX_WAITCeiling on the resolved retry policy's max_wait (Go duration).unset

This is the per-run bound. The per-org monthly cost cap, run quota, concurrency and launch rate are a separate admission layer with its own variables — see quotas-and-limits.md.

See also

  • probes-and-graceful-shutdown.md — what the probe endpoints promise and how the delays compose.
  • settings-precedence.md — compression / permission / backend precedence.
  • backends.md — backend, provider, and OAuth-forfait variables.
  • sandbox.md — sandbox default, override, and host-state variables.
  • notifications.mdITERION_WEBPUSH_VAPID_{PUBLIC,PRIVATE}_KEY; the user-addressed counterpart to the deployment-wide ITERION_ALERTS_* above.
  • worktree-pool.md — the worktree pool bound and ITERION_WORKTREE_POOL_MAX.
  • usage-caps.mdITERION_USAGE_CAP, ITERION_USAGE_CAP_5H_{MODE,PCT}, ITERION_USAGE_CAP_WEEK_{MODE,PCT}.
  • scheduling.md — the retry policy's machine defaults (ITERION_RETRY_*) and the platform ceiling (ITERION_CLOUD_RETRY_*).
  • web-search.mdITERION_WEB_SEARCH and the search-tier resolver.
  • secrets.mdITERION_SECRETS_KEY and the redaction variables.
  • observability.mdITERION_LOG_FORMAT, ITERION_LOG_LEVEL, and the SENTRY_* variables.