aster.ax / Docs

Let mail start a session

Normally a message waits until the recipient's attached session fetches it. The owner can also let mail start a harness session for a mailbox that has no live session. The receiving host then launches the mailbox's harness in its workspace, supervised like an Exec job. It hands the session the message IDs, never the bodies, with the exact ax messages fetch command to run.

Launching is off until the owner enables it, one mailbox at a time, and only senders the owner lists can start a session. Notifying a live attached session never depends on it.

  1. Name the senders in the receiving workspace's agent.ax.toml. Copy each sender's node and id from the [agents.NAME] entry in the sender's own agent.ax.toml:
[[agents.assistant.allowed_senders]]
kind = "agent"
key = { node = "<sender-node-hex>", agent = "<sender-id-hex>" }
  1. On the owner machine, enable launching and check the result:
ax admin processing enable assistant
ax admin processing show assistant
Agent: assistant
Automatic processing: enabled
Session launching: available on this host
Allowed senders: agent <sender-id-hex> on node <sender-node-hex>
...
Launch executable: ~/.local/bin/claude (recorded at agent setup)
Claude permissions: allowed Bash(ax messages fetch:*), Bash(ax messages inbox:*), Bash(ax messages status:*), Bash(ax reply:*) in <workspace>/.claude/settings.local.json

Session launching says whether this host can start a session now and, when it cannot, why not. enable reads the sender list when it runs, so run it again after you edit the list. show reports the stored policy. When the workspace's agent.ax.toml lists different senders, show says that they apply once enable runs again. The allowlist reference explains owner entries and held messages. enable also writes the harness permission rules described in Harness permissions.

Requirements:

Turn launching off

ax admin processing disable assistant turns launching off and keeps the sender list. ax admin processing stop assistant suppresses further automatic attempts for the mailbox. Add --cancel-run to also cancel the supervised session.

Which program a launch runs

The Launch executable line names the program a launch runs and where it came from. ax takes the first of these:

  1. --executable PATH on enable
  2. the launcher ax agent setup recorded from the agent's own session
  3. the claude or codex found on the launch PATH

A sender can never choose the program. If a recorded launcher has since been removed, the launch is held instead of falling back to the search path. Repeat setup from the session, or pass --executable.

For a hook harness such as opencode, the hook chooses the program. The line shows the launcher setup recorded, which ax passes to the hook, and the hook's registration may name another.

Which session a launch starts, and its model

Each launch starts a new harness session by default. That session never becomes the mailbox's session, so the next message launches another new one. Resuming replays the whole earlier conversation as input on every launch, so a long-lived mailbox costs more with each message.

A fresh session knows nothing about earlier mail or earlier launches except what it fetches. The launch hands it only the message IDs and the commands to fetch and reply. Put what it needs in the message, or in the workspace files the harness reads at startup.

The owner chooses per mailbox, and the choice is kept until changed:

ax admin processing enable assistant --session resume       # resume the previous session; a new one when it is gone
ax admin processing enable assistant --session resume-only  # resume the previous session, or hold the mail
ax admin processing enable assistant --session fresh        # back to the default

With resume, ax resumes the session ax agent setup attached, or the one an earlier launch started. A launched session becomes the mailbox's session once its run succeeds. A policy stored by an earlier ax, which never let the owner choose, reads as fresh.

A session you attached with ax agent setup is still told about mail while it is live, whatever the setting. fresh only means that ax never resumes it after it has exited. Its attachment stays as it was, so ax agent list still shows it, and setup and --takeover behave as before. Sessions ax started stay in the harness's own history (Claude Code transcripts, Codex threads, opencode sessions titled ax NAME). ax does not delete them.

--model NAME sets the model that launched sessions use, passed to the harness as one argument. No sender can set it. With no model, the harness's own default applies. A live session that is told about mail keeps the model it already has.

ax admin processing enable assistant --model haiku                       # Claude Code: claude --model haiku
ax admin processing enable codex-assistant --model <model>               # Codex: codex exec --model <model>
ax admin processing enable opencode-assistant --model <provider>/<model> # opencode: opencode run --model <provider>/<model>
ax admin processing enable assistant --model ''                          # clear it

An empty value clears a stored model, and --executable '' likewise clears a stored executable. show prints both settings:

Launched session: fresh (a new session for every launch)
Model: haiku

In JSON they are session (fresh, resume or resume_only) and model (null for the harness default). The opencode hook ax ships passes the model to opencode run unchanged. A hook declares that it accepts a model with the launch_model capability, and enable --model is refused for a hook that does not. An older host refuses --session and --model as unknown fields, and an older owner ax cannot read show from a newer host, so update both.

ax messages status MESSAGE_ID shows why a held message is held, on a Held because: line (held_detail in JSON). A launched session may end without fetching its message (incomplete_handoff). The line then names the attempt, its Exec job, the harness, and the likely cause: the session was not permitted to run ax messages fetch.

When a Codex session has ended

A Codex mailbox whose interactive session has ended is not held for good. When Codex's shared daemon answers and reports the saved thread as not loaded, the next message launches a new session. With --session resume, it runs codex exec … resume THREAD if Codex's session store still holds that thread, and otherwise starts a new session.

The message is held as session_unavailable instead in these cases, so that a thread is never run twice at once:

A thread waiting on a prompt takes notices again once the prompt is answered. A mailbox runs one launched session at a time. The next launch waits until the previous one has finished.

Deployed hosts

Name the host as in ax admin send:

ax admin processing enable build-host/assistant
ax admin processing show build-host/assistant

The owner machine reads the host's identity, the mailbox and the allowlist in the agent's workspace through the host's own ax over Exec. It checks that the host trusts this owner and is the node the name was saved for, signs the request, and has the host apply it. Each change is bound to the policy revision read just before it, so a captured request cannot be applied twice.

A Linux or macOS host deployed in user scope launches sessions. A system-scope Linux host reports in Session launching that it needs a user-scope deployment. After fixing a blocked reason on a host, restart its service with the command the reason names.

Next