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

# Run commands and handle results

> Choose command or shell execution, make persistence explicit, and interpret operation and process results.

Each request to `POST /v1/instances` starts a new operation from an image. The operation result describes the primary process. A retained result image, when requested and produced, represents filesystem state after the operation; it does not preserve processes, memory, or connections.

Complete [access setup](/sandboxes/start/set-up-access). The runnable example uses the Python SDK to submit a command, wait for completion, and decode its output. The REST response fields are explained below for applications that call the API directly.

## Choose direct or shell execution

Use `command` with `args` when the executable accepts ordinary arguments. This avoids shell expansion and is the safer choice for dynamic values. For pipes, redirects, variable expansion, or compound statements, pass the command string as `shell="..."` in the SDK. In a REST request, put that string in `command` and set `shell: true`.

The execution environment also depends on that choice. A shell receives the environment stored in the image. For direct execution, pass every required variable in `env` according to the [spawn reference](/api-reference/sandboxes/instances/spawn-a-new-container-instance). Use the REST `preserve_env` flag only when environment values should be written to result-image metadata for later operations. Do not concatenate untrusted values into shell source.

## Choose whether to retain filesystem changes

Set `disposable` explicitly. Python uses `False` and `True`; the REST JSON values are shown below:

| Goal | Value | Result |
| - | - | - |
| Keep changed files as a continuation point | `false` | A successful operation can return `result_image_uuid`. Record that immutable UUID before starting later work. |
| Use only the process result | `true` | No result image is created. Files written by the operation cannot be used as a later branch source. |

The SDK exposes a saved result image through the returned object's `uuid`; REST uses `result_image_uuid`. The input image remains unchanged. A result image is distinct from the operation UUID. Confirm that `result_image_uuid` is present before using it; an unchanged filesystem or an unsuccessful operation may not produce a new image.

## Run a command with Python

Use Python 3.12 and the SDK installation from the [Python quickstart](/sandboxes/start/python-quickstart). Export `NEBIUS_API_KEY`, `NEBIUS_PROJECT_ID`, and an immutable `IMAGE_UUID` from the [image-discovery step](/sandboxes/start/set-up-access#find-an-image-uuid).

Save this as `run_command.py`, then run `uv run python run_command.py`:

```python theme={null}
import asyncio
import os

from contree_sdk import Contree


async def main():
    client = Contree()
    image = await client.images.use(os.environ["IMAGE_UUID"], strict=True)
    result = await image.run(
        shell='printf "ready\\n"; printf "diagnostic\\n" >&2',
        disposable=True,
        timeout=30,
        truncate_output_at=1048576,
    )

    print(f"stdout: {result.stdout}", end="")
    print(f"stderr: {result.stderr}", end="")
    if result.result.truncated:
        raise RuntimeError("Output was truncated; increase the output limit")
    if result.exit_code != 0:
        raise RuntimeError(f"Command failed with exit code {result.exit_code}")
    print(f"Result: process_exit={result.exit_code}")


asyncio.run(main())
```

Expected output:

```text theme={null}
stdout: ready
stderr: diagnostic
Result: process_exit=0
```

Awaiting the run submits it and waits for an operation result. The SDK decodes stdout and stderr into strings. The command has a 30-second execution limit, and `disposable=True` discards its filesystem changes. To invoke an executable directly, replace `shell=...` with `command="/bin/echo", args=["ready"]`.

A returned process result still needs checking: nonzero exit codes indicate command failure, and truncated output may be incomplete. SDK exceptions can indicate request, transport, or operation failures. Do not interpret them as a normal process result.

<Note>
  SDK 0.3.6 attempts best-effort cancellation when its wait ends without observing a terminal result. Resolve an interrupted operation's outcome before repeating the command. A REST polling timeout or event-stream disconnect does not itself cancel execution. See [Execution lifecycle](/sandboxes/concepts/execution-lifecycle).
</Note>

## Start, observe, and finish

Applications that call the API directly follow three stages:

1. Submit the command to [POST /v1/instances](/api-reference/sandboxes/instances/spawn-a-new-container-instance). A `201` response means the operation was accepted; keep its UUID immediately.
2. Poll [GET /v1/operations/\{operationId}](/api-reference/sandboxes/operations/get-an-operation-status) until its status is `SUCCESS`, `FAILED`, or `CANCELLED`. The process result can be null while work is pending.
3. Inspect the terminal response's process state and output. Operation `SUCCESS` means the service finished the work; the process exit code tells you whether the command passed.

### See the requests

For direct execution, the POST request body can be as small as:

```json theme={null}
{
  "image": "YOUR_IMMUTABLE_IMAGE_UUID",
  "command": "/bin/echo",
  "args": ["ready"],
  "shell": false,
  "disposable": true,
  "timeout": 30
}
```

Send the access headers described in [Set up access](/sandboxes/start/set-up-access). The response's `uuid` is the operation ID for subsequent status requests; it is distinct from the input or result image UUID.

### Run with bounded polling

Give each status request a timeout and the polling loop a total deadline. Honor `Retry-After` when provided. If the deadline expires, keep the operation ID and inspect or cancel that operation before resubmitting. A transport failure during POST can leave submission uncertain; do not automatically send the POST again.

The [networking recipe](/sandboxes/cookbook/verify-with-networking-disabled) includes a complete Python HTTP example with bounded polling and operation IDs. For exact request and response schemas, use the separate API reference.

After a terminal response, check both layers:

1. `status` and `error` describe the operation.
2. `metadata.result.state` describes the primary process, including `exit_code`, `signal`, and `timed_out` when available.
3. `metadata.result.stdout` and `metadata.result.stderr` contain the recorded process output and indicate its encoding and whether it was truncated.
4. `result_image_uuid` identifies retained filesystem state when one was produced.

A `SUCCESS` operation can contain a nonzero process exit code. Treat that command as failed. A closed event stream or a completed HTTP request is also insufficient; inspect the terminal response.

| Outcome | Action |
| - | - |
| `SUCCESS`, exit code `0`, no signal or timeout | Consume the result. Use `result_image_uuid` only when it is present. |
| `SUCCESS`, nonzero exit code | Inspect stdout and stderr, correct the command or input, then start a new operation. |
| Process signal or `timed_out: true` | Treat the process as interrupted and decide whether the operation is safe to repeat. |
| `FAILED` | Read `error` and any available process result. Correct platform, capacity, or request problems before retrying. |
| `CANCELLED` | Confirm cleanup and do not assume a result image exists. |

Use `?inflight=1` only when partial stdout or stderr is needed; it performs additional work on an executing instance. See [Get operation status](/api-reference/sandboxes/operations/get-an-operation-status), [Cancel an operation](/api-reference/sandboxes/operations/cancel-an-operation), and the [timeout and disconnection guidance](/sandboxes/operate/troubleshooting#timeouts-and-disconnections).

To display output as the process runs, continue with [Stream output and events](/sandboxes/guides/stream-output-and-events). To add a process to an operation that is already active, use [Run subprocesses and send input](/sandboxes/guides/run-subprocesses-and-send-input).
