Run commands in a sandbox

Preview

Run a command and wait for its result, stream its output, or start a background command and poll it.

A sandbox runs commands in two ways. Pick the one that matches how long the work takes.

ends whenread its output
POST /sandboxes/{sandbox_id}/execthe request endsin the answer, or as a stream
POST /sandboxes/{sandbox_id}/commandsit exits, its timeout ends, you signal it, or its sandbox stopspoll the command

Wait for the result

exec runs one command and answers its exit code and its output. It is the right call for a build step, a test run or a script that ends in seconds or minutes.

curl -sS --fail-with-body "https://api.munito.ai/sandboxes/v1/sandboxes/$SANDBOX/exec" \
  -H "Authorization: Bearer $MUNITO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"command": "pytest -q", "timeout": 600}'
  • A string runs in bash -lc. A list is the argument vector itself.
  • "stream": true answers NDJSON events as the command writes, instead of one result at its end.
  • A command runs for at most 1,800 seconds.
  • The command ends with its request. A client that leaves kills the command.

Start a background command

A background command answers at once with an id, and keeps running. Use it for a dev server, a watcher, a long training step, or any work that outlives one HTTP request.

CMD=$(curl -sS --fail-with-body "https://api.munito.ai/sandboxes/v1/sandboxes/$SANDBOX/commands" \
  -H "Authorization: Bearer $MUNITO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"command": "npm run dev"}' | jq -r .id)

Then read it, poll it, and stop it:

# Its status and its whole output so far.
curl -sS --fail-with-body "https://api.munito.ai/sandboxes/v1/sandboxes/$SANDBOX/commands/$CMD" \
  -H "Authorization: Bearer $MUNITO_API_KEY"

# Only what the command wrote after the first 4,096 bytes of each stream.
curl -sS --fail-with-body \
  "https://api.munito.ai/sandboxes/v1/sandboxes/$SANDBOX/commands/$CMD?stdout=4096&stderr=4096" \
  -H "Authorization: Bearer $MUNITO_API_KEY"

# Ask it to stop with SIGTERM, or send 9 for SIGKILL.
curl -sS --fail-with-body "https://api.munito.ai/sandboxes/v1/sandboxes/$SANDBOX/commands/$CMD/signal" \
  -H "Authorization: Bearer $MUNITO_API_KEY" \
  -H "Content-Type: application/json" -d '{"signal": 15}'
  • GET /sandboxes/{sandbox_id}/commands lists them, the newest first, with no output.
  • status is running, then exited with an exit_code, or failed when the sandbox lost the command.
  • A command that a signal stopped has the exit_code 128 plus the signal.
  • A DELETE kills a command that runs and drops what the sandbox keeps of it.

Read the output as it grows

Each answer carries stdout_bytes and stderr_bytes: the bytes of each stream so far. Pass them back as stdout and stderr, and the next answer holds only what follows. A poll loop then reads each byte once.

What a sandbox holds

  • A sandbox runs 16 background commands at once. Start one more and it answers too_many_commands.
  • The sandbox keeps 1 MiB of each stream. A command that writes more sets truncated, and the rest is left out. Write the output to a file for more, and read the file.
  • The commands live with their sandbox. A pause, a stop and a restart of the sandbox all end them, and the sandbox then holds no record of them.
  • A background command runs for at most 24 hours, and the timeout of its sandbox still ends it first.