The ilium command attaches the terminal interface to a project session and offers short one-shot subcommands for scripts and agents: listing and ending sessions, adding panes, starting agents in Git worktrees, the file-backed agent Chatroom, long-task progress reporting, typed voice input, and listing or messaging agents across every running session. This page documents every subcommand, flag, output format, environment variable and exit behaviour, with examples.
Contents:
- Synopsis
- Global options
- Quick table of commands
- ilium (attach)
- ilium new-session
- ilium ls
- ilium kill-session
- ilium new-pane
- ilium chat
- ilium progress
- ilium voice say
- Pane selection
- ilium panes
- ilium broadcast
- ilium recap
- Environment variables
- Output formats and exit status
- Other binaries and hidden commands
- Recipes
- Troubleshooting
ilium [OPTIONS] [COMMAND]
Commands:
new-session Create (if not already running) and attach to a named session
ls List this project's known sessions and whether each is running
kill-session Gracefully end a running session
new-pane Add a pane running a command, without attaching the interface
chat Read, initialize, or post to this project's file-backed agent room
progress Report or clear a long-running task's progress from inside a pane
voice Voice control from the command line (`voice say`)
panes List the panes of every running session that pass the pane selection
broadcast Send a message to every running agent that passes the pane selection
help Print help for the program or a subcommand
ilium --help and ilium <command> --help print the same information from the program itself, and ilium --version prints the version.
These options are defined once and accepted by every subcommand.
| Option | Default | Meaning |
|---|---|---|
--cwd <CWD> |
. |
Project directory for the session being attached to or created. Every pane starts here and the editor file picker opens rooted here. Every command that addresses a session is scoped to this canonical project directory. The directory must exist. |
--restart-server |
off | Replace this project's running server before attaching, keeping its snapshot. See below. |
--reset-session |
off | Delete this session's snapshot and start it empty. Destructive. Conflicts with --restart-server. |
--onboarding |
off | Open the guided setup even when this installation is already configured. |
-h, --help |
Print help. | |
-V, --version |
Print the version. |
Which commands use which option:
--cwdis used by every command that addresses a session or a project: bareilium,new-session,ls,kill-session,new-pane,chatandvoice say.panesandbroadcastscan every session on the machine and use it only for--hereand relative--projectvalues.progressignores it; it addresses the pane it is running in through its environment (see ilium progress).--restart-server,--reset-sessionand--onboardingonly act when attaching (bareiliumandilium new-session). The other subcommands accept them but ignore them.
Stops this project session's running server (found through the socket peer, so it can never affect another project) and starts a new one from the current executable. The server first saves its tree and exits; the new server restores that snapshot. Use it after installing a new ilium-server binary. Because the old server's processes end, panes are relaunched from the snapshot, as after a reboot. Programs lose any unsaved process state. See Session recovery.
Stops the server, deletes this session's snapshot, and starts an empty server. For the default session it also removes the older project-wide .ilium/sessions.yml if present, so the reset really is empty. It never touches another project or another named session. There is no confirmation prompt.
ilium --reset-session
ilium --reset-session new-session review| Command | What it does | Output |
|---|---|---|
ilium |
Attach to, or create, the current project's default session. |
Interactive interface |
ilium new-session <name> |
Create or attach to a named session. | Interactive interface |
ilium ls |
List this project's sessions. | Plain text |
ilium kill-session <name> |
End a running session and its panes. | Plain text |
ilium new-pane -- <cmd> |
Add a terminal pane running a command. | Plain text |
ilium new-pane --worktree --branch <b> -- <agent> |
Start a built-in agent in a new Git worktree. | JSONL |
ilium chat init |
Create CHATROOM.md and the agent hooks. |
Plain text |
ilium chat send --message <text> |
Post a message to the room. | Plain text |
ilium chat context / ilium chat tail |
Print recent room records. | Plain text |
ilium progress check|set|status|clear |
Manage this pane's long-task monitor. | JSONL |
ilium voice say <sentence>... |
Type sentences into the live voice session. | JSONL |
ilium panes [selection] |
List panes across every running session. | JSONL |
ilium broadcast [selection] <message>... |
Send a message to every selected agent. | JSONL |
ilium close-pane [--worktree keep|remove|remove-and-branch] |
Close this pane, optionally removing its Ilium-created worktree. | JSONL |
ilium ctl <command> |
Full remote control: read the tree, create, move, rename, close and drive panes. | JSON, YAML, Markdown or JSONL |
ilium recap [selection] |
Short and long factual recaps of selected agent and shell panes. | JSONL or Markdown |
ilium [--cwd <dir>] [--restart-server | --reset-session] [--onboarding]- Resolves the canonical project directory from
--cwd. - Ensures a server is running for the session
default, startingilium-serveras a detached background process if not. The client waits up to five seconds for the server to become ready. - Attaches the interface. It stays attached until you detach (
Ctrl+Bd), kill the session (Ctrl+B&), or the connection drops.
Running ilium again in the same directory re-attaches to the same session. Several clients can attach at once.
The interface itself can restart only the client process (for example from a menu Restart entry): the detached server keeps its panes and tree throughout. The restarted client is started again with just the project and session identity, so --restart-server and --reset-session never carry over.
ilium new-session <name>Creates, if it is not already running, and attaches to the session <name> for the current project. Names must be 1 to 48 characters from letters, digits, hyphen and underscore. Anything else fails with session name "..." must contain only letters, digits, hyphens, or underscores.
ilium new-session review
ilium --cwd ~/code/api new-session hotfixSessions of one project are independent trees with separate snapshots in <project>/.ilium/sessions/<name>.json.
ilium lsLists this project's sessions, one per line, with the name padded to 24 characters followed by running or not running:
default running
review not running
Prints no sessions when there are none. A session whose server has stopped stays listed as long as its snapshot file exists, so you can deliberately reopen it. Only sessions of the project given by --cwd are shown, and snapshot files whose names are not valid session names are skipped.
ilium kill-session <name>Gracefully ends a running session: every pane is killed and the tree is torn down. The command first checks that the session is live, verifies the server attached to the session you named (it refuses to send the destructive request to a server serving a different session name), sends the request, and waits up to five seconds for the server to close the connection. On success it prints:
session "review" killed
Errors: session "<name>" is not running when no server answers; other server-reported errors are shown as ilium: the server reported an error: .... The snapshot is not deleted by this command; use --reset-session for that.
To end a session from inside the interface use Ctrl+B &, which does the same without a confirmation.
ilium new-pane [--keep-open] [--session-name <name>] -- <cmd> [args...]
ilium new-pane --worktree --branch <branch> [--base <ref>] [--session-name <name>] -- <agent>Adds a pane to a running or starting session without attaching the interface. Run ilium afterwards to see it. If the session's server is not running, new-pane starts it.
| Option | Default | Meaning |
|---|---|---|
--session-name <name> |
default |
Project-local session that receives the pane. |
--keep-open |
off | Keep the pane open after the command exits. Without it, a plain new-pane command pane closes itself shortly after its command ends (at least 3 seconds after creation, and not while a live progress monitor is registered on it). Cannot be combined with --worktree. |
--worktree |
off | Start a built-in agent in a new Git worktree on its own branch. Requires --branch. |
--branch <branch> |
New branch for --worktree. Must not already exist. Requires --worktree. |
|
--base <ref> |
the repository's default base | Starting ref for --worktree. Requires --worktree. |
-- <cmd>... |
required | The command and its arguments. Everything after -- is taken literally. |
The command and arguments are joined into one shell command line, quoting only the arguments that need it, so boundaries are kept: ilium new-pane -- ls "my folder" runs ls 'my folder'. The server runs it as $SHELL -c <command line> (or through cmd.exe on Windows when SHELL is not a POSIX shell) and shows the command as the pane's name. The pane starts in the project root and is added to the top level of the tree. Because the whole command line is passed to your shell, shell syntax works only when you quote it into a single argument.
ilium new-pane -- claude
ilium new-pane --session-name review -- codex
ilium new-pane -- tail -f /var/log/syslog
ilium new-pane -- sh -c 'npm run build && npm test'Output on success is one plain-text line, not JSON:
pane created in project session "default"
The command waits up to five seconds for the server to confirm that the pane count grew. If no confirmation arrives it fails with no confirmation received from the server.
--worktree starts an agent in a linked Git worktree so it cannot disturb your working tree or other agents. Exactly one command is accepted, and it must be a built-in agent command: claude, codex or agy (Antigravity). Anything else fails with --worktree requires exactly one built-in agent command: claude, codex, or agy.
ilium new-pane --worktree --branch agent/fix-login -- codex
ilium new-pane --worktree --branch agent/spike --base main -- claudeWhat happens:
- The branch name is validated with Git's naming rules (not empty, no spaces,
~ ^ : ? * [ \, control characters,..,@{,//, no leading-, no trailing/or., no component starting with.or ending in.lock). Invalid names fail before anything is created. - The persisted Settings → Git setup command is read, if one is set. A malformed
config.tomlmakes the command fail rather than silently skipping setup. - The server is started if needed, and the command attaches, then asks the server for the repository facts.
- The worktree is created at a sibling directory of the main checkout:
<parent>/<main-checkout-name>.worktrees/<branch-slug>, where the slug is the branch lower-cased with runs of non-alphanumeric characters replaced by-(at most 48 characters,taskif nothing is left). For example, branchagent/fix-loginin/home/me/code/appbecomes/home/me/code/app.worktrees/agent-fix-login. Unlike the interactive dialog, the CLI does not use the configurable location template or branch prefix. - The setup command, if configured, runs after creation (Linux only), then the agent starts.
- Git hooks and filters run as they normally do during creation.
The new branch must not exist. --base defaults to the repository's default base ref. Cleanup of worktrees Ilium created is offered later when they are clean, merged and unused; unclear ownership or process state blocks removal. See Worktrees.
Worktree output is JSONL on stdout, one object per line:
type |
Fields | When |
|---|---|---|
progress |
request_id, stage |
At each stage: querying-repository, then creating-worktree, preparing, running-setup (only with a setup command) and starting. |
result |
request_id, pane_id, branch, base, worktree_path |
The agent pane exists. |
error |
request_id, message |
Any failure. The process then exits non-zero. |
Example:
{"type":"progress","request_id":4821,"stage":"querying-repository"}
{"type":"progress","request_id":4821,"stage":"creating-worktree"}
{"type":"progress","request_id":4821,"stage":"starting"}
{"type":"result","request_id":4821,"pane_id":17,"branch":"agent/fix-login","base":"main","worktree_path":"/home/me/code/app.worktrees/agent-fix-login"}
Timeouts: 5 seconds to attach, 30 seconds for the repository query, 180 seconds for creation. When the creation confirmation times out the message says creation may still have completed, so check the session and git worktree list before retrying.
Chatroom is a file-backed message log (CHATROOM.md in the project root) that agents use to coordinate. These commands work on the file directly and do not need a running server or an attached interface. See Automation.
ilium chat init
ilium chat send --message <text> [--author <name>]
ilium chat context [--limit <n>] [--since-last-read] [--max-bytes <n>] [--reader <key>]
ilium chat tail [--limit <n>]| Subcommand | Option | Default | Behaviour |
|---|---|---|---|
init |
Creates CHATROOM.md if it does not exist, adds /CHATROOM.md and /CHATROOM.archive.md to .gitignore, and installs hook entries for Claude (.claude/settings.local.json) and Codex (.codex/hooks.json) on SessionStart and UserPromptSubmit, so agents see recent messages at the start of a session and before each prompt. Existing content in those files is preserved. Refuses to use a symlinked or non-regular CHATROOM.md. Prints chatroom ready at <path>. |
||
send |
--message <text> (required) |
Appends one record. Fails if the project has no chatroom, if the author or message is empty, or if the message is longer than 4000 characters. Prints chatroom message sent. |
|
send |
--author <name> |
$ILIUM_CHATROOM_AUTHOR, then $AGENT_NAME, then agent |
The name recorded with the message. |
context |
--limit <n> |
40 | Prints the last n records preceded by posting guidance, in the form injected into an agent turn by the lifecycle hooks. Prints an empty-room notice with the guidance when there are no messages. |
context |
--since-last-read |
off | Prints only records the reader has not seen yet and nothing when none are new. The reader is --reader, else the ILIUM_PANE_ID pane, else the session_id of the hook input on stdin. A reader seen for the first time, or a SessionStart hook, gets the full form with four times the --max-bytes budget. Without a reader key it behaves like plain context. |
context |
--max-bytes <n> |
unlimited | Caps the output size. Newest records win, a single oversized newest record is cut, and skipped records are counted in a closing note that points to ilium chat tail. |
context |
--reader <key> |
Explicit reader key for --since-last-read. Read positions are stored under .ilium/chat-readers/. |
|
tail |
--limit <n> |
100 | Prints the last n records for reading in a terminal, one per line: <timestamp> | <author> | <content>. |
Details:
- Timestamps are local time with an offset, like
2026-10-04 14:32:10 +02:00. send,contextandtaillook for the nearestCHATROOM.mdin the working directory or any parent, so they work from a subdirectory of the project.CHATROOM.mdis git-ignored and lives only in the main checkout, so from inside a linked Git worktree they use the main checkout's room instead. A shell that left its pane's worktree (for example in a scratch build folder) is mapped through the pane'sILIUM_WORKTREEvariable the same way.- If no room is found,
sendandtailfail withthis project does not have a chatroom.contextprints nothing, because session hooks run it in every project, including ones without a room. - Appends take an advisory lock, so several agents can post at once without interleaving.
- Fields are sanitised to one line each; control characters in a human-edited file are neutralised before they reach a model.
- A row for the Chatroom also appears in the project tree when a project has one.
Examples:
ilium chat init
ilium chat send --author claude --message "Taking the auth refactor in src/auth. Please avoid it."
ilium chat tail --limit 20
ilium chat context --limit 40ilium progress lets an agent (or a script it wrote) report a long-running task to the pane it runs in. The agent registers a cheap probe command; the Ilium server runs that probe on an interval and shows the result in the pane footer, in the tree and in notifications. Because the server, not the agent, does the polling, the agent can stop spending turns on status checks.
ilium progress check --command '<probe>'
ilium progress set --command '<probe>' [--interval-seconds <n>] [--wait] [--replace]
ilium progress wait [<monitor_id>]
ilium wait [<monitor_id>]
ilium progress status
ilium progress clear [--monitor-id <id> [--running] | --all]Requirements:
- It must run inside an Ilium terminal pane. The server injects the environment that identifies the pane. Outside a pane the command prints a
progress_request_failedrecord with codepane-identity-unavailableand exits non-zero withnot running inside an ilium-managed pane: ILIUM_PANE_ID is not set. - The progress monitor feature must be enabled (Settings → Appearance → Progress monitor,
progress_monitor_enabledin[ui]; on by default). When it is off, requests are rejected with codedisabled. - A pane holds up to 8 monitors at once, one per task, in registration order. The server keeps them in memory and in the session snapshot; a cleared monitor cannot be resurrected by a stale agent (see
--monitor-id).
The probe is a shell command line (at most 16 KiB). It must print exactly one JSON object on stdout and exit 0:
| Field | Required | Rules |
|---|---|---|
job_id |
yes | A stable, non-empty identifier of the task, at most 256 bytes. It must not change between probes of one monitor. |
status |
yes | One of not-started-yet, running, error, done. |
percent |
no | A finite number from 0 to 100 when progress is measurable. Omit it when progress is unavailable; done is shown as exactly 100. |
indeterminate |
no | Set to true when progress cannot be measured. The gauge and estimate are hidden. |
message |
recommended | One line, at most 2048 bytes, always visible in the pane footer. It should make sense to someone who has not read the agent's session. |
details |
optional | Multi-line text, at most 8192 bytes, shown when the user hovers the footer. |
eta_seconds |
optional | Whole seconds the task still needs (at most 315360000). Replaces the pace-based ETA in the footer when present. |
error |
required when status is error, forbidden otherwise |
Text, at most 4096 bytes. |
Limits: the probe may run for at most 30 seconds, produce at most 64 KiB on stdout and 16 KiB on stderr, and must exit successfully. A task that reports error is a task failure; a probe that cannot be run or read is a monitor failure, and the two are reported separately. After repeated consecutive observation failures (up to three) the monitor is marked failed rather than the task.
Working directory and environment. The server spawns the probe, not your shell. It does not inherit the pane's current directory, exported variables or aliases. It starts in the server's fixed working directory, the session's project root. Use absolute paths, or an unconditional cd /absolute/path && ... at the start.
Cost. The probe is a brand-new process on every tick, for as long as the monitor exists. Keep it cheap: read a small status file or counter, avoid walking trees, avoid network calls. If the check is inherently heavy, raise --interval-seconds instead of letting it run every second.
Runs one probe through the server and validates it, without installing anything. Always do this before set.
ilium progress check --command 'cat /tmp/build.status'On success prints:
{"type":"progress_check","request_id":...,"pane_id":12,"checked_at_unix_millis":...,"report":{"job_id":"build-7","status":"running","percent":42,"message":"Compiling crate 14 of 22","details":"","error":null}}
Validates the probe, then atomically adds a monitor to this pane, and waits for a correlated acknowledgement carrying the monitor ID and the accepted first report. Silence is never treated as acceptance. Other monitors of the pane are not touched. Registering the exact command of a monitor that is still running returns that monitor instead of adding a second one. Settled monitors whose outcome was already delivered make room for new ones; a ninth monitor that is still needed is refused with too-many-monitors.
| Option | Default | Meaning |
|---|---|---|
--command <probe> |
required | The probe command line. |
--interval-seconds <n> |
1 | How often the probe re-runs, from 1 to 86400 (24 hours). |
--wait |
off | After the acknowledgement line, block like ilium progress wait <monitor_id> and print its progress_wait line. |
--replace |
off | Clear every monitor of this pane first. Use only on purpose. |
ilium progress set --command 'cat /tmp/build.status' --interval-seconds 5{"type":"progress_set","request_id":...,"pane_id":12,"monitor_id":3,"progress":{"monitor_id":3,"report":{...},"monitor_health":{"state":"healthy"},"last_observed_unix_millis":...}}
Keep the monitor_id. After this, do not poll: the server watches the task and tells the agent when it reaches done or error. A live progress monitor can also suppress "agent finished" alerts while work continues. See Agent monitoring and Notifications.
Blocks until one monitor settles, then prints one progress_wait record and exits with a status an agent can act on. There is no elapsed-time deadline; the removed deadline flag is rejected as unsupported. Task, monitor/connection failure, clear/replacement and interruption remain terminal conditions. ilium wait is the same command. This is the normal way for an agent to wait: one blocking command instead of ending its turn or polling.
| Argument | Meaning |
|---|---|
<monitor_id> |
The monitor to wait for. Optional when the pane has exactly one monitor; with several, the command refuses with monitor-ambiguous (exit 2) and lists their IDs in monitor_ids. |
{"type":"progress_wait","pane_id":12,"monitor_id":3,"outcome":"done","exit_code":0,"waited_seconds":412,"composer_notice":"suppressed","next":"...","progress":{...}}
| Exit | outcome |
Meaning |
|---|---|---|
| 0 | done |
The task reported done. |
| 2 | (progress_rejected, code monitor-ambiguous) |
No ID given and the pane has several monitors. |
| 3 | error |
The task reported error. |
| 4 | monitor-failed |
The probe stopped working; the task outcome is unknown, so check the task directly. |
| 5 | cleared, no-monitor |
The monitor was cleared while waiting, or does not exist. |
While a wait is held, the server hands the outcome to it instead of typing a notification into the agent's prompt (composer_notice is suppressed). If the wait is killed first, the typed notification still arrives; may-also-arrive means a typed message about the same monitor is a duplicate.
Prints every monitor of the pane, in registration order, with its latest report and health.
{"type":"progress_status","request_id":...,"pane_id":12,"monitor_count":2,"running":true,"monitors":[{"monitor_id":3,...},{"monitor_id":4,...}]}
monitors is empty when the pane has no monitor. running is true while any monitor's task is still live. monitor_health.state is healthy, degraded or failed; the last two carry consecutive_failures and last_error.
Stops monitors and clears their retained results.
| Option | Meaning |
|---|---|
--monitor-id <id> |
Clear only this monitor. If it no longer exists, the request is rejected with stale-monitor and the other monitors are untouched. If its task is still running, the request is refused with monitor-running (exit 2), because on a pane shared by several agents the ID may belong to another agent's task. |
--running |
With --monitor-id: also clear the monitor when its task is still running. |
--all |
Clear every monitor of the pane. |
| (neither) | Clears the only monitor; refused with monitor-ambiguous when the pane has several. |
{"type":"progress_clear","request_id":...,"pane_id":12,"cleared":true,"cleared_monitor_ids":[3]}
Every failure is reported on stdout as one JSON record and the process exits non-zero.
type |
Meaning |
|---|---|
progress_rejected |
The server refused the request. Fields: operation, request_id, pane_id, code, message. |
progress_request_failed |
The request never completed. Fields: operation, request_id, pane_id (or null), code, message. Codes: pane-identity-unavailable, connection-failed, request-send-failed, transport-error. |
Rejection codes: disabled, invalid-request, invalid-probe-report, probe-spawn-failed, probe-timed-out, probe-exited-non-zero, probe-output-too-large, probe-io-failed, pane-not-found, stale-monitor, too-many-monitors, monitor-ambiguous. The CLI waits up to 45 seconds for the server's correlated reply.
# 1. Start the long job so its status file exists.
./run-tests.sh > /tmp/tests.log 2>&1 &
# 2. A cheap probe that prints one JSON object. Absolute paths only.
probe='cat /tmp/tests.status.json'
# 3. Validate, then register and block until the task settles.
ilium progress check --command "$probe"
# Run it with the longest wait your tool allows (in Claude Code, as a background
# command). The logical wait has no elapsed-time deadline.
ilium progress set --command "$probe" --interval-seconds 5 --wait
# 4. After handling the result:
ilium progress clear --monitor-id 3ilium voice say [--start] [--session-name <name>] [--timeout-s <seconds>] <SENTENCE>...
printf '%s\n' "focus the first agent" "say hello to it" | ilium voice say -Types sentences into the running voice conversation as if they had been spoken. Each sentence becomes one user turn, in order; the voice model interprets it and acts on it (for example by typing into the focused agent), and typed text can be mixed freely with live microphone audio. See Voice.
| Argument or option | Default | Meaning |
|---|---|---|
<SENTENCE>... |
required | Sentences, in order. A lone - reads one sentence per non-empty line from standard input, in place. Put -- first when a sentence starts with a hyphen. |
--start |
off | Switch voice control on when it is off (persisted, exactly as pressing F8 does), or restart a session that failed to start, instead of failing with voice-off. |
--session-name <name> |
default |
Session to address when not run from inside an Ilium pane. |
--timeout-s <n> |
30 | How long to wait for the voice session to accept the text, 1 to 600. Starting voice opens audio devices and the provider connection first, so allow longer with --start. |
Rules:
- The voice session lives in an attached interactive client: it owns the microphone, the provider connection and the tool executor. The command never starts a server and fails with
session-not-runningorno-voice-clientwhen no client is attached. - Run from inside an Ilium pane it addresses that pane's session (
session_sourceispane-env). Elsewhere it uses--cwdand--session-name(session_sourceiscwd). - Each sentence is trimmed and bounds-checked: at most 32 sentences per call, each at most 4000 characters, none empty.
- A result means the text is in the live session's queue. The provider sends no per-turn acknowledgement, so check the target for the outcome. Destructive voice actions still ask for confirmation, and terminal submission includes Enter unless you enabled the confirmation option.
- A server started before this command existed cannot answer it; restart Ilium to load the current server.
Output is JSONL: first a progress record, then exactly one result or error:
{"type":"progress","command":"voice say","stage":"sending","request_id":...,"session":"default","socket":"/run/user/1000/ilium/....sock","session_source":"cwd","sentence_count":2,"start":true}
{"type":"result","command":"voice say","ok":true,"request_id":...,"session":"default","sentence_count":2,"accepted_sentences":2,"voice_phase":"listening","started_voice":true,"delivery":"queued-to-voice-session"}
voice_phase is connecting, listening, recording, thinking or speaking. An error record carries code, message and a hint:
| Code | Meaning and hint |
|---|---|
invalid-request |
No sentences, an empty sentence, too many or too long. |
no-voice-client |
Attach an interactive client with ilium. |
voice-off |
Pass --start, or press F8 in the client. |
voice-unavailable |
Fix the voice settings (API key, audio devices) in Settings → Voice control. |
client-unresponsive |
The attached client did not answer; is it frozen or suspended? |
invalid-session |
The session name or --cwd is not valid. |
session-not-running |
Start Ilium in this project with ilium, or pass --cwd and --session-name. |
connection-failed, request-send-failed, server-closed-connection |
The server was unreachable or stopped answering; check ilium ls. |
timeout |
No answer within --timeout-s. |
stdin-unreadable |
The - input could not be read. |
The process exits non-zero after an error record. Human-readable diagnostics go to stderr.
ilium panes and ilium broadcast share one set of selection options, so a selection means the same thing in both. Use ilium panes with a selection first to see exactly which panes ilium broadcast would reach.
Both commands look at every running session on this machine, in every project: they list the live sockets in the session socket directory and read each session's pane tree in turn. A session started under a different ILIUM_SOCKET_DIR or XDG_RUNTIME_DIR is not visible.
| Option | Meaning |
|---|---|
-m, --match <TEXT> |
Keep panes whose searched fields contain TEXT, ignoring case. |
-e, --regex <PATTERN> |
Keep panes whose searched fields match the regular expression (Rust regex syntax, unanchored, case-insensitive). |
--field <FIELD> |
Fields searched by --match and --regex: name (title and short title), project, cwd, agent, session. Default: all. |
-v, --invert |
Keep panes that no --match or --regex matches. Needs at least one of them. |
-p, --project <PROJECT> |
Keep panes in these projects. A value with a path separator, or ., .., ~, is a directory and selects every project at or below it (relative values are resolved against --cwd). A bare value is a project folder name, compared ignoring case. |
--exclude-project <PROJECT> |
Drop panes in these projects (same syntax). Exclusion wins over --project. |
--here |
Keep only panes of the project that contains --cwd (the current directory by default). |
-s, --session <NAME> |
Keep panes in these session names. |
-a, --agent <AGENT> |
Keep panes running these agents: claude, codex, antigravity, or a custom agent's name. |
--state <STATE> |
Keep agents in these states: working, waiting-approval, waiting-subagents, settling, idle (includes done), done (finished a turn nobody has looked at yet). |
--kind <KIND> |
Keep panes of these kinds: agent, shell, editor, board, unavailable-agent (an agent pane whose program is not running). |
--pane <ID> |
Keep these pane ids. Ids are unique only within one session, so combine with --session or --project when several sessions run. |
How options combine:
- Different options narrow the selection (AND). Repeating an option, or giving it comma-separated values, widens that option (OR):
--project ilium,lumenand--project ilium --project lumenare the same. --matchand--regextogether form the text filter: a pane passes when any of them matches any searched field.--invertflips only the text filter, never the other options.- An invalid regular expression,
--invertwithout a pattern, or--hereoutside a readable directory prints anerrorrecord with codeinvalid-selection(orinvalid-requestforbroadcast) and exits 2.
ilium panes [selection options]
ilium panes --agent codex --state idleLists the selected panes, one pane record each, then a summary:
{"type":"pane","session":"default","pane_id":12,"name":"refactor parser","kind":"agent","agent":"Codex","state":"working","project":"/home/me/dev/ilium","cwd":"/home/me/dev/ilium","is_self":false}
{"type":"summary","command":"panes","ok":true,"sessions":3,"unreachable_sessions":0,"panes":1}
kind, agent and state use the values of the selection options; agent and state are null for panes that are not agents. is_self marks the pane running the command. A session that is running but cannot be read produces a warning record with code session-unreachable, and ok is then false; the command still exits 0.
ilium broadcast [selection options] [--when-idle] [--dry-run] [--include-self] <MESSAGE>...
ilium broadcast --project ilium,lumen "Re-read CLAUDE.md before your next step."
ilium broadcast --regex 'review|audit' --field name --invert --dry-run "Stop and report."
cat notice.md | ilium broadcast --agent claude -Sends one message to every selected agent: it is typed into the agent's prompt and submitted with Enter, exactly as the interface's "Send message to all" does. Shells, editors, boards, and agent panes whose program is not running are never typed into, whatever the selection. Sessions are visited one at a time, and each agent's delivery is confirmed by its server before the next.
| Argument or option | Default | Meaning |
|---|---|---|
<MESSAGE>... |
required | The message; several words are joined with spaces. A lone - reads the whole message from standard input. Put -- first when the message starts with a hyphen. |
--file <PATH> |
Read the message from a file instead (relative to the current directory). | |
--when-idle |
off | Send now only to idle agents. Busy agents get the message in their prompt queue and receive it when their current turn finishes. |
--dry-run |
off | Print what would happen to each recipient without sending anything. |
--include-self |
off | Also send to the pane running this command. By default it is skipped. |
--timeout-seconds <n> |
15 | How long to wait for each delivery's confirmation, 1 to 600. |
| selection options | all agents | See Pane selection. |
A trailing newline is removed. A multi-line message is sent as one bracketed paste, so the receiving program must have bracketed paste switched on (Claude Code and Codex do); otherwise that recipient reports a failed result.
Output is JSONL: a progress record, a warning per session that could not be read, one result per selected agent, then a summary:
{"type":"progress","command":"broadcast","stage":"sending","sessions":3,"message_bytes":41}
{"type":"result","command":"broadcast","outcome":"delivered","session":"default","pane_id":12,"name":"refactor parser","kind":"agent","agent":"Codex","state":"working","project":"/home/me/dev/ilium","cwd":"/home/me/dev/ilium","is_self":false}
{"type":"summary","command":"broadcast","ok":true,"dry_run":false,"sessions":3,"unreachable_sessions":0,"recipients":1,"delivered":1,"queued":0,"planned":0,"skipped":0,"failed":0}
outcome is delivered, queued (--when-idle), would-send or would-queue (--dry-run), skipped (the calling pane) or failed; skipped and failed carry a reason. A failed delivery that timed out may still arrive.
Exit status: 0 when at least one agent was reached (or planned) and nothing failed; 1 when nothing was selected, any delivery failed, or any running session could not be read; 2 for an invalid selection or an empty message.
ilium close-pane [--pane <id>] [--worktree keep|remove|remove-and-branch] [--timeout-seconds <n>]
ilium close-pane --worktree removeCloses a pane of the running session. With no --pane, it closes the pane the command runs in, from the ILIUM_PANE_ID variable Ilium sets in every pane. This is how a worktree agent wraps up: commit, merge into the base branch, then run ilium close-pane --worktree remove as the last step.
| Argument or option | Default | Meaning |
|---|---|---|
--pane <id> |
this pane | Close another pane of the same session instead. |
--worktree keep |
keep | Close the pane and leave its worktree on disk. |
--worktree remove |
Close the pane, then remove its worktree when it is clean, merged into its recorded base branch, has no running process, and was created by Ilium. The branch is kept. | |
--worktree remove-and-branch |
As remove, and also delete the creation branch when that is safe. |
|
--timeout-seconds <n> |
120 | How long to wait for the server's answer. |
The server runs the same checks as Safe remove in the worktree manager (see Worktrees). The server stops the pane's processes, checks for running processes and custody tickets, removes the worktree, and closes the pane. The worktree is removed only when every check passes. A refusal keeps the worktree and reports the reasons. A refusal that comes after the pane's processes have stopped also closes the pane; a refusal before that point (for example uncommitted or untracked files) leaves the pane open. Ilium never removes a worktree it did not create; such a request is blocked.
Closing a pane stops every process in it, including this command. The server still completes the request, but the lines printed after the pane stops may not reach the calling agent. Confirm the result with git worktree list and git branch --list <branch> in the main checkout.
Output is JSONL: a progress record, then exactly one answer:
{"type":"progress","command":"close-pane","request_id":1783428455846,"pane_id":12,"worktree":"remove","stage":"requesting-close"}
{"type":"result","command":"close-pane","request_id":1783428455846,"pane_id":12,"worktree":"remove","outcome":"removed","reasons":[]}
| Record | Meaning |
|---|---|
result with outcome closed |
The pane closed; the worktree was kept (keep). |
result with outcome removed |
The pane closed and its worktree was removed. |
blocked |
The server refused. reasons says why (uncommitted changes, not merged, running process, foreign worktree, and so on). Nothing was removed. |
uncertain |
The server did not confirm in time, or a removal reported a failure partway. Inspect the worktree before retrying; do not assume it is gone or intact. |
error |
The request never ran. code is not-inside-ilium-pane, pane-not-found, session-unreachable, connection-closed or server-error. |
Exit status: 0 for result; 1 for blocked or uncertain; 2 for error.
ilium recap [selection options]
ilium recap --kind agent --length short --format markdownWrites a short and a long factual recap of each selected pane. The selection options are the same as ilium panes and ilium broadcast (see Pane selection). Terminal panes are included by default: agents, shells and unavailable agents. Editors and boards are skipped; an unavailable agent produces an explicit unavailable record without reading its historical transcript or invoking inference. The pane that runs the command is skipped unless --include-self is given.
Recaps are generated by the AI provider you configured under Inference and privacy. One model call covers both lengths of one pane. ilium recap does nothing and sends nothing when automatic AI is off or onboarding is not finished: every selected pane then gets a denied record.
| Option | Meaning |
|---|---|
--length short|long|both |
Lengths to print. Default both. short is at most 40 words; long is at most 250 words. |
--format jsonl|markdown |
Output format. Default jsonl. |
--timeout-seconds <N> |
Limit for the whole run, 1 to 600. Default 60. Panes still running at the limit are reported as failed; panes that finished keep their text. Ctrl-C cancels the run the same way. |
--max-concurrency <N> |
Panes recapped at the same time, 1 to 8. Default 4. |
--max-panes <N> |
Most panes recapped in one run, 1 to 64. Default 32. Extra selected panes produce a warning. |
--include-self |
Also recap the pane that runs the command. |
- Agent panes use the transcript of the pane's own session. Ilium reads it only when the session id the server reports for that pane resolves to a transcript inside that pane's project. If no such transcript exists, the pane is
unavailable; Ilium never falls back to the screen for an agent. - Shell panes request only their selected pane's current screen, capped at 64 KiB before text allocation. Ilium does not subscribe to terminal journals for a recap. Busy, oversized or replaced screens are
unavailable; an available empty screen isidle. - Reads are bounded: a few megabytes of transcript head and tail, long lines skipped, prompts and answers clipped, and at most 40 screen lines.
- Secrets are redacted before any text leaves Ilium: values of keys such as tokens, passwords and API keys are replaced with
[redacted], and key names stay visible. - Paths in the sensitive areas Ilium denies, such as SSH and cloud credential folders, are never read and never offered as pointers.
Each recap is a few factual sentences. Its pointers are file or resource paths named in the evidence. Ilium keeps a pointer only when the path appears in the evidence, lies under the pane's project or working directory, exists now, and is not denied. Other pointers are dropped, and rejected_pointers counts them.
Goals are not written by the model. For agent panes Ilium reads the goal recorded in the transcript (/goal in Claude Code, the thread goal in Codex) and reports its state as Goal active, Goal paused, Goal blocked, Goal done or Goal state unknown. A done goal means the goal was completed. Whether the agent is working on it now is the separate state of the pane, so a finished goal and an idle pane can both be true.
state |
Meaning |
|---|---|
summarized |
Text was produced from current evidence. |
idle |
Nothing to recap: an empty transcript or an empty screen. |
denied |
Not read: AI is off, onboarding is not finished, or the pane's project is a denied location. |
unavailable |
No verified evidence source: no transcript bound to the session, or an agent kind Ilium cannot read. |
stale |
The pane or its session changed while the recap was running, so the text was dropped. |
failed |
Provider error, timeout, cancellation or an answer that did not match the contract. failure says which. |
evidence_age_seconds is the age of the newest evidence. evidence_stale is true when that age is over 600 seconds, so the recap may describe work that has since moved on.
JSONL, one object per line:
{"type":"recap","pane_id":"12","pane_name":"refactor parser","state":"summarized","goals":["Goal active: Finish the parser refactor"],"evidence_age_seconds":42,"evidence_stale":false,"window_truncated":false,"short":{"text":"The parser refactor is in progress. The lexer tests pass.","pointers":[{"path":"/home/me/dev/ilium/src/parser.rs","note":"parser entry point"}],"rejected_pointers":0},"long":null,"failure":null}
{"type":"warning","pane_id":"12","state":"failed","message":"provider timed out"}
{"type":"summary","panes":1,"summarized":1,"idle":0,"denied":0,"unavailable":0,"stale":0,"failed":0,"cancelled":false}
pane_id is a string here. A long value is null when --length short was given. Markdown output prints one section per pane with the same facts.
Exit status is 0 when the run finished, including with failed or stale panes; read the summary and warning records for per-pane outcomes. Exit 2 means an invalid selection, and exit 1 means the configuration could not be read.
ilium ctl is the full remote-control surface for agents and scripts. It reads the live tree and changes it: anything the interface does to panes, projects and groups has a command. Start with ilium ctl guide, which prints the essentials as example commands; ilium ctl guide topics lists deeper topics (reading, creating, controlling, arranging, http) and ilium ctl ops prints one JSON example of every operation.
Global options: --session NAME (session of the --cwd project), --socket PATH (one live session, see ilium ctl sessions), --format json|jsonl|yaml|markdown for reads. Inside an Ilium pane the pane's own session is the default. Nodes are addressed by numeric id; projects also by absolute path, directory name or display name when unambiguous.
| Command | What it does |
|---|---|
ctl tree [--depth N] [--project P] [--no-details] |
The whole session. |
ctl project P / ctl node ID |
One project or node and its subtree. |
ctl pane ID [--screen] [--lines N] |
Everything known about one pane, optionally with its screen text. |
ctl find [--agent A] [--state S] [--kind K] [--project P] [--name-contains T] |
Flat list of matching panes. |
ctl screen ID [--lines N] |
Current screen text of a terminal pane. |
ctl wait ID [--state idle,done] [--timeout S] |
Block until an agent reaches a state or the pane closes. |
ctl whoami, ctl sessions |
The calling pane; live sessions. |
ctl new-pane [--project P | --parent ID] [--workdir DIR] [--agent claude|codex|agy [--prompt T]] [--worktree --branch B [--base REF]] [--editor FILE] [--keep-open] [-- CMD] |
Create a shell, command, editor or agent pane; a worktree pane creates the Git worktree first. |
ctl new-project DIR, new-group NAME, new-folder DIR, new-split-view NAME ID ID..., change-folder P DIR |
Create and re-point containers and split views. |
ctl replace-command ID COMMAND |
Replace the process of a pane with a shell command line. |
ctl new-board NAME PATH [--markdown], freeze ID RESUME, unfreeze ID |
Open a kanban board pane; park a pane as a frozen placeholder and restart it. |
ctl rename ID TITLE, close ID [--worktree keep|remove|remove-and-branch], move ID (--up | --down | --to PARENT [--index N]) |
Rename, close and arrange. |
ctl send ID TEXT [--no-enter], keys ID KEY..., schedule ID --in S TEXT, queue ID TEXT [--times N | --forever], queue-clear ID, terminate ID |
Drive a pane. |
ctl bookmark ID [--off], expand ID, collapse ID, lock-closed ID [--off] |
Sidebar state. |
ctl restructure PLAN.json [--project P], ctl revert-restructure [--project P] |
Apply or undo a restructure plan (planning stays in the interface). |
ctl kill-session |
End the session. |
ctl op JSON (or - for standard input) |
Any operation as JSON, same body as POST /v1/ops. |
Reads print one document in the chosen format. Mutations print one JSONL record: {"type":"result","ok":true,"op":...} with the ids involved, or {"type":"error","code":...,"message":...}. A mutation succeeds only after the server's tree shows the change. Exit status: 0 success, 2 bad arguments or selector, 3 rejected or not confirmed, 4 no reachable session. Reads never start a server; new-pane starts the project's session when none runs.
Variables set by Ilium inside every terminal pane:
| Variable | Meaning |
|---|---|
ILIUM_PANE_ID |
This pane's numeric ID. Used by ilium progress to address the pane. |
ILIUM_SESSION_NAME |
The session the pane belongs to. |
ILIUM_SESSION_SOCKET |
The session's socket path. ilium progress and ilium voice say use it to reach the right server. |
ILIUM_WORKTREE |
Canonical root of the pane's Git worktree. Present only for a workspace-backed pane. |
ILIUM_BRANCH |
The worktree's branch name, when the worktree setup command runs. |
Variables you can set:
| Variable | Meaning |
|---|---|
ILIUM_CHATROOM_AUTHOR, AGENT_NAME |
Default author for ilium chat send (in that order, then agent). |
ILIUM_CONFIG_DIR |
Use this directory instead of the platform default for config.toml (~/.config/ilium on Linux, ~/Library/Application Support/ilium on macOS, %APPDATA%\ilium on Windows). A relative value is resolved against the current directory. |
ILIUM_SOCKET_DIR |
Directory for session sockets and locks. Honoured on every platform. |
ILIUM_DEBUG_LOG_DIR |
Root directory for debug logs. |
XDG_RUNTIME_DIR |
On Linux, the default parent of the ilium/ socket directory. When it is not set, a short per-user directory under /tmp is used. |
XDG_CONFIG_HOME, XDG_DATA_HOME |
Standard locations honoured on Linux. |
SHELL, COMSPEC |
The shell that runs new-pane commands. On Windows, a POSIX-style SHELL (for example Git Bash) keeps POSIX quoting. |
Relative values for the ILIUM_*_DIR overrides are made absolute so that the client and the detached server agree on the same path.
Logging is off by default. When enabled in Settings, logs are written under the debug log root and can contain project prompts and request bodies (credentials redacted). Treat them as sensitive. The five newest logs per session are kept.
| Command | stdout | Failure output |
|---|---|---|
ilium, new-session |
the interface | ilium: <error> on stderr |
ls, kill-session, new-pane (plain), chat |
plain text | ilium: <error> on stderr |
new-pane --worktree |
JSONL (progress, result, error) |
an error record, plus ilium: <error> on stderr |
progress |
JSONL, one record per call | a progress_rejected or progress_request_failed record, plus the error on stderr |
voice say |
JSONL (progress, then result or error) |
an error record, plus the error on stderr |
panes, broadcast |
JSONL (see each command) | an error record for an invalid selection or message (exit 2); broadcast exits 1 when nothing was selected or any delivery failed |
recap |
JSONL (recap, warning, summary), or Markdown with --format markdown |
an error record for an invalid selection (exit 2) or a configuration problem (exit 1) |
Every JSONL line is a single JSON object with a type field. Parse stdout line by line and branch on type; paths and IDs are explicit fields.
Exit status:
0on success.1on any failure (invalid directory or session name, session not running, server did not start within 5 seconds, server-reported error, rejected request, timeout).2for command-line usage errors reported by the argument parser, such as an unknown flag, a missing required argument, or--restart-servercombined with--reset-session.
Error messages worth knowing:
| Message | Meaning |
|---|---|
--cwd "..." is not a valid directory |
The directory does not exist. |
could not locate the ilium-server binary next to ... or on PATH |
The server binary is missing. Keep ilium and ilium-server together. |
session "<name>"'s server did not become ready within 5s |
Server start timed out. See the log under the debug log root. |
session "<name>" is not running |
The command needs a live session. |
project session socket path is too long |
The session name and digest overflow the socket path limit. Use a shorter name or set ILIUM_SOCKET_DIR to a short path. |
Other binaries and hidden commands
ilium-server: the background daemon, one per project session. You normally never start it yourself;iliumspawns it detached with internal arguments. It also accepts unauthenticatedPOST /create_agentrequests on127.0.0.1:8872; any local process can submit one, so keep that listener private (the port is[api].portinconfig.toml). See Automation.ilium-animation-helper: the confined helper that runs bundled.iliumanimanimations. It and the animations must stay besideilium. See Animations.- Hidden subcommands exist for internal and release qualification use (
clipboard-helper,release-embedding-probe,release-animation-probe). They are not part of the user interface and may change without notice. - Flatpak builds forward the
iliumcommand to the host so panes can use host tools. See Installation.
Start an agent for a task in its own worktree and keep the final JSONL line (the result record) for a script:
ilium new-pane --worktree --branch agent/fix-login -- codex | tail -n 1Add a long-running dev server as a pane in a named session:
ilium new-pane --session-name dev -- npm run dev
ilium new-session dev # attach laterTell the voice assistant something from a script, starting voice if needed:
ilium --cwd ~/code/app voice say --start "what agents are running?"Post a hand-off to the room when you finish:
ilium chat send --author "$AGENT_NAME" --message "Finished the parser change; tests pass in src/parse."Check every session of several projects:
for dir in ~/code/*/; do echo "== $dir"; ilium --cwd "$dir" ls; doneThrow away a session's saved layout and begin again:
ilium --reset-session new-session scratch| Symptom | Cause and fix |
|---|---|
ilium progress says it is not inside a pane |
You ran it from a normal terminal. Run it inside an Ilium terminal pane, where ILIUM_PANE_ID is set. |
| Progress shows 0% forever | The probe uses relative paths. The server runs it from the project root, not the pane's directory. Use absolute paths. |
progress set rejected with disabled |
Enable Progress monitor in Settings → Appearance. |
progress rejected with invalid-probe-report |
The probe printed more than one object, a non-JSON line, a changed job_id, a bad status, a percent outside 0 to 100, or error with the wrong status. Run progress check and read the message. |
voice say fails with no-voice-client |
No interactive client is attached. Run ilium in the project first. |
voice say fails with server-closed-connection or timeout |
The running server predates the command, or the client is unresponsive. Restart Ilium to load the current server. |
new-pane --worktree says the branch exists |
Choose an unused branch name. |
new-pane prints no confirmation received from the server |
The server is busy or the session is not the one you meant. Check ilium ls and --session-name. |
chat send says the project does not have a chatroom |
Run ilium chat init first. |
| After installing a new build the old behaviour persists | A running server keeps its old executable. Use ilium --restart-server (panes are relaunched from the snapshot) when you are ready. |
ilium resource (alias ilium ressource) coordinates exclusive access across linked projects on this machine. Commands connect to an existing project server; they never start or restart one. Use --project PATH or the global --cwd PATH to select a project and optionally --session NAME to select its session. An explicit project directory takes precedence over an inherited pane connection; when selecting a project explicitly, supply --agent PANE or --agent SESSION/PANE for agent operations. Without an explicit project or session, commands can infer the current pane.
| Command | Result |
|---|---|
resource list [--all] / resource show SLUG |
Project bindings or the user-wide catalog, including queue and gate state |
resource create --name NAME --slug SLUG [--kind KIND] [--device-identity ID] [--description TEXT] [--rules TEXT] |
Create one shared resource and bind this project |
resource link RESOURCE_ID --slug SLUG |
Bind an existing shared resource |
resource edit SLUG [--name NAME] [--description TEXT] [--rules TEXT] [--kind KIND] [--device-identity ID | --clear-device-identity] |
Edit the shared definition |
resource unlink SLUG / resource archive SLUG |
Remove this binding, or archive an unused shared resource |
resource repair SLUG |
Retry managed instruction/settings projection and read back its synchronization state |
resource rebind PROJECT_ID PROJECT_PATH --expected-revision N |
Rebind a moved project using its stable identity and current catalog revision |
resource reserve [AGENT] SLUG DURATION |
Return a reservation ID, ownership generation or FIFO position and estimate |
resource wait RESERVATION |
Block until acquisition or explicit error; show native queue progress |
resource status [RESERVATION] |
Read authoritative status; authenticated acquisition readback acknowledges delivery |
resource release RESERVATION |
Release the current generation after actual hardware use stops |
resource cancel RESERVATION |
Cancel the agent's queued claim |
resource estimate RESERVATION DURATION |
Update the estimate without extending or expiring ownership |
resource gate SLUG open|paused|unavailable [--reason TEXT] |
Change availability without clearing occupancy |
resource recover SLUG --reason TEXT [--expected-revision N] |
From an agent pane of the project: clears a stale (rebooted or dead) owner in one step. For a live owner: interactive, typed confirmation by the user |
Mutations return a timestamped request key. Reuse it with --request-id KEY when retrying an uncertain response; changing the payload under the same key is rejected. Durations use explicit units, for example 20m or 1h30m, from one second through seven days. Interrupted waits retain reservations. Estimates never expire ownership or prove that hardware is safe. User cancellation additionally requires --reason TEXT --expected-revision N and fresh interactive confirmation. See Resource queues for recovery and GPU/USB-board workflows.