Sessions, Runs, and Reviews
sessions.inspect returns a Session with its Runs, and review.inspect returns its Reviews. Start and follow tasks and Review pull requests show how to call them.
A Run's machine says where its work runs: { "kind": "managed", "size": "large" } for a devboxes machine, or { "kind": "runner", "id": "…", "name": "…" } for one of your own machines. It is null until devboxes creates the Run's task.
origin says where the Session's first Run came from: chat for a Chat thread, schedule for an occurrence of a Schedule in the thread where it was set up, issue for an issue, through its tracker or a Schedule that a new issue fired, and direct for the CLI, the MCP server, or the API. A Session that a Run dispatched has that Run's origin. Its link opens the thread, in Google Chat the Space, or the issue. For a conversation in the devboxes app, the link opens that conversation and is given only to the person who had it; anyone else gets null. The link is null for direct. A thread's link is also null when you ask from a thread of another Channel, when the thread's conversation was erased, when the chat provider has no link, and when devboxes can't resolve it, for example because the thread's chat connection was removed or its Channel routes no Project.
A Session's repositoryUrl is the web address of its Project's repository, or null for a taskbox. Its pullRequestMode says how its work reaches a pull request. own: its Runs open the Session's own pull request. in_place: they push to the pull request the Session was started for. stacked: they open the Session's own pull request into that pull request's branch. A Session that works in place becomes stacked when branch protection refuses its push.
sessions.inspect also returns pullRequest, the pull request that the Session's work goes to: on a stacked Session, its own pull request once a Run opened it, and otherwise the one that pullRequestNumber names. Its read gives the state, whether it is a draft, the title, the head and base branches, and the checks of its head commit, as devboxes last read them from GitHub: its check runs and commit statuses. sessions.refresh-pull-requests reads them again, for a pull request that isn't merged and whose latest read attempt is more than 30 seconds old, and readAt says when a read last succeeded. read is null until the first read succeeds.
sessions.list returns the same pullRequest for each Session, with its checks counted as passed, failed and pending instead of listed. A list answers from what devboxes stored and then reads its pull requests again in the background, on the same 30-second schedule, so a later list shows the new state. A merged pull request is not read again.
Run status
status | Meaning |
|---|---|
queued | The Run has not started. queueReason can name why. |
running | The Run works. |
cancel_requested | A person or devboxes stopped the Run, and it is ending. |
succeeded | The Run finished its Blueprint. |
failed | The Run failed. Its error gives the reason. |
cancelled | A person or devboxes stopped the Run. |
paused | The Run stopped because its model account's usage limit or credit is exhausted. |
A Run's summary is what the agent reported: the result it gives when it reports the goal achieved or, when it did not, what it did in the completed agent nodes and why the failed agent nodes stopped. Its answers to the messages people sent during the Run follow. A failed Run has no summary. A paused Run stopped because its model account's usage limit or credit is exhausted. The Session keeps the Run's work, and the Run's error names the provider and gives the provider's answer. When the Blueprint's publish node had not run yet, the Run first pushes its work to the Session's branch as a checkpoint commit. Continue the Session once the limit resets or the credit is renewed, or continue it on another account that offers the same model. When the agent stops without doing the work because something the work needs is missing or unfinished, such as other work it depends on, its agent node fails with the agent's reason. Unless that node has a failed or completed edge, the Run is then failed and its error gives the reason.
Who stopped a Run
stoppedBy says who stopped a cancel_requested or cancelled Run. person gives the name of the person who stopped it with sessions.cancel. credit means devboxes stopped it because your Organization's compute credit ran out. halt means devboxes stopped it while it paused Runs to resolve an operational issue. It is null for any other Run, and when devboxes can't name who stopped it.
Why a Run waits
queueReason names a wait that devboxes knows about:
workspace_image: the Run waits for a workspace build: the Project's first, a new one that the task was started to wait for, or the workspace built for its Runner's platform, which devboxes builds once per workspace and platform. The value comes from the build stage that devboxes last recorded, so it can stay set for a while after the build finishes.images.inspectshows the build's current state. When a build for the Runner's platform fails, the Run fails and itserrorgives the reason. When another build fails and the Project has an earlier workspace, the Run starts on that one. When the Project's first build fails on devboxes' side, devboxes builds the workspace again by itself while the Run waits, up to three times, and once more whenever devboxes updates its image builder, and the Run starts once it is ready. When the image builder rejects the Project's packages or services, the Run starts once a laterimages.configurebuilds. See Give agents the tools your repository needs.retry: devboxes hit a problem on its side and starts the work again by itself.retryAttemptsays which retry this is. Failures on devboxes' side explains when and how.capacity: capacity that devboxes manages has no room for the Run yet. The Run starts when room frees up.credit: 3 Runs already run on your own Runners, and your Organization has no money for a fourth. The Run starts when one of them ends or when your Organization has money again.
A queueReason of null does not mean that the Run is about to start. A Run on a Runner also waits while the Runner works on another task or is offline.
Where a continuation starts
continuation says where sessions.continue starts its new Run:
checkpoint: from the work the Session saved.beginning: from the start of the task, because every earlier Run ended before its agent started.unavailable: the latest Run that reached its agent ended before the Session kept its work, sosessions.continuefails withCHECKPOINT_UNAVAILABLE. Start a new task withsessions.dispatchinstead.
Node states
While a Run works, follow its progress in nodes. It holds the states of the nodes of the Run's Blueprint version, which blueprintVersionId names. A running node has the state running and a startedAt time. A node that has finished has an endedAt time, and a command node also has the exitCode of its command.
| Node state | Meaning |
|---|---|
running | The node runs. |
succeeded | The node finished. A command node exited with code 0. |
failed | The node failed, or the Run ended while the node still ran. |
skipped | None of the node's incoming edges matched, or the Run ended before it reached the node. |
Agent events
sessions.events shows the agent's messages and tool calls as it works, oldest first. With latest, it shows the newest ones, which tell what the agent did most recently. Each page holds up to 1,000 events. To read on, pass the page's cursor as after. To read back through older events, pass latest and the first event's id of the page you have as before: cursor is always the page's last event. devboxes runs command nodes outside the log that sessions.events reads, so while a command node runs, such as one that runs your tests, sessions.events shows its next events once the command node ends. A long command still shows as running in nodes.
devboxes doesn't keep the contents of the files that the agent writes, edits, patches, or reads in the events. A repository Session's changes live in its pull request. A write or edit call keeps the file's path, but not the text it wrote or replaced. A patch call keeps no input. Each file diff keeps the file's name, status, and counts of added and removed lines, but not the diff. A read result shows as "devboxes doesn't keep file contents." A tool call's raw input text is empty.
personMessages lists the messages that came from people, as id and text: the opening prompt of every work Run, which is the Run's instruction, and every message sent with sessions.input. Every other prompt in the events is one that devboxes gave the agent, such as the opening of a review, fix, or recheck Run.
How a Review ends
The result lists the findings with their severity (high, medium, or low), file, and line. A finding without a severity counts as medium. A finished Review ends in one of three ways:
complete: the reviewer found nothing more. You decide whether to merge.handoffReasonstarts withREVIEW_PASSED.merged: the reviewer found nothing more, and the pull request merged at the reviewed commit.handoffReasonsays whether devboxes merged it (MERGE_COMPLETED) or found it merged, for example by a person (PULL_REQUEST_MERGED).handoff: devboxes stopped and needs you.handoffReasonstarts with a code from the tables below, or with the code of a command refusal that stopped the Review.
| Reason | What happened |
|---|---|
REVIEW_RUN_ENDED | The review, fix, or recheck Run failed or was cancelled. The reason names the Run's kind and how it ended. |
REVIEW_STATE_CHANGED | The candidate, or a provider Review of it, changed while devboxes reviewed it. |
FIX_BUDGET_EXHAUSTED | The fix budget ran out, and findings remain. |
FIX_NOT_PUBLISHED | The fix Run did not publish the current candidate. |
REVIEW_FAILED | devboxes could not advance the Review for another reason. |
A review, fix, or recheck Run that fails because of a problem on devboxes' side is retried within the same Review, up to three times, as retry in Why a Run waits describes. The Review keeps its state and its fix budget. When the pull request changed meanwhile, or after the third retry, the Review ends in handoff.
While devboxes waits for the checks of an approved pull request before it merges, the Review is in merge.
When devboxes doesn't merge an approved pull request, the Review ends in handoff, and handoffReason says why:
| Reason | What happened |
|---|---|
MERGE_CHECKS_FAILED | A check failed, was cancelled, timed out, became stale, or needs an action. The reason names the checks. |
MERGE_EXPIRED | devboxes had not merged a day after the Review, for example because the checks had not finished. |
MERGE_HELD | A person held merging the work of a Session that carries the pull request. The reason gives theirs. |
MERGE_CANDIDATE_CHANGED | The pull request was closed, someone pushed to it, reviewed it, or changed its review threads after the Review, or a person commented on it or replied in its review threads after the work started. |
MERGE_FAILED | devboxes could not merge for a reason GitHub did not give. |
MERGE_REFUSED | GitHub refused the merge, for example because the pull request conflicts with its base branch or branch protection requires an approval. The reason contains GitHub's message. |
When automatic Review doesn't start for a work Run, that Run's handoffReason in the Review's evidence says why. It starts with one of these codes, or with the code of the command refusal that kept Review from starting:
| Reason | What happened |
|---|---|
REVIEW_NO_CHANGES | The Run published no changes, so there is nothing new to review. |
REVIEW_NO_PULL_REQUEST | No pull request carries the Run's work. |
REVIEW_START_EXPIRED | Review could not start within 24 hours after the work ended. The reason gives the last cause. |
While Review waits to start, the reason gives the last cause it hasn't started yet: EXECUTOR_NOT_STOPPED when the machine that did the work hasn't reported that it stopped, REVIEW_START_FAILED after an unexpected internal error, or the code of a command refusal. devboxes keeps trying until the 24 hours pass.