Run untrusted code in a hardened, live sandbox.
code-runner is a Piston-style execution service: it isolates code in a locked-down container, streams stdout as it happens, and lets you write to stdin while the process is still running.
Four sandboxes ship today. Each language is a folder the worker discovers at boot.
- python3.12
- rust1.83
- r4.4
- sqlite3
- + add your own
Already running live exams in production
- edalef
Request lifecycle
Every execution takes the same locked path.
- your backendany stack · bearer token
POST /run
- apiHono · validates, enqueues
enqueue
- redisjob queue + stdin bus
BRPOP · claim slot
- workerGo · attaches stdio
create · attach
- sandboxruns untrusted code
- network=none
- ro-rootfs
- cap-drop ALL
- seccomp
output-only
- soketi → browserlive stream, output-only
Everything above the wall is trusted and authenticated. Beyond it, the sandbox runs with no network and a read-only root. Output leaves through soketi, which is output-only toward the client; nothing trusted ever enters that way.
stdin is the only thing that re-enters mid-run, and only back through the trusted worker, never through soketi.
Hardened by default, not by checklist.
Every sandbox starts from a deny-by-default posture. There is no opt-in security to forget; the runner only relaxes what a language image actually needs. Swap the runtime to gVisor with a single env var when you want a second wall.
The hardening modelapplied to every container
- network = none
- read-only rootfs
- cap-drop ALL
- seccomp: deny by default
- no-new-privileges
- mem · cpu · pids cgroups
A real session, not a batch job.
Your backend pushes stdin into the still-running process through one SDK call. Output streams to the browser over soketi the moment a byte is written. The sandbox holds its pipes open for the length of the conversation.
Interactive stdin guideimport { CodeRunnerClient } from '@teovilla/code-runner-sdk-node';
const client = new CodeRunnerClient({ baseUrl, token });
const { jobId, channel } = await client.execute({
language: 'python',
files: [{ name: 'main.py', content: source }],
});
await client.start(jobId); // worker boots the sandbox
// the browser is subscribed to `channel`, already streaming stdout
await client.sendStdin(jobId, 'ada\n'); // written while it runsThree clocks, and any one of them wins.
A session runs under wall time, idle time, and CPU time at once. The first to expire kills the sandbox unconditionally and frees its slot.
Total lifetime from start. The hard ceiling.
Time with no stdout and no stdin written.
Accumulated scheduler time, ignores wall-clock.
Adding a language is adding a folder.
No core changes, no language hardcoded anywhere. Drop a manifest and a pre-built image into languages/; the worker picks it up at boot.
{
"language": "go",
"version": "1.23",
"aliases": ["golang"],
"image": "executor/go:1.23",
"entrypoint": "main.go",
"run": ["go", "run", "main.go"],
"interactive": true
}FROM golang:1.23-alpine
# everything the run command needs,
# nothing it doesn't. read-only at
# runtime; the worker mounts code in.
WORKDIR /sandboxCase study
Thousands of live coding exams, graded as the code runs.
edalef built its online examination platform on code-runner. At Universidad de San Andrés, students sit thousands of programming exams in it. Each one writes and runs code inside its own hardened sandbox, with stdin sent and output streamed live while the process is still running. Every session is bounded by the three clocks and reaped the moment it ends, so no exam ever leaks a container or holds a slot it no longer needs.
- Thousands
- exams administered
- 1 : 1
- hardened sandbox per student
- 0
- containers or slots leaked
running on code-runner
Universidad de San Andrés · Buenos Aires, Argentina
from clone to round-trip
Up and running in four commands.
A plain docker compose up is a true no-op for telemetry; nothing leaves your machine until you point it somewhere.
cp .env.example .env # safe local defaultsmake build-images # build the language sandbox imagesdocker compose up # redis + soketi + api + workermake e2e # interactive "hello, world" round-trip