v0.3.1 (2026-06-25)
v0.3.1 is an architecture-consolidation release. Where
v0.3.0 re-architected server-side execution into a
per-run-Job pipeline (backend run queue → dispatcher → driver), it left the
CLI and the Tauri desktop
app running test cases locally, through an
in-process core runner backed by a host Docker/Podman. v0.3.1 removes that local
execution path entirely: the CLI and the desktop app are now thin enqueue +
watch clients of the backend run queue, exactly like the web
console, so there is now a single way a run executes
everywhere. The only remaining runner is the
driver.
This is still pre-1.0 software intended primarily for project developers. v0.3.1 trades launching a run on your own machine with nothing but a container runtime for a simpler, uniform topology: one execution path, one set of manifests, no second runner to maintain.
Breaking changes
Section titled “Breaking changes”The CLI and desktop app no longer execute runs locally
Section titled “The CLI and desktop app no longer execute runs locally”tcab and the Tauri app used to drive a run through the
core on the host, against a local Docker/Podman.
That path is gone. Both now POST the run to the backend’s /jobs queue, a
dispatcher claims it and creates a per-run
Kubernetes Job running the driver, and the
launcher watches the run over GET /jobs/{id}/live. The practical consequences:
- Neither needs a container runtime anymore. What they need instead is a
reachable backend (
TCAB_BACKEND_URL) and a logged-in account. For local development this means the k3d service stack must be up.tcab runand the desktop app target it just as the web console does (see Running and thedeployments/local/Makefileflow). tcab runis now enqueue + watch. It prints the queued job id, streams the live event stream until the run finishes, and reads the produced run record back to print its summary.--auth-modewas added;--out-diris now optional, because the backend holds the artifacts and passing it only writes the fetched record JSON locally.- Removed flags and variables.
--work-dir/TCAB_WORK_DIRand--orchestrator-dirare gone fromtcab run; there is no host staging directory to point at and no local orchestrator-dir override (the run executes in the cluster). The CLI/desktop runner-side overrides (TCAB_CONTAINER_RUNTIME,TCAB_WORK_DIR, and the publishing release credentials) no longer apply to these clients. pushis a read-back confirmation. A backend-driven run’s record and artifacts are released by the driver during the run, so by the time an operator sees a produced run it is already stored.tcab push <run-id>…reads each run back by run id and reports whether the backend holds it and where its source and playable build resolve.reviewandpublishlikewise operate by backend run id. (This mirrors the web console, whosepushis a near no-op.)
The local-only commands are unchanged: seed, prompt, validate, catalog,
harnesses, orchestrators, and the account commands login / register /
logout.
Removed desktop URI schemes
Section titled “Removed desktop URI schemes”The Tauri app’s local execution commands and its tcab-proof://,
tcab-asset://, and playable-build URI schemes were removed. A run’s loadable
media, meaning proof artifacts and an
asset-generation run’s images and action
log, now loads over HTTP from the artifact
service, exactly as in the browser (the
backend reports its public URL via GET /config). The desktop CSP was opened to
reach the backend, auth, and artifact origins.
Features
Section titled “Features”Unified HTTP transport for both consoles
Section titled “Unified HTTP transport for both consoles”The desktop UI now uses the same HTTP transport as the web console, promoted out
of apps/web into the UI library and exported as
@clockwyrks/ui/transport. The two consoles are now the same console over the
same BackendClient, differing only in delivery (a desktop binary vs. a browser
bundle).
A shared Rust job-queue client
Section titled “A shared Rust job-queue client”A shared job-queue client (launch_run / job_status / list_active_jobs /
watch_job / subscribe_notifications) and its wire types were added to the
core, so the CLI and any other Rust client enqueue and watch runs through one
contract.
Retained
Section titled “Retained”The desktop’s local adversarial arena
Section titled “The desktop’s local adversarial arena”The one thing the desktop app still runs locally, in-process, is the
adversarial arena, because quick matches and
tournaments are CPU-bound wasm the desktop plays itself. Its
tcab-tournament:// scheme, which serves a tournament’s host-produced replay
media, is kept. Everything else the desktop does is enqueue + watch + report
over HTTP. See Arena.
Playable builds now load in the console iframe
Section titled “Playable builds now load in the console iframe”The standalone artifact service was missing
the trailing-slash /runs/{id}/build/ route, the exact URL the driver emits as
a run’s playable-build link (it doubles as the build’s <base href>) and the
one the console loads into its iframe. The worker served it, but the standalone
service had only carried over /runs/{id}/build and /runs/{id}/build/{*path},
and axum’s {*path} capture rejects an empty path, so the build 404’d despite
uploading fine. The route now maps to the build root.
Completed adversarial runs now appear in the arena
Section titled “Completed adversarial runs now appear in the arena”A backend-driven adversarial run’s controller
wasm is mirrored into the backend store at finalize so the run is pittable in
the arena (Quick Match / tournaments) without
being published. That upload was silently failing. The backend’s run-media
upload routes inherited Axum’s default 2 MiB request-body limit, but a
full-length proof replay serializes to tens of MiB (a time-limit Pac-Man match
is ~20 MiB), so the canonical replay’s POST was rejected with 413. Because
the controller was uploaded after the replays, that rejection aborted the upload
before the controller ever reached the store. The run completed and produced its
replays, but never showed up alongside the baselines in the arena.
The run-media and tournament-replay upload routes now accept a generous body size, and the controller wasm is uploaded ahead of the replays in both the driver and the CLI push, so a run’s arena visibility no longer depends on its (much larger) replays uploading first. Runs produced before this fix need to be re-run to mirror their controller into the store.