-
Notifications
You must be signed in to change notification settings - Fork 0
Execution Backends
How CW lifts execution out of the kernel into a pluggable driver layer —
node, bun, shell, container, remote, ci, agent — without the kernel ever
learning which driver ran a task.
The design mantra for this layer:
One narrow interface.
Many interchangeable drivers.
The kernel never knows which one ran.
Same evidence, any backend.
Fail closed, never downgrade.
CW models execution exactly like a BSD VFS / device-driver layer. There is ONE
narrow ExecutionBackend interface (the mechanism) and many interchangeable
drivers (the policy of how and where). The kernel — orchestrator, dispatch,
pipeline-runner — issues the same call regardless of driver, the same way a
filesystem issues read()/write() without knowing if the device is a disk,
an SSD, or a network share.
selected backend -> sandbox attestation -> execution/delegation -> canonical envelope
- Kernel (mechanism, policy of intent): WHAT to run, and WHICH evidence to record.
- Driver (policy of execution): HOW and WHERE it runs.
The kernel must contain no backend-specific branching. WHAT/WHERE is pushed to the edge, behind a three-member interface:
descriptor which sandbox dimensions it enforces vs attests; local/remote; readiness
probe(ctx) live, deterministic readiness check
run(request) execute or delegate under a sandbox profile; return a canonical envelope
Every driver MUST account for all five sandbox dimensions — read, write,
command, network, env — declaring each as enforce, attest, or
unsupported. This is the same enforce/attest split CW already used between
itself and the host; backends just make it explicit and per-driver.
A driver may not pretend. What it cannot enforce, it must honestly attest
(a verifiable claim the host/runner upholds) or mark unsupported.
The result envelope, evidence refs, and provenance are schema-identical no matter which driver ran the task. The backend id and its sandbox attestation are recorded as provenance, not in the result.
This is the load-bearing invariant: because evidence is backend-independent,
eval/replay, the verifier gates, and the v0.1.28 run registry stay completely
agnostic to who executed a run. Running CW's own self-verify through node,
shell, and bun yields byte-identical result and evidence; only
provenance.backendId differs.
command:<command + args>
exitCode:<code>
stdoutSha256:sha256:<hex>
If a required sandbox dimension is unsupported, the backend is not ready, the
command is denied by the profile, or a delegating driver has no target, then
run returns status: "refused" with attestation.status: "refused".
CW never silently runs a task unsandboxed when the requested profile cannot be honored, and never substitutes a different backend behind your back. Ambiguity is a refusal, not a guess.
Consistent with CW's standing model (CW records evidence; the host runs
workers), the container/remote/ci drivers delegate and record a
handle + attestation + result. CW drives docker/podman, a remote runner, or a
CI job through a thin adapter and captures verifiable evidence — it never
reimplements a container runtime or a CI system.
The node driver is the default and reproduces pre-v0.1.29 behavior exactly.
bun is a driver, not a kernel runtime: it executes via the Node-compatible
runtime so evidence stays byte-stable, and attests Bun availability in
provenance.
This keeps the standing distribution stance intact:
Node-compatible by default.
Bun-friendly where useful.
Bun-only only if the ecosystem standard changes.
Bun lives at the execution edge as an optional, fail-closed driver — never as a dependency of the kernel that every agent host would have to satisfy.
Selection parallels --sandbox:
--backend <id> (flag) > CW_BACKEND (env) > node (default)
backend list|show|probe and the --backend flag are declared once in
src/capability-registry.ts, so the CLI and MCP render one data source and pass
the v0.1.27 CLI ↔ MCP parity gate automatically. Selection is recorded in run
state and surfaced in the v0.1.28 registry's backends field.
The backend fields are additive and optional. Old run state loads unchanged,
runs with no backend selected behave exactly as before, and the ResultEnvelope
schema (summary, findings, evidence) is untouched — backend id and
attestation live in provenance and run state, never in the result.
v0.1.29 was developed in dev-mode bootstrap (claude --plugin-dir): the
live local plugin built its own next version, and the acceptance bar was
self-referential — CW had to run its own build/verify across more than one
backend with byte-identical evidence before the feature was considered done.
- Architecture Principles
- Runtime Contract
- CLI and MCP Surface
- Distribution Strategy
- Repo doc:
plugins/cool-workflow/docs/execution-backends.7.md
Organized from local Obsidian notes and reconciled with the current
coo1white/cool-workflow repository state.
Start here
Go deeper
- Workflow Apps
- Architecture
- Trust And Audit
- Recovery And Restore
- Commands or API
- MCP And Manifests
- Operations
- FAQ
Source docs