> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tensorlake.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Execute Commands

> Run commands with output capture, streaming, and error handling

Run shell commands inside sandboxes with full stdout/stderr capture, real-time streaming, and configurable timeouts.

<Note>
  Sandbox-specific operations use the sandbox proxy URL: `https://<sandbox-id-or-name>.sandbox.tensorlake.ai`

  For named sandboxes, you can use the sandbox **name** in place of the ID — both in the proxy hostname and in CLI/API commands. For example, `https://my-env.sandbox.tensorlake.ai/api/v1/processes` and `tl sbx exec my-env python main.py` work the same as their ID-based equivalents. The proxy resolves the name to the underlying sandbox automatically.

  The command and process APIs documented here run on the management URL on port `9501`, which always requires authentication. Unauthenticated proxy access applies only to exposed user ports.
</Note>

## Basic Execution

<Tabs>
  <Tab title="CLI">
    ```bash theme={null}
    # Run in an existing sandbox — use the sandbox ID or name
    tl sbx exec my-env python -c 'print("Hello from sandbox!")'

    # Or create, run, and tear down in one step
    tl sbx run python -c 'print("Hello from sandbox!")'
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    from tensorlake.sandbox import Sandbox


    sandbox = Sandbox.create()
        result = sandbox.run("python", ["-c", "print('Hello from sandbox!')"])
        print(result.stdout)     # Hello from sandbox!
        print(result.exit_code)  # 0
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    const result = await sandbox.run("python", {
      args: ["-c", "print('Hello from sandbox!')"],
    });

    console.log(result.stdout);   // Hello from sandbox!
    console.log(result.exitCode); // 0
    ```
  </Tab>

  <Tab title="HTTP">
    ```bash theme={null}
    # Start a Python process inside the sandbox
    curl -X POST https://<sandbox-id>.sandbox.tensorlake.ai/api/v1/processes \
      -H "Authorization: Bearer $TL_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "command": "python",
        "args": ["-c", "print(\"Hello from sandbox!\")"]
      }'
    ```

    **Response:**

    ```json theme={null}
    {
      "pid": 294,
      "status": "running",
      "exit_code": null,
      "signal": null,
      "stdin_writable": false,
      "command": "python",
      "args": ["-c", "print(\"Hello from sandbox!\")"],
      "started_at": 1773950042728,
      "ended_at": null
    }
    ```
  </Tab>
</Tabs>

## CLI Options

<Tabs>
  <Tab title="CLI">
    ```bash theme={null}
    # Timeout is in seconds
    tl sbx exec <sandbox-id> --timeout 10 python -c 'print("hi")'

    # Run from a specific working directory
    tl sbx exec <sandbox-id> --workdir /workspace python main.py

    # Inject environment variables into a single command
    tl sbx exec <sandbox-id> --env MODE=prod --env DEBUG=0 /bin/sh -lc 'printf "%s %s\n" "$MODE" "$DEBUG"'

    # Keep the sandbox after a one-shot run so you can inspect it afterwards
    tl sbx run --keep /bin/sh -lc 'echo KEEP_TEST && sleep 1'
    ```

    A verified `--env` run printed `prod 0`. A verified `--keep` run ended with `Sandbox <id> kept alive.`, and `tl sbx ls --all` then showed that sandbox as `running`.
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    # Run with a timeout, working directory, and per-command environment
    result = sandbox.run(
        "python",
        ["main.py"],
        env={"MODE": "prod", "DEBUG": "0"},
        working_dir="/workspace",
        timeout=10,
    )
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    const result = await sandbox.run("python", {
      args: ["main.py"],
      env: { MODE: "prod", DEBUG: "0" },
      workingDir: "/workspace",
      timeout: 10,
    });

    console.log(result.exitCode);
    ```
  </Tab>

  <Tab title="HTTP">
    ```bash theme={null}
    # Start a process with custom environment variables and working directory
    curl -X POST https://<sandbox-id>.sandbox.tensorlake.ai/api/v1/processes \
      -H "Authorization: Bearer $TL_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "command": "python",
        "args": ["main.py"],
        "env": {"MODE": "prod", "DEBUG": "0"},
        "working_dir": "/workspace"
      }'
    ```
  </Tab>
</Tabs>

## Shell Commands

<Tabs>
  <Tab title="CLI">
    ```bash theme={null}
    # Count Python files in /workspace with a pipe
    tl sbx exec <sandbox-id> bash -c "ls -la /workspace | grep '.py' | wc -l"

    # Redirect stdout and stderr to files
    tl sbx exec <sandbox-id> bash -c "python script.py > output.txt 2> errors.txt"

    # Chain setup and execution in one shell command
    tl sbx exec <sandbox-id> bash -c "cd /workspace && pip install -r requirements.txt && python main.py"
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    sandbox = Sandbox.create()
        # Pipes
        result = sandbox.run("bash", ["-c", "ls -la /workspace | grep '.py' | wc -l"])
        print(result.stdout)

        # Redirects
        sandbox.run("bash", ["-c", "python script.py > output.txt 2> errors.txt"])

        # Command chaining
        sandbox.run("bash", ["-c", "cd /workspace && pip install -r requirements.txt && python main.py"])
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    const count = await sandbox.run("bash", {
      args: ["-lc", "ls -la /workspace | grep '.py' | wc -l"],
    });
    console.log(count.stdout);

    await sandbox.run("bash", {
      args: ["-lc", "python script.py > output.txt 2> errors.txt"],
    });

    await sandbox.run("bash", {
      args: [
        "-lc",
        "cd /workspace && pip install -r requirements.txt && python main.py",
      ],
    });
    ```
  </Tab>

  <Tab title="HTTP">
    ```bash theme={null}
    # Use bash when you need pipes, redirects, or command chaining
    curl -X POST https://<sandbox-id>.sandbox.tensorlake.ai/api/v1/processes \
      -H "Authorization: Bearer $TL_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "command": "bash",
        "args": ["-c", "ls -la /workspace | grep .py | wc -l"]
      }'
    ```
  </Tab>
</Tabs>

## Get Process Output

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    sandbox = Sandbox.create()
        result = sandbox.run("python", ["-c", "print('hello')"])
        print(result.stdout)
        print(result.stderr)
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    import { ProcessStatus } from "tensorlake";

    const proc = await sandbox.startProcess("python", {
      args: [
        "-c",
        "import sys; print('hello'); print('oops', file=sys.stderr)",
      ],
    });

    let info = await sandbox.getProcess(proc.pid);
    while (info.status === ProcessStatus.RUNNING) {
      await new Promise((resolve) => setTimeout(resolve, 100));
      info = await sandbox.getProcess(proc.pid);
    }

    console.log((await sandbox.getStdout(proc.pid)).lines);
    console.log((await sandbox.getStderr(proc.pid)).lines);
    console.log((await sandbox.getOutput(proc.pid)).lines);
    ```
  </Tab>

  <Tab title="HTTP">
    ```bash theme={null}
    # Get stdout
    curl https://<sandbox-id>.sandbox.tensorlake.ai/api/v1/processes/<pid>/stdout \
      -H "Authorization: Bearer $TL_API_KEY"

    # Get stderr
    curl https://<sandbox-id>.sandbox.tensorlake.ai/api/v1/processes/<pid>/stderr \
      -H "Authorization: Bearer $TL_API_KEY"

    # Get combined output
    curl https://<sandbox-id>.sandbox.tensorlake.ai/api/v1/processes/<pid>/output \
      -H "Authorization: Bearer $TL_API_KEY"
    ```

    **Combined output response:**

    ```json theme={null}
    {
      "pid": 297,
      "lines": ["hello", "oops"],
      "line_count": 2
    }
    ```
  </Tab>

  <Tab title="CLI">
    Not supported in the CLI.
  </Tab>
</Tabs>

## Interactive Shell

<Tabs>
  <Tab title="CLI">
    ```bash theme={null}
    # Open an interactive shell in the sandbox
    tl sbx ssh <sandbox-id>

    # Use a custom shell
    tl sbx ssh <sandbox-id> --shell /bin/sh
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    sandbox = Sandbox.create()
        pty = sandbox.create_pty(
            command="/bin/bash",
            rows=24,
            cols=80,
        )

        pty.send_input("pwd\nexit\n")
        print(pty.wait())
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    const pty = await sandbox.createPty({
      command: "/bin/bash",
      rows: 24,
      cols: 80,
    });

    await pty.sendInput("pwd\nexit\n");
    console.log(await pty.wait());
    ```
  </Tab>

  <Tab title="HTTP">
    ```bash theme={null}
    # 1. Create a PTY session
    curl -X POST https://<sandbox-id>.sandbox.tensorlake.ai/api/v1/pty \
      -H "Authorization: Bearer $TL_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{"command": "/bin/bash", "rows": 24, "cols": 80}'
    ```

    **Response:**

    ```json theme={null}
    {
      "session_id": "LYtJOrxE9Kz3bphPUDzuX",
      "token": "<pty-session-token>"
    }
    ```

    ```bash theme={null}
    # 2. Connect via WebSocket
    wscat -c "wss://<sandbox-id>.sandbox.tensorlake.ai/api/v1/pty/<session-id>/ws?token=<token>"
    ```
  </Tab>
</Tabs>

`tl sbx ssh` requires an interactive terminal and automatically resumes a suspended sandbox before opening the PTY session.

For the full programmatic PTY flow, including the `READY` handshake, binary WebSocket opcodes, and clean shutdown, see [PTY Sessions](/sandboxes/pty-sessions).

## Error Handling

<Tabs>
  <Tab title="CLI">
    ```bash theme={null}
    # The CLI prints stderr and returns a non-zero exit code on failure
    tl sbx exec <sandbox-id> python -c "import nonexistent_module"
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    sandbox = Sandbox.create()
        result = sandbox.run("python", ["-c", "import nonexistent_module"])

        if result.exit_code != 0:
            print(f"Command failed with exit code {result.exit_code}")
            print(f"stderr: {result.stderr}")
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    const result = await sandbox.run("python", {
      args: ["-c", "import nonexistent_module"],
    });

    if (result.exitCode !== 0) {
      console.log(`Command failed with exit code ${result.exitCode}`);
      console.log(`stderr: ${result.stderr}`);
    }
    ```
  </Tab>

  <Tab title="HTTP">
    ```bash theme={null}
    # Check the exited process status
    curl https://<sandbox-id>.sandbox.tensorlake.ai/api/v1/processes/<pid> \
      -H "Authorization: Bearer $TL_API_KEY"
    ```

    **Process status response:**

    ```json theme={null}
    {
      "pid": 305,
      "status": "exited",
      "exit_code": 1,
      "signal": null,
      "stdin_writable": false,
      "command": "python",
      "args": ["-c", "import nonexistent_module"],
      "started_at": 1773950228855,
      "ended_at": 1773950228866
    }
    ```

    **stderr response:**

    ```json theme={null}
    {
      "pid": 305,
      "lines": [
        "Traceback (most recent call last):",
        "  File \"<string>\", line 1, in <module>",
        "ModuleNotFoundError: No module named 'nonexistent_module'"
      ],
      "line_count": 3
    }
    ```
  </Tab>
</Tabs>

## Streaming Output

Stream stdout/stderr in real time for long-running commands using Server-Sent Events:

<Tabs>
  <Tab title="CLI">
    `tl sbx exec` streams combined output to your terminal while the process runs.
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    sandbox = Sandbox.create()
        # Start a long-running process
        proc = sandbox.start_process("python", ["-c", """
    import time
    for i in range(5):
        print(f"Step {i+1}/5")
        time.sleep(1)
    """])

        # Stream output as it arrives
        for event in sandbox.follow_output(proc.pid):
            print(event.line, end="")
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    const proc = await sandbox.startProcess("python", {
      args: [
        "-c",
        "import time\nfor i in range(5):\n print(f'Step {i+1}/5')\n time.sleep(1)",
      ],
    });

    for await (const event of sandbox.followOutput(proc.pid)) {
      process.stdout.write(event.line);
    }
    ```
  </Tab>

  <Tab title="HTTP">
    ```bash theme={null}
    # Follow stdout via SSE
    curl -N https://<sandbox-id>.sandbox.tensorlake.ai/api/v1/processes/<pid>/stdout/follow \
      -H "Authorization: Bearer $TL_API_KEY"

    # Follow combined output via SSE
    curl -N https://<sandbox-id>.sandbox.tensorlake.ai/api/v1/processes/<pid>/output/follow \
      -H "Authorization: Bearer $TL_API_KEY"
    ```

    **SSE stream:**

    ```
    event: output
    data: {"line":"Step 1/2","timestamp":1773950220162,"stream":"stdout"}

    event: output
    data: {"line":"Step 2/2","timestamp":1773950220162,"stream":"stdout"}

    event: eof
    data: {}
    ```
  </Tab>
</Tabs>

## Learn More

<CardGroup cols={3}>
  <Card title="Processes" icon="gears" href="/sandboxes/processes">
    Manage background processes.
  </Card>

  <Card title="File Operations" icon="folder-open" href="/sandboxes/file-operations">
    Read, write, and copy files.
  </Card>

  <Card title="Lifecycle" icon="arrows-spin" href="/sandboxes/lifecycle">
    Sandbox states, resources, and timeouts.
  </Card>
</CardGroup>
