Act on an environment
Supported actions:
rotate-token— generate fresh per-VM credentials, upload them to the guest filesystem, and persist the orchestrator’s encrypted copy. Returns 204. Note: the running fused process reads its token once at startup and keeps serving the old token until it is restarted; rotation currently takes full effect only after the guest agent restarts.drain— first phase of two-phase teardown. Runs the environment’s configured drain command inside the guest (default: the fused drain command) so in-guest workloads quiesce gracefully; an empty drain command only transitions the state. The VM transitions todrainingbut is not destroyed; a subsequent DELETE tears it down. Only running VMs can be drained — any other state returns 409. If the drain command fails the VM remains indrainingso the caller can still DELETE; the failure is returned as 5xx. A VM left indraininglonger than the orchestrator’s draining timeout (--draining-timeout, default 5m30s) is destroyed by the reconcile loop, unless a hitl decision is pending on it or its destroy is gated.fork— create a new environment seeded from a checkpoint of this one. Withreuse_snapshot_idempty the server snapshots the source first; otherwise it reuses that ready snapshot (it must belong to this VM). The fork is pinned to the source’s host, receives its own guest credentials (fused is restarted), and is returned as a new Environment with 201. GPU environments (spec.gpus > 0, including MIG) and QEMU-hosted environments cannot be forked: a vfio device cannot be checkpointed, so the request returns 409conflict. That is a permanent property of the environment and must not be retried.exec— run a single command inside the guest and return its exit code, stdout, and stderr. Takes an ExecEnvironmentRequest body and returns an ExecEnvironmentResponse. See the exit-code contract below.request: the agent asks a human for something the environment’shitl.requestsdeclares: anask, asecretor atakeover(RequestHumanRequest). Returns 201 with the pending Intervention.takeover: a human takes control of the environment (TakeoverRequest, body optional). Claims the agent’s pending takeover request when there is one, else opens a new takeover on the caller’s behalf. Returns 200 with the intervention, stillpending, withpayload.takeover.holderandstarted_atset. While it is held the agent’sexecand computer actions get 423locked. Taking over again as the current holder returns the same intervention. Needshitl:takeover; the agent’s own key cannot claim the request it raised (403self_approval). 409 when someone else already holds it, or the VM is not running. 400 when the environment does not declarehitl.requests.takeover, or not for thisvia.release: end the held takeover (ReleaseRequest, body optional). The intervention is approved andnotebecomes itsdecision.answer, which is what the waiting agent reads; an empty note becomesreleased by <actor>. Any caller withhitl:takeovermay release, not only the holder, so a takeover whose holder walked away does not have to wait out its deadline. Returns 200 with the intervention. 409 when nothing is held, or the takeover expired before the release arrived.
Exec: a non-zero exit code is not an HTTP error. A guest
command that exits non-zero comes back as 200 with that
code in exit_code. The command ran, and it failed; that is the
answer the caller asked for, not a transport failure. Clients
and SDKs must surface it as a value and must not raise on it.
HTTP errors are reserved for the cases where the command could not be run at all:
- 400
invalid_argument— neithercmdnorshellwas set, or both were. - 403
unauthorized— exec requires the master token. API keys are refused: exec is root in the guest, and keys carry no scopes today. - 404
not_found— unknown VM. - 409
conflict— the VM is not running (e.g. draining). - 423
locked: a human holds the environment (a takeover), or anaskstall is waiting for a human to ack it. Nothing ran.details.intervention_idnames the intervention anddetails.kindistakeoverorstall. Wait on it with GET /v1/interventions/{interventionId}?wait= until it is no longerpending, then send the exec again. The lock never outlives the intervention’s deadline. The SDKs do this by default. - 501
unimplemented— the provider has no guest to exec into (e.g. the in-memory stub).
Fork error mapping. Fork returns 409 conflict for three
distinct preconditions:
- the reused snapshot (
reuse_snapshot_id) is not in stateready; - the source holds a GPU passthrough device (permanent — do not retry);
- with
reuse_snapshot_idempty, the implicit seed snapshot is refused because the snapshot quota (count or bytes) is exhausted. This 409 has nothing to do with a reused snapshot’s state, so do not infer the cause from the status code alone.
404 covers an unknown VM or snapshot, including a reused snapshot that is no longer present on the host.
Known limitation: the remaining fork and rotate-token
precondition failures — source VM not running, and a provider
with no fork support — still return 500 internal rather than
409/501. Treat the message, not the status code, as the contract
until these move to 4xx.
Hitl gates. When the environment’s hitl.gates or
hitl.exec match, exec, fork, migrate, drain and
rotate-token are checked before anything runs. A gate in ask
mode answers 202 with a HeldResponse and performs the action only
once a human approves it; notify lets it run and records a
terminal intervention; deny answers 403 forbidden with
details.reason hitl_denied. A grant from an earlier approval
(env or ttl:<duration>) lets a matching action through
without a prompt.
/v1/environments/{vmId}AuthorizationBearer token · headerrequiredfuse_sessionAPI key · cookierequiredvmIdstringrequiredactionstringrequiredrotate-tokendrainforkmigrateexecrequesttakeoverreleaseFuse-ActorstringFuse-Actor-Namestringapplication/jsoncmdstring[]shellstringtimeout_msintegerreuse_snapshot_idstringcommentstringtarget_host_idstringlivebooleanlazybooleankindstringasksecrettakeoverreviewquestionstringchoicesstring[]targetstringmessagestringpathstringcontentstringformatstringtextdiffviastringterminaldesktopreasonstringtimeout_secondsinteger<int64>viastringterminaldesktopreasonstringnotestringidstringrequiredstatestringrequiredprovisioningrunningdrainingdestroyingtask_idstringrequiredhost_idstringurlstringrequiredspecResourceSpecrequiredShow propertiesHide properties
cpusinteger<int32>ram_mbinteger<int32>storage_gbinteger<int32>gpusinteger<int32>gpu_kindstringgpu_profilestringimagestringregionstringhost_idstringlabelsobjecthuge_pagesbooleanmax_runtime_secondsinteger<int64>idle_timeout_secondsinteger<int64>created_atstring<date-time>requiredupdated_atstring<date-time>requirederrorstringendpointsEndpoint[]Show propertiesHide properties
EndpointasstringurlstringrequiredprotocolstringtcpudpportintegerrequiredhealthobjectShow propertiesHide properties
statestringrequiredstartingpassingfailingsincestring<date-time>failuresintegermessagestringegressobjectShow propertiesHide properties
modestringrequireddirectproxyproviderstringprotocolstringsocks5httpendpointstringhealthobjectShow propertiesHide properties
statestringrequiredunknownhealthyunhealthyreasonstringchecked_atstring<date-time>exit_codeintegerrequiredstdoutstringrequiredstderrstringrequiredidstringrequiredenv_idstringrequiredkindstringrequiredasksecrettakeoverreviewexeclifecyclecomputerstallexpirygatestringmodestringasknotifydenystatestringrequiredpendingapprovedrejectedexpiredcancelledpayloadobjectrequiredShow propertiesHide properties
questionstringchoicesstring[]execExecPayloadShow propertiesHide properties
argvstring[]requiredshellstringtimeout_msinteger<int64>lifecycleLifecyclePayloadShow propertiesHide properties
actionstringrequireddestroyforkmigratedrainsnapshotrotate-tokensecretInterventionSecretShow propertiesHide properties
targetstringrequiredlabelstringrequiredmessagestringtakeoverInterventionTakeoverShow propertiesHide properties
viastringrequiredterminaldesktopreasonstringholderActorShow propertiesHide properties
idstringrequirednamestringsourcestringrequiredpinnedassertedkeysystemdeciderkey_idstringstarted_atstring<date-time>signalInterventionSignalShow propertiesHide properties
failuresintegerlast_exit_codeintegerquiet_secondsinteger<int64>reaperstringidle_timeoutmax_runtimereap_atstring<date-time>extended_untilstring<date-time>computerComputerPayloadShow propertiesHide properties
actionstringrequiredtextstringinputobjectrequiredreviewInterventionReviewShow propertiesHide properties
pathstringcontentstringrequiredformatstringrequiredtextdiffmessagestringtruncatedbooleandeciderInterventionDeciderShow propertiesHide properties
verdictstringrequiredaskreasonstringerrorstringtriggered_byActorrequiredShow propertiesHide properties
idstringrequirednamestringsourcestringrequiredpinnedassertedkeysystemdeciderkey_idstringdeadlinestring<date-time>requiredon_timeoutstringrequiredrejectallowdecisionobjectShow propertiesHide properties
outcomestringrequiredapproverejectanswerstringreasonstringdecided_byActorrequiredShow propertiesHide properties
idstringrequirednamestringsourcestringrequiredpinnedassertedkeysystemdeciderkey_idstringdecided_atstring<date-time>requirededited_argvstring[]edited_textstringgrantstringresultInterventionResultShow propertiesHide properties
execExecEnvironmentResponseShow propertiesHide properties
exit_codeintegerrequiredstdoutstringrequiredstderrstringrequiredcomputerComputerActionResponseShow propertiesHide properties
outputstringscreenshotstringenv_idstringsnapshot_idstringerrorstringfinished_atstring<date-time>requiredcreated_atstring<date-time>requiredupdated_atstring<date-time>requiredidstringrequiredstatestringrequiredprovisioningrunningdrainingdestroyingtask_idstringrequiredhost_idstringurlstringrequiredspecResourceSpecrequiredShow propertiesHide properties
cpusinteger<int32>ram_mbinteger<int32>storage_gbinteger<int32>gpusinteger<int32>gpu_kindstringgpu_profilestringimagestringregionstringhost_idstringlabelsobjecthuge_pagesbooleanmax_runtime_secondsinteger<int64>idle_timeout_secondsinteger<int64>created_atstring<date-time>requiredupdated_atstring<date-time>requirederrorstringendpointsEndpoint[]Show propertiesHide properties
EndpointasstringurlstringrequiredprotocolstringtcpudpportintegerrequiredhealthobjectShow propertiesHide properties
statestringrequiredstartingpassingfailingsincestring<date-time>failuresintegermessagestringegressobjectShow propertiesHide properties
modestringrequireddirectproxyproviderstringprotocolstringsocks5httpendpointstringhealthobjectShow propertiesHide properties
statestringrequiredunknownhealthyunhealthyreasonstringchecked_atstring<date-time>idstringrequiredenv_idstringrequiredkindstringrequiredasksecrettakeoverreviewexeclifecyclecomputerstallexpirygatestringmodestringasknotifydenystatestringrequiredpendingapprovedrejectedexpiredcancelledpayloadobjectrequiredShow propertiesHide properties
questionstringchoicesstring[]execExecPayloadShow propertiesHide properties
argvstring[]requiredshellstringtimeout_msinteger<int64>lifecycleLifecyclePayloadShow propertiesHide properties
actionstringrequireddestroyforkmigratedrainsnapshotrotate-tokensecretInterventionSecretShow propertiesHide properties
targetstringrequiredlabelstringrequiredmessagestringtakeoverInterventionTakeoverShow propertiesHide properties
viastringrequiredterminaldesktopreasonstringholderActorShow propertiesHide properties
idstringrequirednamestringsourcestringrequiredpinnedassertedkeysystemdeciderkey_idstringstarted_atstring<date-time>signalInterventionSignalShow propertiesHide properties
failuresintegerlast_exit_codeintegerquiet_secondsinteger<int64>reaperstringidle_timeoutmax_runtimereap_atstring<date-time>extended_untilstring<date-time>computerComputerPayloadShow propertiesHide properties
actionstringrequiredtextstringinputobjectrequiredreviewInterventionReviewShow propertiesHide properties
pathstringcontentstringrequiredformatstringrequiredtextdiffmessagestringtruncatedbooleandeciderInterventionDeciderShow propertiesHide properties
verdictstringrequiredaskreasonstringerrorstringtriggered_byActorrequiredShow propertiesHide properties
idstringrequirednamestringsourcestringrequiredpinnedassertedkeysystemdeciderkey_idstringdeadlinestring<date-time>requiredon_timeoutstringrequiredrejectallowdecisionobjectShow propertiesHide properties
outcomestringrequiredapproverejectanswerstringreasonstringdecided_byActorrequiredShow propertiesHide properties
idstringrequirednamestringsourcestringrequiredpinnedassertedkeysystemdeciderkey_idstringdecided_atstring<date-time>requirededited_argvstring[]edited_textstringgrantstringresultInterventionResultShow propertiesHide properties
execExecEnvironmentResponseShow propertiesHide properties
exit_codeintegerrequiredstdoutstringrequiredstderrstringrequiredcomputerComputerActionResponseShow propertiesHide properties
outputstringscreenshotstringenv_idstringsnapshot_idstringerrorstringfinished_atstring<date-time>requiredcreated_atstring<date-time>requiredupdated_atstring<date-time>requiredintervention_idstringrequiredinterventionInterventionrequiredShow propertiesHide properties
idstringrequiredenv_idstringrequiredkindstringrequiredasksecrettakeoverreviewexeclifecyclecomputerstallexpirygatestringmodestringasknotifydenystatestringrequiredpendingapprovedrejectedexpiredcancelledpayloadobjectrequiredShow propertiesHide properties
questionstringchoicesstring[]execExecPayloadShow propertiesHide properties
argvstring[]requiredshellstringtimeout_msinteger<int64>lifecycleLifecyclePayloadShow propertiesHide properties
actionstringrequireddestroyforkmigratedrainsnapshotrotate-tokensecretInterventionSecretShow propertiesHide properties
targetstringrequiredlabelstringrequiredmessagestringtakeoverInterventionTakeoverShow propertiesHide properties
viastringrequiredterminaldesktopreasonstringholderActorShow propertiesHide properties
idstringrequirednamestringsourcestringrequiredpinnedassertedkeysystemdeciderkey_idstringstarted_atstring<date-time>signalInterventionSignalShow propertiesHide properties
failuresintegerlast_exit_codeintegerquiet_secondsinteger<int64>reaperstringidle_timeoutmax_runtimereap_atstring<date-time>extended_untilstring<date-time>computerComputerPayloadShow propertiesHide properties
actionstringrequiredtextstringinputobjectrequiredreviewInterventionReviewShow propertiesHide properties
pathstringcontentstringrequiredformatstringrequiredtextdiffmessagestringtruncatedbooleandeciderInterventionDeciderShow propertiesHide properties
verdictstringrequiredaskreasonstringerrorstringtriggered_byActorrequiredShow propertiesHide properties
idstringrequirednamestringsourcestringrequiredpinnedassertedkeysystemdeciderkey_idstringdeadlinestring<date-time>requiredon_timeoutstringrequiredrejectallowdecisionobjectShow propertiesHide properties
outcomestringrequiredapproverejectanswerstringreasonstringdecided_byActorrequiredShow propertiesHide properties
idstringrequirednamestringsourcestringrequiredpinnedassertedkeysystemdeciderkey_idstringdecided_atstring<date-time>requirededited_argvstring[]edited_textstringgrantstringresultInterventionResultShow propertiesHide properties
execExecEnvironmentResponseShow propertiesHide properties
exit_codeintegerrequiredstdoutstringrequiredstderrstringrequiredcomputerComputerActionResponseShow propertiesHide properties
outputstringscreenshotstringenv_idstringsnapshot_idstringerrorstringfinished_atstring<date-time>requiredcreated_atstring<date-time>requiredupdated_atstring<date-time>requirederrorobjectrequiredShow propertiesHide properties
codestringrequirednot_foundroute_not_foundconflictinvalid_argumentunauthorizedforbiddenunavailableinternalunimplementedlockedmessagestringrequireddetailsobjecterrorobjectrequiredShow propertiesHide properties
codestringrequirednot_foundroute_not_foundconflictinvalid_argumentunauthorizedforbiddenunavailableinternalunimplementedlockedmessagestringrequireddetailsobjecterrorobjectrequiredShow propertiesHide properties
codestringrequirednot_foundroute_not_foundconflictinvalid_argumentunauthorizedforbiddenunavailableinternalunimplementedlockedmessagestringrequireddetailsobjecterrorobjectrequiredShow propertiesHide properties
codestringrequirednot_foundroute_not_foundconflictinvalid_argumentunauthorizedforbiddenunavailableinternalunimplementedlockedmessagestringrequireddetailsobjecterrorobjectrequiredShow propertiesHide properties
codestringrequirednot_foundroute_not_foundconflictinvalid_argumentunauthorizedforbiddenunavailableinternalunimplementedlockedmessagestringrequireddetailsobjecterrorobjectrequiredShow propertiesHide properties
codestringrequirednot_foundroute_not_foundconflictinvalid_argumentunauthorizedforbiddenunavailableinternalunimplementedlockedmessagestringrequireddetailsobjecterrorobjectrequiredShow propertiesHide properties
codestringrequirednot_foundroute_not_foundconflictinvalid_argumentunauthorizedforbiddenunavailableinternalunimplementedlockedmessagestringrequireddetailsobjectcurl -X POST "http://localhost:8080/v1/environments/string?action=rotate-token" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"cmd": [
"ls",
"-l"
],
"timeout_ms": 5000
}'const response = await fetch("http://localhost:8080/v1/environments/string?action=rotate-token", {
method: "POST",
headers: {
"Authorization": "Bearer YOUR_TOKEN",
"Content-Type": "application/json"
},
body: JSON.stringify({
"cmd": [
"ls",
"-l"
],
"timeout_ms": 5000
})
});import requests
response = requests.post(
"http://localhost:8080/v1/environments/string?action=rotate-token",
headers={
"Authorization": "Bearer YOUR_TOKEN",
"Content-Type": "application/json"
},
json={
"cmd": [
"ls",
"-l"
],
"timeout_ms": 5000
},
){
"id": "string",
"state": "provisioning",
"task_id": "string",
"host_id": "string",
"url": "string",
"spec": {
"cpus": 0,
"ram_mb": 0,
"storage_gb": 0,
"gpus": 0,
"gpu_kind": "string",
"gpu_profile": "string",
"image": "string",
"region": "string",
"host_id": "string",
"labels": {},
"huge_pages": true,
"max_runtime_seconds": 0,
"idle_timeout_seconds": 0
},
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z",
"error": "string",
"endpoints": [
{
"as": "string",
"url": "string",
"protocol": "tcp",
"port": 0
}
],
"health": {
"state": "starting",
"since": "2024-01-01T00:00:00Z",
"failures": 0,
"message": "string"
},
"egress": {
"mode": "direct",
"provider": "string",
"protocol": "socks5",
"endpoint": "string",
"health": {
"state": "unknown",
"reason": "string",
"checked_at": "2024-01-01T00:00:00Z"
}
}
}{
"id": "string",
"state": "provisioning",
"task_id": "string",
"host_id": "string",
"url": "string",
"spec": {
"cpus": 0,
"ram_mb": 0,
"storage_gb": 0,
"gpus": 0,
"gpu_kind": "string",
"gpu_profile": "string",
"image": "string",
"region": "string",
"host_id": "string",
"labels": {},
"huge_pages": true,
"max_runtime_seconds": 0,
"idle_timeout_seconds": 0
},
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z",
"error": "string",
"endpoints": [
{
"as": "string",
"url": "string",
"protocol": "tcp",
"port": 0
}
],
"health": {
"state": "starting",
"since": "2024-01-01T00:00:00Z",
"failures": 0,
"message": "string"
},
"egress": {
"mode": "direct",
"provider": "string",
"protocol": "socks5",
"endpoint": "string",
"health": {
"state": "unknown",
"reason": "string",
"checked_at": "2024-01-01T00:00:00Z"
}
}
}{
"intervention_id": "string",
"intervention": {
"id": "string",
"env_id": "string",
"kind": "ask",
"gate": "string",
"mode": "ask",
"state": "pending",
"payload": {
"question": "string",
"choices": [
"string"
],
"exec": {
"argv": [
"string"
],
"shell": "string",
"timeout_ms": 0
},
"lifecycle": {
"action": "destroy"
},
"secret": {
"target": "string",
"label": "string",
"message": "string"
},
"takeover": {
"via": "terminal",
"reason": "string",
"holder": {
"id": "string",
"name": "string",
"source": "pinned",
"key_id": "string"
},
"started_at": "2024-01-01T00:00:00Z"
},
"signal": {
"failures": 0,
"last_exit_code": 0,
"quiet_seconds": 0,
"reaper": "idle_timeout",
"reap_at": "2024-01-01T00:00:00Z",
"extended_until": "2024-01-01T00:00:00Z"
},
"computer": {
"action": "string",
"text": "string",
"input": {}
},
"review": {
"path": "string",
"content": "string",
"format": "text",
"message": "string",
"truncated": true
},
"decider": {
"verdict": "ask",
"reason": "string",
"error": "string"
}
},
"triggered_by": {
"id": "string",
"name": "string",
"source": "pinned",
"key_id": "string"
},
"deadline": "2024-01-01T00:00:00Z",
"on_timeout": "reject",
"decision": {
"outcome": "approve",
"answer": "string",
"reason": "string",
"decided_by": {
"id": "string",
"name": "string",
"source": "pinned",
"key_id": "string"
},
"decided_at": "2024-01-01T00:00:00Z",
"edited_argv": [
"string"
],
"edited_text": "string",
"grant": "string"
},
"result": {
"exec": {
"exit_code": 0,
"stdout": "hi\n",
"stderr": ""
},
"computer": {
"output": "string",
"screenshot": "string"
},
"env_id": "string",
"snapshot_id": "string",
"error": "string",
"finished_at": "2024-01-01T00:00:00Z"
},
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z"
}
}{
"error": {
"code": "not_found",
"message": "string",
"details": {}
}
}{
"error": {
"code": "not_found",
"message": "string",
"details": {}
}
}{
"error": {
"code": "not_found",
"message": "string",
"details": {}
}
}{
"error": {
"code": "not_found",
"message": "string",
"details": {}
}
}{
"error": {
"code": "not_found",
"message": "string",
"details": {}
}
}{
"error": {
"code": "not_found",
"message": "string",
"details": {}
}
}{
"error": {
"code": "not_found",
"message": "string",
"details": {}
}
}