Scripting & Automation¶
contree-cli is designed for scripting. Exit codes propagate, output formats are machine-readable, and shebang mode lets you write executable sandbox scripts.
Shebang scripts¶
Note
Shebang scripts are a CLI-only feature. They are not available in the interactive shell.
Any file with a contree run -I shebang runs inside a sandbox:
#!/usr/bin/env -S contree run -I
echo "Hello from a ConTree sandbox"
uname -a
Save it, chmod +x, and run it directly:
chmod +x hello.sh
./hello.sh
The -I (interpreter) flag reads the script, strips the shebang line, and
sends the body as stdin to /bin/sh -s inside the sandbox.
Combining flags¶
Shebang flags stack. A disposable run with a 10-second timeout:
#!/usr/bin/env -S contree run -I -D -t 10
apt-get update -qq
apt-get install -y curl
curl https://example.com
Since -D is set, the session image is not advanced – the script runs in
a throwaway sandbox.
Passing arguments¶
Extra arguments after the script name are forwarded to the shell:
#!/usr/bin/env -S contree run -I
echo "arg1=$1 arg2=$2"
./script.sh foo bar
# arg1=foo arg2=bar
Note
The -S flag on /usr/bin/env is required because the contree entry point
is a Python script. Without -S, the kernel sees a nested shebang
(script -> script -> binary) and returns ENOEXEC. Using /usr/bin/env -S
(a real binary) splits the argument string and avoids this.
Execution modes¶
Direct command¶
The default mode. Each positional argument becomes a separate argv entry:
contree run uname -a
uname -a
Shell mode¶
-s joins all arguments into a single shell expression:
contree run -s -- 'echo hello && ls /'
echo hello && ls /
Bare commands in the shell always use shell mode.
Useful when you need pipes, redirects, or && chains.
Piped stdin¶
Note
Piped stdin is a CLI-only feature. It is not available in the interactive shell.
When stdin is not a TTY, it is read, base64-encoded, and sent to the sandbox:
echo 'uname -a' | contree run /bin/sh
cat deploy.sh | contree run /bin/sh
Detached mode¶
-d spawns the operation and exits immediately, printing the operation UUID:
contree run -d -- long-running-task
Check on it later:
contree show UUID
contree run -d -- long-running-task
contree show UUID
Flags like -d require the explicit contree run prefix.
Exit codes¶
Note
Exit code propagation is a CLI-only feature useful for scripting. The interactive shell does not expose sandbox exit codes.
The sandbox exit code propagates to the CLI process:
contree run -- /bin/sh -c 'exit 42'
echo $? # 42
This means contree run works naturally in if, &&, ||, and set -e
scripts:
set -e
contree run -- make test # script aborts if tests fail
contree run -- make install
If the operation fails at the platform level (timeout, cancelled), the CLI exits with code 1.
Environment variables¶
Pass environment variables into the sandbox with -e:
contree run -e DEBUG=1 -e DB_HOST=postgres -- ./app
contree run -e DEBUG=1 -e DB_HOST=postgres -- ./app
Flags like -e require the explicit contree run prefix.
The flag is repeatable. Format is KEY=VALUE.
Output truncation¶
By default, stdout/stderr is capped at 64 KiB in the API response. Override
with -T:
contree run -T 1048576 -- ./generate-big-output.sh
contree run -T 1048576 -- ./generate-big-output.sh
Monitor operations¶
List running and recent operations:
contree ps # active operations only
contree ps -a # all (including completed)
contree ps -q # UUIDs only, one per line
contree ps
contree ps -a
contree ps -q
Show the full result of a specific operation:
contree show UUID
contree show UUID
Cancel an operation:
contree kill UUID
contree kill --all
contree kill UUID
contree kill --all
Scripting patterns¶
Note
Shell piping and command substitution are CLI-only features. These patterns are not available in the interactive shell.
Combine -q with other tools:
# Show results of all active operations
contree ps -q | xargs -I {} contree show {}
# Kill all running operations
contree ps -q | xargs -I {} contree kill {}
# Launch detached, capture UUID
OP=$(contree run -d -- sleep 3600)
# ... do other work ...
contree show "$OP"
Output formats¶
Note
The --format flag is global and set at CLI launch time. In the interactive
shell, the format is fixed for the entire session and cannot be changed
mid-session.
Use -f / --format to control output. The flag is global and goes
before the subcommand:
default
: Table-like output optimized for human reading. Some commands (like
run) use a custom default that prints only stdout/stderr.
table
: Aligned columns with headers. Identical to default for most commands.
csv
: Comma-separated values with a header row. Useful for spreadsheet import
or cut/awk processing.
tsv
: Tab-separated values with a header row. Works well with column -t.
json
: One JSON object per line (JSONL/NDJSON). Each output row is a separate
JSON object. Suitable for jq processing.
json-pretty
: All rows collected into a single pretty-printed JSON array. Output is
flushed at the end.
Examples¶
# Pipe JSON to jq
contree -f json ps | jq '.uuid'
# CSV for scripting
contree -f csv images --tagged > images.csv
# Tab-separated for column alignment
contree -f tsv ps | column -t
# Get image UUID from tag
contree -f json images --prefix=ubuntu | jq -r '.uuid'
Streaming behavior¶
json and json-pretty formatters support streaming output from
commands like run and show – stdout/stderr are included in the
JSON payload.
csv, tsv, and table formatters do not include stdout/stderr
from sandbox execution. Use default or json formats to see
sandbox output.
Session management in scripts¶
Note
Script-level session management with eval and CONTREE_SESSION is a
CLI-only pattern. The interactive shell manages sessions automatically.
The eval $(contree use ...) pattern exports the session key into your
shell. In scripts, set CONTREE_SESSION explicitly to control which
session you operate on:
#!/bin/bash
export CONTREE_SESSION=ci-build-$$
contree use tag:ubuntu:latest
contree run apt-get update -qq
contree run apt-get install -y build-essential
contree run --file ./src:/src make -C /src test
Using $$ (PID) or a fixed name gives you a predictable, isolated session
per script run.
You now know the full CLI. Next: Configuration & Profiles.