Create exec

Executes a program in a throwaway sandbox and answers with what it printed and what it left behind.

POST /v1/exec

Addresshttps://api.hanzo.ai/v1/exec
MethodPOST
Operationpost_exec
AuthAuthorization: Bearer $HANZO_API_KEY

Executes a program in a throwaway sandbox and answers with what it printed and what it left behind.

lang names one of the thirteen the sandbox image carries — py, js, ts, bash, r, php, go, rs, c, cpp, java, d, f90 — and code is the whole program, not a fragment: a compiled language is compiled and then run, an interpreted one is interpreted, and args becomes the program's own argv either way. Nothing is installed for you; the image is the environment.

A PROGRAM THAT FAILS IS A SUCCESSFUL CALL. A non-zero exit answers 200 with the diagnostics on stderr, because "the code threw" and "the interpreter is down" are different facts a caller renders differently. Only the second is an error status.

Runs are stateful through session_id. Omit it and the run gets a fresh sandbox whose id comes back on the answer; pass that id again and the next run sees the same filesystem, so a program can write a file one call and read it the next. files names bytes already uploaded to a session (POST /v1/exec/upload), copied in before the program starts. files on the ANSWER is what the program created or changed, by comparison against a marker taken at start — so it is the run's real output, not a listing of the directory — and each is fetched from GET /v1/exec/download/{session}/{name}.

The tenant is the caller's, never the body's, at every entry point. A typed op is also an MCP tool and an op-plane op; MCP's tools/call invokes it directly, with no route and therefore no middleware, so nothing there could have checked a credential. tenantOf refuses a context carrying no validated principal, so those entry points fail closed without a second gate to keep in step.

Request

11 fields, body application/json (required).

FieldInTypeRequiredDescription
argsbodystring[]—Args become the PROGRAM's argv, never the compiler's.
codebodystringyesCode is the WHOLE program, not a fragment: it is written to a single file and that file is what runs, so a compiled language needs its entry point and an interpreted one runs top to bottom.
filesbodyexec.CodeFile[]—Files are inputs the host already put in some session.
files[].idbodystring—ID is the file's path RELATIVE to its session's artifact directory, which is also how it is fetched: GET /v1/exec/download/{session}/{id}.
files[].namebodystring—Name is the display name.
files[].session_idbodystring—SessionID is the other accepted spelling of the same fact on the way IN.
files[].storage_session_idbodystring—StorageSessionID names the session holding the bytes, and is the spelling the answer always uses.
langbodystringyesLang selects the toolchain, and with it the filename the code is written to and the line that runs it: py, js, ts, bash, r, php, go, rs, c, cpp, java, d, f90.
runtime_session_hintbodystring—RuntimeSessionHint is the stateful-session hint.
session_idbodystring—SessionID continues an EXISTING sandbox, which is what makes runs stateful: the same filesystem, so one run's output file is the next run's input.
user_idbodystring—UserID attributes the run inside the caller's org.

Response

StatusBodyMeaning
200exec.CodeResultok
defaultproblem-detailsrefused

200 body — 8 fields.

FieldInTypeAlwaysDescription
filesbodyexec.CodeFile[]—Files are what this run CREATED OR CHANGED, decided by mtime against a marker taken before the program started — so it is the run's output, not a listing of the directory.
files[].idbodystring—ID is the file's path RELATIVE to its session's artifact directory, which is also how it is fetched: GET /v1/exec/download/{session}/{id}.
files[].namebodystring—Name is the display name.
files[].session_idbodystring—SessionID is the other accepted spelling of the same fact on the way IN.
files[].storage_session_idbodystring—StorageSessionID names the session holding the bytes, and is the spelling the answer always uses.
session_idbodystring—SessionID is the sandbox this run used — the one that was passed in, or the fresh one that was leased.
stderrbodystring—Stderr is what the program wrote to standard error, INCLUDING a compiler's diagnostics and the trace of a program that exited non-zero.
stdoutbodystring—Stdout is what the program wrote to standard output.

Failure carries the platform error shape — see Errors.

Examples

hanzo exec create \
  --code <code> \
  --lang <lang>
import { Configuration, ExecApi } from 'hanzoai';

const api = new ExecApi(new Configuration({ accessToken: process.env.HANZO_API_KEY }));
const { data } = await api.postExec({ lang: "<lang>", code: "<code>" });
from hanzoai.cloud import ApiClient, Configuration
from hanzoai.cloud.api import ExecApi

client = ApiClient(Configuration(access_token=os.environ["HANZO_API_KEY"]))
result = ExecApi(client).post_exec(lang="<lang>", code="<code>")
cfg := hanzoai.NewConfiguration()
cfg.AddDefaultHeader("Authorization", "Bearer "+os.Getenv("HANZO_API_KEY"))
client := hanzoai.NewAPIClient(cfg)

resp, _, err := client.ExecAPI.PostExec(context.Background()).Execute()
if err != nil {
	return err
}
use hanzo_client::apis::{configuration::Configuration, exec_api};

let mut cfg = Configuration::new();
cfg.bearer_access_token = std::env::var("HANZO_API_KEY").ok();

let result = exec_api::post_exec(&cfg, Default::default()).await?;
import ai.hanzo.cloud.ApiClient;
import ai.hanzo.cloud.api.ExecApi;

ApiClient client = new ApiClient();
client.setBearerToken(System.getenv("HANZO_API_KEY"));

var result = new ExecApi(client).postExec();
curl -X POST https://api.hanzo.ai/v1/exec \
  -H "Authorization: Bearer $HANZO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "lang": "<lang>",
       "code": "<code>"
     }'

MCP reaches exec through the exec tool, which names its 2 operations with its own verbs — this one among them, under a name only MCP declares. describe explains any of them:

curl -X POST https://api.hanzo.ai/v1/mcp \
  -H "Content-Type: application/json" \
  -d '{
       "jsonrpc": "2.0",
       "id": 1,
       "method": "tools/call",
       "params": {
         "name": "describe",
         "arguments": {
           "op": "get_exec_file"
         }
       }
     }'

Exec API · All Hanzo APIs · Interactive reference

Was this page useful?