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

# Run commands

> Shell strings, argv form, persistent sessions, and background work — plus the real limits, exactly where they bite.

```python theme={null}
r = sb.run("pytest -q | tail -1")        # shell string: pipes, globs, redirects
r.exit_code; r.stdout; r.stderr          # runs to completion, children included
sb.run("npm run dev", background=True)   # something that OUTLIVES the call
r = sb.exec(["python3", "-c", code])     # argv form: no shell, no injection
with sb.session() as sh:                 # cwd/env persist across calls
    sh.run("cd /work && . .venv/bin/activate")
    sh.run("pip install -q -r requirements.txt")
```

Use `run()` for everyday work, the argv form (`run(["cmd", arg])`) the moment
any part of the command comes from untrusted input, `session()` when state must
carry over, and `background=True` for servers and workers (the idle policy sees
them and keeps the sandbox awake while they live).

## Sessions vs. background

They answer different questions. A **session** keeps *state* between commands:
one shell process stays alive across `.run()` calls, so `cd`, `export`, an
activated venv, and shell functions carry over — exactly like a terminal window
you keep typing into. Filesystem changes persist either way; it is only
process-local state (cwd, environment, shell internals) that dies with each
plain `run()`'s fresh shell. **`background=True`** changes one process's
*lifetime*: the call returns immediately and the process outlives it. They
compose — launch a background job from inside a session and keep working.

## Sharp edges

A synchronous call has \~110 s at the edge — longer work belongs in
`background=True` or a session, collected later. One argv string caps at
128 KiB (kernel limit). stdout/stderr are UTF-8 text capped at 16 MiB per
stream (`ExecResult.truncated` + an inline notice mark a cut) — big or binary
output goes to a file. Background execs return no pid — record one yourself
(`cmd & echo $! > pid`) and redirect output to a file or it is discarded.
