Configuration
Environment variables, CLI flags, and the security posture of the internal API.
Iris reads configuration from /iris/.env (written by bootstrap) and CLI flags
(--provider, --model, --sandbox, --transport, --api-port). Flags override
env vars.
Environment variables
| Variable | Default | Purpose |
|---|---|---|
IRIS_PROVIDER / IRIS_MODEL | anthropic / provider default | LLM provider and model (see data/models.json) |
IRIS_SLACK_APP_TOKEN / IRIS_SLACK_BOT_TOKEN | — | Slack tokens; presence enables the Slack transport |
TELEGRAM_BOT_TOKEN | — | Telegram token; presence enables the Telegram transport |
IRIS_WEBUI_PORT | — | Presence enables the built-in web chat transport, bound to 127.0.0.1 |
IRIS_WEBUI_PASSWORD | — | Shared-secret login for the web UI. Unset = no auth gate (fine for loopback-only use; set before exposing via serve-public) |
IRIS_ENV | prod | preview | prod |
IRIS_API_PORT / IRIS_API_HOST | 3000 / 127.0.0.1 | Internal HTTP API bind (always on) |
IRIS_API_TOKEN | — | When set, API requires Authorization: Bearer <token> (except /health) |
IRIS_BRIDGE_PORT / IRIS_BRIDGE_HOST | — / 127.0.0.1 | Sub-agent bridge server (sub-agents only) |
IRIS_LLM_TIMEOUT_SECS | 90 | Per-attempt LLM timeout |
IRIS_LLM_MAX_RETRIES / IRIS_LLM_RETRY_BASE_MS | 3 / 2000 | Retry with exponential backoff on 429/timeout/transient errors |
IRIS_COMPACT_THRESHOLD / IRIS_COMPACT_TARGET | 0.6 / 0.1 | Pre-run auto-compaction trigger/target (fraction of context window) |
IRIS_SLACK_MAX_CHARS | 30000 | Safe Slack message length before splitting |
IRIS_TELEGRAM_FORCE_RECLAIM | — | Set true + restart to transfer bot ownership |
IRIS_GITHUB_ORG / IRIS_GITHUB_REPO | — | The repo Iris commits her own skills, sub-agents, and self-edits to (the github skill's push target — see Extending Iris). Use a fork of iris-core or your own private overlay repo, never the upstream you cloned from. Prompted by bootstrap alongside the GitHub token; also injected into the constitution as Iris's identity source |
IRIS_KEY_VAULT | — | Azure Key Vault name (Key Vault profile only) |
IRIS_SECRETS_MODE | env | env | store | proxy — opt-in credential broker, see Secrets |
IRIS_SECRET_KEY_FILE / IRIS_SECRET_STORE_FILE | /iris/secret.key / /iris/secrets.json.enc | Encrypted store paths (store mode) |
IRIS_BROKER_PORT / IRIS_BROKER_HOST | 9099 / 127.0.0.1 | iris-broker daemon bind (proxy mode) |
IRIS_BROKER_SERVICES_FILE | /iris/broker/services.json | Operator overrides for the injection gateway's service map |
IRIS_SECRET_BROKER_URL / IRIS_SECRET_BROKER_TOKEN | — | When set, GET /secrets/:name proxies here instead of env/Key Vault/store — points at the bundled iris-broker (proxy mode), Vault, Infisical, or any HTTP service speaking the same tiny contract |
IRIS_BASE_DOMAIN / IRIS_EMAIL_FROM | — | Public serving domain / outbound email sender |
PASSTHROUGH_API_KEY | — | Fallback API key for passthrough channels (see Channel Modes) |
Models and providers
The runtime loads provider endpoints and model definitions from
<workspace>/models.json (generated from data/models.json.template at bootstrap).
Anthropic and OpenAI work out of the box; custom endpoints (Azure AI Foundry,
DeepSeek, Mistral, AWS Bedrock) are defined in the template. Switch with:
IRIS_PROVIDER=anthropic
IRIS_MODEL=claude-sonnet-4-5For Azure AI Foundry (azure-foundry), bootstrap asks for the bare account
name (e.g. my-account-eastus2), not the full endpoint URL. Pasted URLs or
hostnames are trimmed automatically, and the generated baseUrl is validated —
bootstrap aborts on a malformed hostname and warns if it doesn't resolve in DNS.
DeepSeek (deepseek) and Mistral (mistral, including Devstral) need only an
API key — both go through pi-ai's openai-completions provider module,
since Mistral's /v1/chat/completions endpoint is OpenAI-compatible and
pi-ai's native mistral provider module hangs indefinitely on every call
(see the Fixed entry in iris-runtime/CHANGELOG.md — do not switch Mistral's
api back to "mistral"). Both ship ready-to-use model entries in the
template (deepseek-chat / deepseek-reasoner, devstral-medium-latest /
mistral-large-latest).
For any other OpenAI-compatible endpoint (Kimi/Moonshot direct, a self-hosted
vLLM/Ollama gateway, etc.), pick custom — bootstrap asks for a short provider
name (used as the models.json key), the base URL, the API key, and the exact
model id the endpoint expects, and writes a fresh openai-completions provider
block. To add one without bootstrap, add a block by hand — see
data/README.md for the shape.
azure-foundrywas namedfoundry-e2before this repo supported more than one custom provider; the name was a leftover from its originaleastus2deployment. Bootstrap migratesIRIS_PROVIDER=foundry-e2and theFOUNDRY_E2_KEY/FOUNDRY-E2-KEYsecret automatically on re-run, but a hand-editedmodels.jsonneeds itsfoundry-e2key renamed manually.
MCP servers
External toolsets connect via <workspace>/data/mcp.json (optional,
hot-reloaded per message; secrets referenced as ${VAR} from .env) — see
MCP Servers.
Internal API security
The internal API binds to loopback by default. If sub-agent containers reach Iris
via the Docker gateway (172.18.0.1:3000), set IRIS_API_HOST=0.0.0.0 and
IRIS_API_TOKEN — never expose the API beyond loopback without a token. Iris logs
a warning at startup if you do.
LLM resilience
Two mechanisms keep long-running channels healthy:
- Retry with backoff — failed LLM calls (429, timeout, connection reset) retry
up to
IRIS_LLM_MAX_RETRIEStimes with jittered exponential backoff, posting a visible_Retrying (n/3)..._notice. - Auto-compaction — before each prompt, if the estimated context exceeds
IRIS_COMPACT_THRESHOLDof the model window, Iris summarises older history down towardIRIS_COMPACT_TARGET(up to 3 passes). A post-run check at ≥70% real usage acts as a backstop.