Browse documentation

REPODESK DOCUMENTATION

Original Markdown from stonega/repodesk. This versioned snapshot includes proposals and research, not just shipped features. See the implementation evidence for current scope and limits.

View source at 521ccc0

Alternative Codex sandboxes and benchmarks

RepoDesk supports deployment-selected docker and opensandbox execution through the same task supervisor. Operators can also choose a runtime in Plugins → Codex → Runtime → Edit. This is a deployment-wide setting, separate from workspace workflow settings. Workspace settings and the application runner HTTP protocol remain the same; the historical payload value backend: "podman" names that local runner protocol, not its selected engine. Podman and microsandbox execution support have been removed; the old wire value remains only for persisted approval/protocol compatibility. The shipped VPS overlay continues to select Docker. This change does not switch or deploy an existing installation.

Admin-panel selection

The saved panel selection takes precedence over CODEX_CONTAINER_ENGINE. Choose Follow environment variable to remove the override. The trusted supervisor stores only the selected engine and revision in its private state volume, in runtime-selection.json (mode 600). A restart loads that choice before tasks. Retain the state volume when redeploying. Host credentials are never returned by the runtime API or copied into task environments.

Selection changes are operator-only, with session, Origin and CSRF enforcement; the supervisor separately requires its management token. Revision checks reject concurrent edits. A changed engine is probed before saving, and a failed probe leaves the current selection unchanged. A lost save response is uncertain: read the current selection before retrying. The management operation never replays tasks.

Switching the effective engine requires every retained task record to be cleaned, including completed work, questions/auth pauses, unknown outcomes and checkpoints. Finishing a task alone may retain its checkout for follow-ups. Wait for configured retention/normal erasure, or use an isolated runner for benchmarks. Changing the configuration source while keeping the same engine does not interrupt tasks. Do not delete live state to force a switch.

The panel selects prepared host profiles; it does not start a sandbox server, mount sockets or import images. Existing environment-only configuration continues to work. Optional per-engine image/socket settings allow one supervisor to prepare multiple backends:

CODEX_CONTAINER_ENGINE=docker
CODEX_DOCKER_IMAGE=localhost/deepx-codex-job:local
CODEX_OPENSANDBOX_IMAGE=localhost/repodesk-codex-opensandbox:local
CODEX_DOCKER_HOST=unix:///var/run/docker.sock

The environment default retains the legacy CODEX_RUNNER_IMAGE/CONTAINER_HOST fallback. The Docker profile uses its configured socket. Selecting OpenSandbox from another default requires its explicit compatible image. Alternate sandbox profiles append the engine name to configured shared storage roots, so the OpenSandbox server's allowed-host-path prefix must include that subdirectory. Both host and supervisor paths must still refer to the same data. Prepare the proxy address for every intended backend before enabling switching. A successful connection probe is not an end-to-end model/publication validation.

Execution contract

Every prepare/setup/implement/check/export/publish phase receives a fresh execution environment. Work storage persists across the first five phases; publication gets separate storage and the verified patch. Inputs are mounted read-only, and export also gets read-only work storage and denied network access. Only implementation receives the temporary model proxy token or a separate writable account credential mount. Only checkout/publication receive their respective GitHub tokens. Setup and checks receive neither credential. Completed sandboxes are destroyed before a subsequent phase starts. No background implementation process can survive into verification. Managed account refresh ordering remains unchanged.

Sandbox IDs and background job IDs persist across supervisor restarts. Environment reservations are encrypted with the runner management key and removed before launch. Uncertain create/command responses never trigger automatic replacement or replay. Cancellation and retention remove sandboxes and task storage; failed cleanup remains retryable. Metadata files are bounded regular files, read without following symlinks.

The first adapters retain the existing phase boundaries and polling. They do not yet implement prewarmed pools, memory snapshots or cross-task dependency caches. Benchmark results describe this implementation, not each upstream runtime's best possible startup time. Live Codex/account and publication validation are separate from the credential-free benchmark.

OpenSandbox

The pinned TypeScript SDK and companion server are 1.1.1. Start a dedicated self-hosted server using a private copy of the example configuration. Create its state directory first, replace the example API key, keep the configuration mode 600 and permit only the dedicated sandbox storage prefix. The server and Docker daemon must see that storage at the configured host path.

Build docker build --target codex-opensandbox-job -t localhost/repodesk-codex-opensandbox:local . for this backend. Its trusted execd starts as root so Linux can switch command identity; every repository command explicitly runs as UID/GID 1000. Using the ordinary USER node image makes execd's UID transition fail with EPERM. The example pins matching release-1.1.1 execd/egress images.

Use dns+nft egress enforcement, the capability restrictions, process limits, loopback endpoint publication and management authentication shown in the example. Keep task networks separate from the application/database network. The Docker runtime does not support secureAccess; its execd ports must remain private. On Kubernetes, set OPENSANDBOX_SECURE_ACCESS=true when using secured endpoints.

CODEX_CONTAINER_ENGINE=opensandbox
CODEX_RUNNER_TOKEN=the-existing-private-runner-management-token
CODEX_RUNNER_IMAGE=localhost/repodesk-codex-opensandbox:local
CODEX_RUNNER_STATE=/var/lib/repodesk-codex-opensandbox
CODEX_SANDBOX_ROOT=/var/lib/repodesk-sandboxes/opensandbox
OPENSANDBOX_URL=http://127.0.0.1:3021
OPENSANDBOX_API_KEY=the-private-server-key
OPENSANDBOX_SECURE_ACCESS=false
CODEX_RUNNER_PROXY_URL=http://runner.example.internal:3020

CODEX_SANDBOX_HOST_ROOT optionally maps the storage root to a different absolute path on the OpenSandbox/Docker host. It must refer to the same files, not another copy. The initial adapter requires shared host storage and a compatible preloaded task image; it does not transfer checkouts between unrelated hosts.

On SELinux hosts, give a fresh dedicated storage root the shared container file label before creating tasks, for example chcon -t container_file_t /var/lib/repodesk-sandboxes. Newly created descendants inherit it. Do the same for a fresh SANDBOX_BENCHMARK_ROOT. An unlabeled home-directory bind mount can return EACCES despite matching UID 1000 permissions. Keep SELinux enabled; do not relabel the workspace, server configuration or unrelated host directories.

Egress denies by default. OPENSANDBOX_ALLOWED_DOMAINS is a comma-separated operator allowlist; defaults cover GitHub, npm, Debian and OpenAI endpoints. The configured model proxy hostname is added. Add the package registries needed by your repositories. Export has no allowed destinations. The management key is used only by the supervisor SDK and is never included in task environment/input. The proxy must have a DNS name resolvable inside the sandbox network; OpenSandbox's domain policy does not support IP-literal destinations.

Browser tasks need a prepared image as well as network access. The landing-page VPS test initially passed lint/types/unit/build but failed downloading Chromium because cdn.playwright.dev was outside the allowlist. Prepare the repository's pinned Playwright browser and native dependencies in a dedicated task image, using playwright install --with-deps chromium and PLAYWRIGHT_BROWSERS_PATH; ensure UID 1000 can use the cache. Keep browser packages out of the ordinary minimal job image unless the deployment needs them. A preinstalled browser avoids repeated downloads and does not require broadening task egress. If a task must download browsers, explicitly allow its required CDN/redirect domains. Both shipped Compose overlays pass through OPENSANDBOX_ALLOWED_DOMAINS and CODEX_RUNNER_PROXY_URL overrides. See Playwright's custom image guidance and the VPS receipt.

For OpenSandbox, build with bun run build, then start with node dist/runner-server.js. Connect the existing application worker to that private authenticated runner endpoint. Use separate state roots when comparing backends: retained tasks reject backend changes rather than operating on the wrong engine. Drain/erase old tasks before a production migration.

Repeatable benchmark

Build the dedicated fixture from the same trusted task image used by all engines:

docker build --target codex-job -t localhost/deepx-codex-job:local .
docker build -f deploy/codex/benchmark.Dockerfile \
  -t localhost/repodesk-sandbox-benchmark:local .

The fixture executes local Git operations, writes 100 source files and a roughly one-MiB change, verifies it, exports the patch and simulates publication in fresh storage. It checks that credential-free phases have no task credentials. It makes no model, GitHub, Telegram or dependency-download calls. The publication URL is explicitly synthetic. No real task/provider/account credentials are used.

Set OpenSandbox's URL/key and configure its allowed storage prefix to include the absolute benchmark root. Its helper images must also be preloaded to measure warm image behavior fairly. Then run:

docker network create repodesk_sandbox_benchmark
SANDBOX_BENCHMARK_ENGINES=docker,opensandbox \
SANDBOX_BENCHMARK_ITERATIONS=10 \
SANDBOX_BENCHMARK_CONCURRENCY=1 \
CODEX_RUNNER_NETWORK=repodesk_sandbox_benchmark \
bun run benchmark:sandboxes

Create the benchmark network once and remove it when finished. With no network setting, the harness defaults OCI phases to none; use the dedicated bridge for comparison with normal network-enabled tasks. Repeat with concurrency 4 to compare throughput. CONTAINER_HOST selects the Docker socket. The fixed runner limits default to 2 CPUs / 4096 MiB. SANDBOX_BENCHMARK_IMAGE, SANDBOX_BENCHMARK_ROOT, SANDBOX_BENCHMARK_OUTPUT, SANDBOX_BENCHMARK_POLL_MS (default 25), and SANDBOX_BENCHMARK_TIMEOUT_MS (default 180000) override the fixture, storage, report path, polling interval and per-task loop deadline. Engine calls retain their own timeouts. Use 5000ms polling to include the production polling cadence.

JSON reports contain host/SDK metadata, individual phase and runtime-operation timings (including startup and file copies/reads), total task times, P50/P95 and failures. Iteration zero is the first measured run, not a guaranteed cold start; later iterations reuse image caches with fresh sandboxes. No host cache eviction or snapshot restore is performed. A failed engine produces an explicit failure and no fabricated timing. All attempts finish before cleanup begins; cleanup is limited to this run's task identities. Failed cleanup preserves its state directory for recovery and causes a nonzero exit. Successful runs erase private task storage and keep the report in node_modules/.cache/sandbox-benchmark/results.json.

Measure live model time, network clones, dependency installation and user follow-up latency separately before selecting a production backend. The fixture benchmark cannot establish those costs or live semantic correctness.

Initial local smoke measurements (2026-10-17)

The same preloaded fixture image ran three times per backend, sequentially, with 2 CPUs / 4096 MiB limits, concurrency 1 and 25ms polling. Docker used a dedicated bridge; OpenSandbox used its Docker runtime with the pinned execd/egress images. The two supported backends below completed all six trials and erased their resources.

BackendTotal P50Total P95
Docker4.24s4.52s
OpenSandbox18.44s18.64s

These are small-sample smoke measurements of six fresh phase environments, not a general ranking of the platforms or a live Codex benchmark. OpenSandbox's measured phase startup/teardown dominates this fixture. Compare pooling/snapshot adapters and production polling separately before drawing an end-to-end speed conclusion. The local raw report is node_modules/.cache/sandbox-benchmark/comparison-final.json.

Upstream references