Configuration
Zero configuration by default. Environment variables for power users.
Philosophy
Irrlicht is designed to work with zero configuration. Install and run — sessions are discovered automatically. These options exist for power users who need to customize behavior.
Environment Variables
| Variable | Type | Default | Description |
|---|---|---|---|
IRRLICHT_MAX_SESSION_AGE |
Duration | 120h (5 days) |
Maximum age for transcript sessions before pruning |
GT_BIN |
Path | $PATH lookup |
Override path to Gas Town gt CLI binary |
IRRLICHT_UI_DIR |
Path | auto-detect | Directory containing the dashboard's index.html; escape hatch when auto-detection fails (see When to use these) |
IRRLICHT_BIND_ADDR |
host:port | 127.0.0.1:7837 |
Override the daemon's TCP bind — use 0.0.0.0:7837 to expose on the LAN |
IRRLICHT_MDNS |
Boolean (1/0) | unset | Advertise _irrlicht._tcp via Bonjour so other devices on the LAN can discover the daemon |
IRRLICHT_DEBUG |
Boolean (1/0) | unset | macOS app dumps session state to ~/.irrlicht/debug-state.json on every update |
PI_CODING_AGENT_SESSION_DIR |
Absolute path | ~/.pi/agent/sessions |
Relocate the Pi adapter's transcript root. Read once at daemon startup; restart required after changing. Non-absolute values are rejected with a log warning |
CLAUDE_CONFIG_DIR |
Absolute path | ~/.claude |
Relocate the Claude Code adapter's transcript root (the daemon appends /projects). PID-metadata directory at ~/.claude/sessions/ remains hardcoded |
CODEX_HOME |
Absolute path | ~/.codex |
Relocate the Codex adapter's transcript root (the daemon appends /sessions) |
KIRO_HOME |
Absolute path | ~/.kiro/sessions/cli |
Relocate the Kiro CLI adapter's transcript root (the daemon appends /sessions/cli). Non-absolute values are rejected with a log warning |
VIBE_HOME |
Absolute path | ~/.vibe/logs/session |
Relocate the Mistral Vibe adapter's transcript root (the daemon appends /logs/session). Non-absolute values are rejected with a log warning. Vibe's own [session_logging].save_dir in $VIBE_HOME/config.toml takes precedence and replaces the root outright |
IRRLICHT_PERMISSION_MODE |
ask | grant-all |
ask |
Consent behavior. ask (production default) keeps every per-agent permission pending until answered via the wizard — nothing is read or modified before a grant. grant-all auto-grants everything in-memory for demo / recording / test daemons; it is never persisted |
IRRLICHT_READY_SESSION_TTL |
Duration | 30m |
How long an idle ready session is kept before automatic deletion. Used by test harnesses to expire long-idle sessions in seconds rather than half an hour |
IRRLICHT_YIELD_SWEEP_INTERVAL |
Duration | 30m |
How often the yield sweep correlates git revert commits back to the sessions that authored the reverted work, feeding the History view's productive-vs-reverted ratio |
IRRLICHT_HOME |
Path | ~/.local/share/irrlicht |
Relocate the daemon's entire state tree — socket, addr file, history rollups, session/cost/ledger stores, and recordings — for a fully isolated dev / test daemon that never touches the production install |
IRRLICHT_DEMO_MODE |
Boolean (1/0) | unset | When 1, disables the process watcher and per-adapter file watchers — the daemon serves only seeded session state. For demos and screenshots |
IRRLICHT_RECORD |
Boolean (1/0) | unset | When 1 (equivalent to the --record flag), records the session lifecycle event stream to JSONL for replay fixtures |
IRRLICHT_RECORDINGS_DIR |
Path | <dataDir>/recordings |
Override the directory lifecycle recordings are written to. Wins even when IRRLICHT_HOME is set, so a recording run can be pinned somewhere specific (only used while recording is enabled) |
IRRLICHT_RELAY_URL |
URL | unset | Opt-in outbound relay: forward this daemon's session events to a standalone irrlichtrelay so remote clients can see them. Accepts a bare base (e.g. ws://host:7839); http(s):// is rewritten to ws(s):// and the stream path is appended automatically |
IRRLICHT_RELAY_TOKEN |
String | unset | Bearer token for an auth-enabled relay. Overrides the token field of <dataDir>/relay-token.json; leave unset against a no-auth relay |
IRRLICHT_RELAY_CONTROL |
on | unset |
unset | When on, lets the relay forwarder act on inbound remote-control frames (the backchannel's outer remote gate). For standalone/headless daemons; the macOS app drives the same toggle via POST / DELETE /api/v1/activation/relay-control |
IRRLICHT_CACHE_BLOAT_THRESHOLD |
Float | 1.4 |
Cache-creation regression detector: a working session trips the rule when its median cache-creation-per-turn exceeds the per-project baseline × this factor. 0 (or negative) disables the whole rule — the kill switch |
IRRLICHT_CACHE_BLOAT_BASELINE_DAYS |
Integer | 14 |
Trailing window over completed sessions used to compute the per-project cache-creation-per-turn baseline |
IRRLICHT_CACHE_BLOAT_MIN_TURNS |
Integer | 3 |
Variance guard — the rule won't fire before this many completed turns |
IRRLICHT_CACHE_BLOAT_VERSION_DELTA |
Integer (tokens) | 10000 |
Minimum per-turn cache-creation difference between two agent versions before the regression is attributed to an upstream agent version change |
IRRLICHT_MODEL_CAPACITY_CACHE |
Path | auto-detect | Override the model capacity / pricing cache file with an explicit path. An escape hatch used by replay tests to pin pricing to a committed snapshot so cost resolution can't drift |
NO_COLOR |
Boolean (presence) | unset | Standard no-color convention — when set to any value, the irrlicht-ls CLI disables ANSI color in its text output |
GT_ROOT |
Path | ~/gt |
Override the Gas Town root directory the orchestrator adapter probes for daemon/state.json and rig layout |
IRRLICHT_DAEMON_PORT |
Integer | 7837 |
macOS app only — override which daemon port the dashboard connects to, so a dev-build daemon (e.g. port 7838) can coexist with the production daemon |
IRRLICHT_RELAY_MAX_MSG_BYTES |
Integer (bytes) | 1048576 |
Env fallback for irrlichtrelay serve --max-msg-bytes — max inbound WebSocket message size the relay accepts; 0 disables the cap |
IRRLICHT_RELAY_MAX_CONNS |
Integer | 256 |
Env fallback for irrlichtrelay serve --max-conns — max total concurrent connections the relay accepts; 0 disables the cap |
IRRLICHT_RELAY_MAX_CONNS_PER_IP |
Integer | 32 |
Env fallback for irrlichtrelay serve --max-conns-per-ip — max concurrent connections per remote IP; 0 disables the cap (meaningless behind a proxy/NAT) |
When to use these
The defaults work for solo, single-machine use. Reach for these overrides when one of the following describes you:
I want to peek at sessions from my phone on the same WiFi
If you run irrlichd yourself from a terminal, set both vars inline:
IRRLICHT_BIND_ADDR=0.0.0.0:7837 IRRLICHT_MDNS=1 irrlichd
If the macOS app auto-spawns the daemon for you (the default for DMG / Homebrew installs), shell env vars never reach it. Set them in the per-user launchd context first, then relaunch the app:
launchctl setenv IRRLICHT_BIND_ADDR 0.0.0.0:7837
launchctl setenv IRRLICHT_MDNS 1
# quit Irrlicht.app from the menu bar, then reopen it
Either way, then open http://<hostname>.local:7837 in any browser on the same network. mDNS lets the phone find the host without you typing an IP.
Security note: the daemon has no authentication today. Anyone on the network you bind to can read all your transcripts. Only do this on networks you trust (your home LAN, your tailnet) — never on a coffee-shop WiFi. See SECURITY.md for the full posture.
Future: these two knobs will be replaced by a single explicit hub mode. See the Relay Server design for the planned consolidation.
The dashboard returned "Dashboard UI not found"
The daemon resolves the dashboard's location in this order (first hit wins):
$IRRLICHT_UI_DIR— escape hatch (what this recipe sets)<exe>/../Resources/web/— production.appbundle layout~/.local/share/irrlicht/web/— daemon-only curl install- Walking up from the executable for
platforms/web/index.html— dev checkout
If the three auto-detect paths (2–4) all miss — custom install layout, fork with a moved UI, broken symlink — set the env var so it takes precedence:
IRRLICHT_UI_DIR=/path/to/dir/containing/index.html irrlichd
The macOS app is misbehaving and I want to see its session state
Env vars set in your shell do not reach a GUI app launched via open -a — LaunchServices spawns the app without inheriting them. Use one of these instead:
# Most reliable: invoke the binary directly
IRRLICHT_DEBUG=1 /Applications/Irrlicht.app/Contents/MacOS/Irrlicht
# Or, on macOS 13+: forward via open's --env flag
open -a Irrlicht --env IRRLICHT_DEBUG=1
# Or, persist for the launchd session and relaunch normally
launchctl setenv IRRLICHT_DEBUG 1
# quit Irrlicht.app, then reopen it
The current session list, connection state, and history buckets are written to ~/.irrlicht/debug-state.json on every update. Useful when filing a bug report.
Filesystem Paths
Daemon
- Session instances:
~/Library/Application Support/Irrlicht/instances/ - Permissions:
~/.local/share/irrlicht/permissions.json— the per-agent consent answers behind the permission wizard. A missing file (or a missing key) means pending: the wizard re-asks and nothing is monitored until granted - Logs:
~/Library/Application Support/Irrlicht/logs/ - Unix socket:
~/.local/share/irrlicht/irrlichd.sock
macOS App
- Session order:
~/Library/Application Support/Irrlicht/session-order.json
Transcript Locations
- Claude Code:
~/.claude/projects/<project>/<session-id>.jsonl - Codex:
~/.codex/sessions/YYYY/MM/DD/<session-id>.jsonl - Pi:
~/.pi/agent/sessions/--<cwd-dashed>--/<session-id>.jsonl - Aider:
<cwd>/.aider.chat.history.md(markdown, per-CWD) - OpenCode:
~/.local/share/opencode/storage/opencode.db(single SQLite WAL, watched viaopencode.db-wal) - Kiro CLI:
~/.kiro/sessions/cli/<uuid>.jsonl(plus a<uuid>.jsonmetadata sidecar for cwd, model, and context metrics) - Gemini CLI:
~/.gemini/tmp/<project>/chats/<session-id>.jsonl - Antigravity:
~/.gemini/antigravity-cli/brain/<conv-id>/.system_generated/logs/transcript.jsonl(CLI) or~/.gemini/antigravity/brain/<conv-id>/.system_generated/logs/transcript.jsonl(IDE) - Mistral Vibe:
~/.vibe/logs/session/<session-id>/messages.jsonl(plus a siblingmeta.jsonsidecar for cwd, model, and context metrics)
App Settings
The macOS app has a Settings panel accessible via the gear icon:
Notifications
- Notifications are opt-in by default — no banners or sounds play until you enable an event in Preferences (part of the consent-first rollout in v0.5.0)
- Three events —
ready,waiting, and context pressure (a single configurable threshold, default 80% of the context window or an absolute token count) — each has its own enable toggle and sound picker in Preferences - Built-in sounds: Ping, Chime, Funk, Whoosh, Sosumi; defaults Ready=Funk, Waiting=Ping, Context=Sosumi
- None — the banner still appears but plays no sound
- Speak aloud — routes the title and body through
AVSpeechSynthesizer(pinned to en-US) with three voice variants: Default, Zoe-Premium (female), Jamie-Premium (male). If a premium voice isn't installed, the row deep-links to System Settings → Accessibility → Spoken Content - Custom — imports
aiff/wav/mp3/m4a/caffrom disk into~/Library/Sounds/, transcodingmp3/m4ato LPCM-in-CAF soUNNotificationSoundcan play them - Requires macOS notification permission (requested on launch)
Logging
- Format: Structured JSON
- Location:
~/Library/Application Support/Irrlicht/logs/ - Files:
events.log(current),events.log.1through.5(rotated) - Max size: 10MB per file, 5 files retained
- Log event types:
startup,shutdown,session-detector,process-watcher,process-exit
Network
- TCP:
localhost:7837(HTTP API + WebSocket + Web UI) - Unix socket:
~/.local/share/irrlicht/irrlichd.sock - mDNS:
_irrlicht._tcp(Bonjour/Zeroconf discovery)
Daemon Lifecycle
The daemon (irrlichd) is embedded inside Irrlicht.app and managed automatically. When you launch the app, the daemon starts; when you quit, it stops. If the daemon crashes, the app restarts it with exponential backoff.
If an external daemon is already running (e.g. from a development build), the app detects it and uses the existing instance instead of spawning a new one.
Terminal hosts
Clicking a session in the menu bar or web UI brings the originating terminal's window — and where possible the exact tab — to the front. Most terminals work out of the box. Kitty needs two extra config lines for precise tab focus.
Kitty
Kitty needs two lines in ~/.config/kitty/kitty.conf to enable precise tab focus. See macOS Setup → Kitty Terminal for the full steps.