Shell Terminal

AIO Sandbox Shell is PTY-based, so it is best for REPLs, interactive programs, and tasks that need real terminal behavior. It exposes both REST APIs and WebSocket: use REST for a small number of terminal operations, and WebSocket for the built-in terminal or custom WebTerminal UI.

For programmatic command execution, separated stdout/stderr, or offset-based incremental log reads, prefer Bash Pipe.

Shell vs Bash

Shell (/v1/shell)Bash Pipe (/v1/bash)
Interaction modelPTY terminalsubprocess pipe
OutputOne output fieldSeparate stdout / stderr
Read modelwait + view snapshots/output + offset reads
InputTerminal input eventsstdin pipe
Best forWebTerminal, REPLs, interactive programsAgent tool calls, programmatic commands

Common Usage Patterns

One-Off Execution

The simplest pattern is to omit id; the service creates a session and runs the command:

curl -X POST http://localhost:8080/v1/shell/exec \
  -H "Content-Type: application/json" \
  -d '{"command": "printf shell-doc-ok"}'

Typical response:

{
  "success": true,
  "data": {
    "session_id": "SESSION_ID",
    "command": "printf shell-doc-ok",
    "status": "completed",
    "output": "shell-doc-ok",
    "exit_code": 0
  }
}

Use this for simple commands, stateless checks, and one-off scripts.

Reuse A Session

Each execution returns a session_id. Send that value as id in later requests to reuse the same Shell session; the working directory and environment variables are preserved within that session:

SESSION_ID=$(curl -s -X POST http://localhost:8080/v1/shell/exec \
  -H "Content-Type: application/json" \
  -d '{"command": "cd /tmp && export DEMO_FLAG=hello"}' | jq -r ".data.session_id")

curl -X POST http://localhost:8080/v1/shell/exec \
  -H "Content-Type: application/json" \
  -d '{"id": "'"${SESSION_ID}"'", "command": "pwd && echo $DEMO_FLAG"}'

Use this for multi-step builds and workflows that need directory or environment context.

Async Execution

For long-running commands, use async_mode to return immediately, then call wait for status and view for the full session snapshot:

SESSION_ID=$(curl -s -X POST http://localhost:8080/v1/shell/exec \
  -H "Content-Type: application/json" \
  -d '{
    "command": "sleep 3; echo done",
    "async_mode": true
  }' | jq -r ".data.session_id")

curl -X POST http://localhost:8080/v1/shell/wait \
  -H "Content-Type: application/json" \
  -d '{"id": "'"${SESSION_ID}"'", "seconds": 5}'

curl -X POST http://localhost:8080/v1/shell/view \
  -H "Content-Type: application/json" \
  -d '{"id": "'"${SESSION_ID}"'"}'

/v1/shell/wait checks whether the current command is still running. /v1/shell/view returns a terminal snapshot. If you need command-level offset polling, use Bash Pipe.

WebSocket Terminal

Built-in terminal page:

http://localhost:8080/terminal

Custom UIs can connect to the Shell WebSocket:

const ws = new WebSocket("ws://localhost:8080/v1/shell/ws");

Common messages:

ws.send(JSON.stringify({ type: "input", data: "ls -la\n" }));
ws.send(JSON.stringify({ type: "resize", data: { cols: 120, rows: 40 } }));

ws.onmessage = (event) => {
  const message = JSON.parse(event.data);
  if (message.type === "output") {
    terminal.write(message.data);
  }
  if (message.type === "ping") {
    ws.send(JSON.stringify({
      type: "pong",
      data: { timestamp: message.timestamp ?? message.data },
    }));
  }
};

After connection, the server returns a session_id so your UI can identify the active terminal. After connection failures, create a new terminal session instead of relying on reconnects for complete output history.

For REPLs, confirmation prompts, and scripts that ask for input, prefer the WebSocket terminal. See WebTerminal Integration for the full xterm.js integration example.

File System Integration

Shell shares the same filesystem as the File API, Code Server, browser downloads, and code execution:

curl -X POST http://localhost:8080/v1/shell/exec \
  -H "Content-Type: application/json" \
  -d '{"command": "echo \"Hello World\" > /tmp/test.txt"}'

curl -X POST http://localhost:8080/v1/file/read \
  -H "Content-Type: application/json" \
  -d '{"file": "/tmp/test.txt"}'
  • Use Bash Pipe for programmatic command execution with separate stdout and stderr.
  • Use WebTerminal Integration to embed the WebSocket terminal in your own UI.
  • Use AIO CLI when working inside the sandbox container.