sandbin

CLI

A third way to talk to sandbin, alongside the browser playground and the raw HTTP API — run code straight from a terminal, with no server required by default.

Install

git clone https://github.com/ayazdoruck/sandbin.git
cd sandbin
npm install
npm link

npm link puts sandbin on PATH. Without it, node bin/sandbin.mjs ... works identically.

Two modes, one command

Local (the default). No server, no port — bin/sandbin.mjs imports sandbox.mjs directly and calls run() itself:

sandbin run script.py

Remote, with --server. Submits over the exact same HTTP + WebSocket protocol the browser frontend speaks against a running instance, local or not:

sandbin run script.py --server localhost:8080

Local is the default on purpose: the more common case for someone who already has the repo checked out is "run this file through the real sandbox right now," which needs nothing running and no port to pick. Local mode needs the same host requirements as npm start itself — see Architecture.

Getting code in

Exactly one source, never ambiguous about which wins:

sandbin run script.py                    # from a file
sandbin run -l python -e 'print(1 + 1)'  # inline
cat script.sh | sandbin run -l bash      # piped stdin

Language is inferred from the file extension (.py, .sh/.bash, .js/.mjs/.cjs, .c, .go) when a file is given. -l/--language overrides it, or supplies it outright for -e or piped input.

Output and exit codes

Stdout and stderr stream live, each to their own real stream, as chunk events arrive — in local mode via run()'s own onChunk, in remote mode via the same WebSocket messages the frontend renders. A summary prints to stderr once it finishes:

$ sandbin run -l python -e 'print("hi")'
hi

verdict      ok
duration     14ms
cpu          6ms
peak memory  3.9 MB
exit code    0

The process exits 0 for verdict ok, 1 otherwise — deliberately not a passthrough of the guest's own exit code. A guest that calls sys.exit(3) still means the CLI itself succeeded at running it and observing that; the verdict (printed alongside duration, CPU and peak memory) is what actually failed. Safe to use directly in shell scripts and CI:

sandbin run deploy-check.py || echo "check failed, see verdict above"
A compile failure needed a second look

run()'s onChunk only ever covers the execute phase — the compile phase (c, go) never gets the callback at all. A compile failure was streaming nothing and then printing a bare verdict compile_error with zero indication of what the compiler actually said. The CLI now prints the result's own captured stderr in full for exactly the two verdicts where the streamed callback wouldn't have shown it (compile_error, setup_failed) — not a change to sandbox.mjs itself, the diagnostic was already there, the CLI just wasn't showing it.

Other commands

CommandDoes
sandbin languageslists what this host can run — reads local IMAGES directly, so go only appears if a toolchain was actually found
sandbin keys createwraps POST /keys against a running server
sandbin keys status <key>wraps GET /keys/:key
sandbin --helpevery flag, including the limit overrides below

Flags

FlagMeaning
-l, --language <lang>override or supply the language
-e, --eval <code>inline code instead of a file
-i, --stdin <file>file whose contents become the guest's stdin (- reads this process's own stdin)
-s, --server <url>submit to a running server instead of running locally (env SANDBIN_SERVER)
-k, --key <key>API key sent as X-Sandbin-Key (env SANDBIN_KEY)
--jsonprint the full result object once, instead of streaming
--memory / --cpu / --timeout / --pidsoverride the matching resource limit

--json skips live streaming entirely and prints the whole result object — verdict, stdout, stderr, durationMs, cpuMs, peakBytes, and the rest — once, for scripting:

sandbin run server.js --json | node -pe "JSON.parse(require('fs').readFileSync(0)).verdict"

Tested as a real subprocess

src/cli-test.mjs spawns the actual bin/sandbin.mjs with node, not by importing its functions — both against run() directly (local) and against a real createServer() on an ephemeral port (remote), asserting on captured stdout/stderr/exit code exactly the way a real caller would observe them. See Testing.