Command Execution

View as Markdown

Chaser provides multiple ways to run commands in sandbox sessions, from simple one-shot execution to long-running background processes with streaming output.

Auto-spawn exec

POST /v1/exec is the simplest way to run a command. It provisions a sandbox automatically (or reuses an existing one for workspace-backed requests) and returns the output.

$# Run on a persistent workspace
$curl -sS "$CHASER_API_URL/v1/exec" \
> -H "Authorization: Bearer $CHASER_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{"workspace": "my-project", "command": "npm test"}' | jq
$
$# Run on an ephemeral sandbox
$curl -sS "$CHASER_API_URL/v1/exec" \
> -H "Authorization: Bearer $CHASER_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{"ephemeral": true, "command": "python3 -c \"print(42)\""}' | jq
$
$# Run with a custom image
$curl -sS "$CHASER_API_URL/v1/exec" \
> -H "Authorization: Bearer $CHASER_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{"ephemeral": true, "image": "node:20-bookworm", "command": "node -v"}' | jq

Response fields (foreground): exit_code, output, output_truncated

In-session exec

POST /v1/sessions/{id}/exec runs a command in an already-running sandbox. Use this when you want to reuse an existing session.

$curl -sS "$CHASER_API_URL/v1/sessions/$SESSION_ID/exec" \
> -H "Authorization: Bearer $CHASER_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{
> "command": "ls -la /workspace",
> "cwd": "/workspace",
> "env": {"NODE_ENV": "production"}
> }' | jq

Optional fields: cwd (working directory), env (environment variables), timeout_ms, background.

Background commands

Set background=true to start long-running processes without blocking the HTTP response. You get back a command_id and pid to manage the process.

$# Start a background process
$curl -sS "$CHASER_API_URL/v1/sessions/$SESSION_ID/exec" \
> -H "Authorization: Bearer $CHASER_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{"command": "npm run dev", "cwd": "/workspace", "background": true}' | jq

Manage background commands

EndpointDescription
GET /v1/sessions/{id}/commandsList all commands in the session
GET /v1/sessions/{id}/commands/{command_id}Get status and output of a specific command
GET /v1/sessions/{id}/commands/{command_id}/streamStream output via Server-Sent Events
POST /v1/sessions/{id}/commands/{command_id}/stdinSend input to the process
POST /v1/sessions/{id}/commands/{command_id}/killSend a signal to the process

Stream output

$curl -N "$CHASER_API_URL/v1/sessions/$SESSION_ID/commands/$COMMAND_ID/stream?from=0&interval_ms=500" \
> -H "Authorization: Bearer $CHASER_API_KEY"

Send input and signals

$# Send stdin
$curl -sS "$CHASER_API_URL/v1/sessions/$SESSION_ID/commands/$COMMAND_ID/stdin" \
> -H "Authorization: Bearer $CHASER_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{"input": "q\n"}' | jq
$
$# Send SIGTERM
$curl -sS "$CHASER_API_URL/v1/sessions/$SESSION_ID/commands/$COMMAND_ID/kill" \
> -H "Authorization: Bearer $CHASER_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{"signal": "TERM"}' | jq

CLI one-shot

$chaser shell <session_id> -c "python3 -c 'print(42)'"

PTY WebSocket

For interactive terminal access, upgrade to a WebSocket:

GET /v1/sessions/{id}/pty?mode=human

Mode options: human (full interactive shell), agent (agent-optimized PTY), exec (non-interactive exec transport).

MCP terminal tool

The terminal MCP tool wraps sandbox execution with session auto-provisioning:

$curl -sS "$CHASER_API_URL/v1/mcp" \
> -H "Authorization: Bearer $CHASER_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{
> "jsonrpc": "2.0", "id": 1,
> "method": "tools/call",
> "params": {
> "name": "terminal",
> "arguments": {"workspace": "my-project", "command": "npm test"}
> }
> }' | jq

Jobs

For queued, retriable command execution, use the jobs API with sandbox.exec or pipeline.run:

$chaser jobs exec --workspace my-project "npm ci && npm test" --wait --json

See Jobs for scheduling, pipelines, and other job kinds.