Session runtime
Status model, branch creation, sandbox layout, injected environment, and the in-sandbox daemon.
The runtime mechanics of a session. For the technical model of what a session is, see Sessions.
A session is one conversation with the agent, run in an isolated sandbox VM (provisioned on Daytona) with the project repo cloned and checked out on a branch named after the session id. The sandbox is ephemeral; the branch persists. Work reaches the default branch only through a change request.
Status model
A session row (project_sessions) carries a status. The enum defines queued, branching, provisioning, running, stopped, failed, completed; the runtime only writes a subset:
| Status | Set when |
|---|---|
provisioning | At session create — the row is inserted directly as provisioning. The session branch is created and the sandbox is requested during this phase. |
running | Once the sandbox is live and reachable. |
stopped | On explicit stop, or by the idle sweep that hibernates inactive sandboxes. |
failed | If provisioning errors out. |
queued and branching exist in the enum but are not part of the live session flow; completed is defined but not currently written. The sandbox itself is tracked in a separate session_sandboxes row with its own states (provisioning → active → stopped | error | archived).
Concurrent-session caps are enforced per account; exceeding your tier returns 429.
Branch model
- The session branch is named after the session id (a UUID).
MACHINE_SESSION_IDandMACHINE_BRANCH_NAMEare the same value. - It is cut from
base_ref, which defaults to the project'sdefault_branch(usuallymain), at create time. - Creation path depends on the backend: GitHub repos use the GitHub API (read the base tip, create the branch ref); generic git backends push
refs/heads/<base>:refs/heads/<session-id>. - Triggers create their session branch the same way an interactive session does. Nothing writes the default branch directly except a change-request merge.
What survives
Only what the agent commits and pushes to the session branch. The sandbox filesystem is disposable — re-cloned fresh on every boot, torn down on stop, hibernation, or restart. Commit in small chunks so a mid-run teardown loses nothing already pushed. The branch reaches the default branch only once a change request merges it.
Layout inside the sandbox
/workspace ← WORKDIR. The project repo is cloned here.
/workspace/.machine/ ← Repo-internal Machine folder (Dockerfile + opencode config dir).
/usr/local/bin/machine-agent ← The daemon (supervisor + reverse proxy).
/usr/local/bin/machine-entrypoint ← The container ENTRYPOINT (PID 1).
/opt/machine/home ← OpenCode's HOME — its object store lives here, off the repo.OpenCode's HOME is /opt/machine/home, not /workspace, so its store never lands among your repo files.
Injected environment
Injected at boot, alongside your project's secrets (which arrive as plain env vars):
| Variable | What |
|---|---|
MACHINE_PROJECT_ID | UUID of this project. |
MACHINE_SESSION_ID | UUID of this session. Also the branch name. |
MACHINE_BRANCH_NAME | Same as MACHINE_SESSION_ID — the branch your work pushes to. |
MACHINE_REPO_URL | Clone URL for the project repo. |
MACHINE_DEFAULT_BRANCH | The base ref (the repo's default branch). |
MACHINE_BASE_REF | The ref this session branched from. |
MACHINE_SERVICE_PORT | 8000 — the daemon's external port. |
MACHINE_API_URL | The platform API base (…/v1). |
MACHINE_AGENT_NAME | The OpenCode agent the session was created with. |
MACHINE_OPENCODE_MODEL | The model to run, when set. |
MACHINE_INITIAL_PROMPT | The first prompt, when the session was spawned by a trigger or created with one. |
MACHINE_PROJECT_AUTO_CLONE | 1 — tells the daemon to clone the repo on boot. |
MACHINE_PROJECT_SECRET_NAMES | Comma-separated names of the project's secrets. |
MACHINE_PROJECT_SECRETS_REVISION | Revision marker for the secret set. |
MACHINE_TOKEN | The sandbox service key. The daemon signs and validates its own control-surface requests with it. It is not a project API token, and the machine CLI does not read it — the project-scoped API routes reject it. |
MACHINE_CLI_TOKEN | The project-scoped PAT the in-sandbox machine CLI authenticates with (same value as MACHINE_EXECUTOR_TOKEN). |
MACHINE_EXECUTOR_TOKEN | The same project-scoped PAT — acts as the launching user, scoped to the project. Also backs the machine-executor MCP gateway. |
MACHINE_BOOTSTRAP_OPENCODE_SESSION | 1 when the session was created with an initial prompt — tells the daemon to open the OpenCode session at boot. |
MACHINE_LLM_API_KEY · MACHINE_LLM_BASE_URL | Managed LLM-gateway key + base URL, injected only on plans that use Machine's bundled model access. MACHINE_YOLO_API_KEY / MACHINE_YOLO_URL are aliases for the same pair. |
Not injected: MACHINE_WORKSPACE (/workspace) is baked into the image, not per session. No MACHINE_GITHUB_TOKEN — git credentials are fetched just-in-time by the daemon (below). When a project brings its own model keys they travel as ordinary project secrets OpenCode reads at boot; the MACHINE_LLM_* pair above appears only on plans that use Machine's managed model access.
The MACHINE_* prefix is reserved for platform variables; a user secret using it is rejected (Secrets).
Pushing from a session
The daemon fetches a short-lived clone credential (GET /v1/projects/:id/git/clone-credential) using MACHINE_TOKEN — no static token in the environment. With that, git push origin HEAD sends commits to the session branch. Landing on the default branch goes through a change request.
The agent runtime
The agent is OpenCode, launched by the daemon as opencode serve --port 4096 --hostname 127.0.0.1 with OPENCODE_CONFIG_DIR at the project's config dir ([opencode] config_dir, default .machine/opencode), resolved from the cloned repo. See Machine vs OpenCode config.
The daemon control surface
The machine-agent binary runs as PID 1's child and fronts OpenCode on MACHINE_SERVICE_PORT (8000). Everything outside /machine/* requires the HMAC-signed X-Machine-User-Context header (validated against MACHINE_TOKEN).
| Path | Purpose |
|---|---|
GET /machine/health | Liveness (auth-bypassed). Reports daemon + OpenCode state, repo, branch, commit. |
POST /machine/refresh | Re-pull the session branch and restart OpenCode in place. |
POST /machine/prompt | Deliver a prompt to the running agent. |
POST /machine/abort | Abort the current run. |
POST /machine/env | Update the runtime environment. |
/proxy/{port}/* | Reverse-proxy to a port inside the sandbox (its own port is blocked). |
* | Catch-all reverse-proxy to OpenCode on 127.0.0.1:4096 (503 while it boots). |
/machine/refresh is how the dashboard applies an out-of-band change (e.g. a manifest edit committed from a parallel session) without re-provisioning the sandbox.
