opencode sessions
ax serves opencode through an executable-hook adapter that ships inside ax, rather than as a built-in harness. opencode calls its server API experimental, so the hook is written for opencode 2.x. With any other major version it stops with an error that names the installed version and the one it supports. The hook can notify an existing opencode session of its mail and, for a mailbox the owner enabled, launch opencode to process it.
Install the opencode hook
Register the hook once per host, as the account the ax service runs as. Then restart the ax service, because it reads adapter registrations only when it starts:
ax agent adapters install opencode
ax exec daemon restart # owner machine
systemctl --user restart ax.service # Linux host deployed in user scope
The command writes the hook to adapters/opencode/ax-opencode-hook in the
messaging state directory. It adds an [adapters.opencode] entry to that
directory's adapters.toml, the owner-local file in which every hook adapter
is registered. An existing adapters.toml keeps its other entries and
comments. If it already registers opencode differently, the command reports
the entry to put in its place. Run the command again after an ax update to
refresh the hook.
--opencode PATH names the opencode program the hook runs. Without it, the
hook runs the first of these it finds:
- the opencode the agent's own session was running when setup recorded it
opencodeon the service'sPATH~/.opencode/bin/opencode
The service's PATH does not normally include ~/.opencode/bin.
Set up an opencode agent
Inside the opencode session, have the agent run:
ax agent setup --name assistant --workspace /absolute/path
opencode gives its tool shells OPENCODE_SESSION_ID,
so setup binds that session without --harness or --session. It does so
after the hook has confirmed that opencode knows the session and that the
session belongs to this workspace. Setup also records the opencode program the
session runs, which is the opencode server that tool shells run under. If the
hook is not registered yet, setup stops and prints the command to run. To bind
a session from outside it, use --harness opencode --session ses_….
How ax works with an opencode session
- Notify. While the session exists, each message is one queued prompt to
it (
opencode api session.promptwithdelivery: "queue"). The prompt names the message ID and the fetch command, never the body. opencode stores it whether the session is idle or busy. A repeated notice reuses the same prompt id, so opencode keeps one copy.ax messages status MESSAGE_IDshows aNotice: sent to opencode session … at …line (noticein JSON) for a message a session was told about and has not fetched yet. - Launch. With
ax admin processing enable(see Let mail start a session), a mailbox whose session no longer exists runsopencode run --format json --title "ax NAME" --session SESSIONin the workspace, with the instructions on stdin. It adds--modelwhen the owner set one. A fresh session's id is derived from the launch request, so ax finds the session it started again without storing anything else. With--session resume, that session becomes the mailbox's session once the run succeeds. By default it does not, and the next message starts another session instead of prompting this one. - Replies from a launched session. While a launched session runs, the
mailbox is still attached to the old session, so the reply command in the
instructions carries the run's
--attempt. ax accepts a reply that names the mailbox's active attempt and one of its messages, from any session. It refuses any other reply from a session other than the attached one. - Resumes.
opencode run --sessionwith an unknown id creates that session, so the hook never plans a resume of a session opencode does not confirm. ax never passes--auto, which widens permissions, or--standalone. - Unknown is not missing. Only opencode's own
SessionNotFoundErrormakes a session missing. A stopped service, a timeout or an unreadable answer leaves it unknown, and the message stays held assession_unavailablerather than starting a second session.ax agent listasks the hook too. The session shows asattached, asunavailableonce opencode reports it gone, or asunknownwith the reason, including when the hook does not answer within 3 seconds. A reply or send from another session is refused only while the hook reports the attached session reachable or cannot tell. - The hook never starts opencode's service.
opencode apistarts the background service when it finds none, and the hook runs inside the ax service. The hook therefore asksopencode service statusfirst, which only reads. With the service stopped, it answers unknown without callingopencode api. A launch is different:opencode runstarts the service it needs, and on Linux Exec stops what a run left behind when it ends, so that server stops with the run.
opencode permissions
opencode has no sandbox. Its permission rules decide only whether it asks
before running a command. ax agent setup for an opencode agent, ax agent move and ax admin processing enable make sure the workspace's
.opencode/opencode.jsonc holds these two rules, creating the file if needed:
{
"permissions": [
{"action": "shell", "resource": "ax messages fetch *", "effect": "allow"},
{"action": "shell", "resource": "ax reply *", "effect": "allow"}
]
}
opencode combines project rules with the user's own, and the last matching
rule wins, so ax appends its rules after any already in
the file. The opencode permissions line (opencode_permissions in JSON)
says whether they were written, were already present, or could not be
written. ax rewrites the file only when it is plain JSON. A file with comments
or trailing commas is left exactly as it is, and the line names the two
entries to add to its permissions array by hand.
- Unattended sessions. A notice to a session with no client attached
runs the turn inside the opencode server. If a command there needs
approval, the turn waits for an answer that may never come. A launched
opencode runrejects such a command instead and ends. A launched session that ended without fetching is held asincomplete_handoff. Keep the two allow rules in place, and checkax messages statusfor a message that was noticed but not fetched. - Environment. A tool command runs with the environment of the last
opencode runclient that drove the session. A session ax launched gets ax's launch environment, withaxfirst onPATH. A session last driven from your own terminal has that terminal's environment, and itsaxmust reach the same ax home. - Version scope. The hook is written for opencode 2.x and was developed against opencode 2.2.5 on Linux. The opencode server API reports itself as experimental (OpenAPI version 0.0.1), and its v1 and v2 endpoints differ.
Next
- Mailboxes and sessions explains mailbox registration for every harness.
- Let mail start a session: enable launches and choose the session and model settings an opencode launch uses.
- Harness permissions lists the rules ax writes for Claude Code and Codex.