---
id: 06-runner-provisioner-port
epic: walking-skeleton
title: IRunnerProvisioner port + local-process and single-host Docker implementations
type: technical-story
status: todo
feature: workspaces
depends-on: [03-workspaces-feature-core, 04-runner-app-protocol-clone-install]
blocks: [07-runner-lifecycle-events-and-realtime]
created: 2026-07-12T10:24:14Z
---

## Goal

Ship the runner provisioning port — `IRunnerProvisioner` (`provision(workspaceId) → RunnerHandle`, `terminate`, `status`) in `workspaces` infrastructure — with two implementations: a local child-process provisioner (dev/CI) and a single-host Docker provisioner (the container-per-workspace baseline of ADR-027 §2).

## Why

Each workspace's repo code must execute in its own isolated runner so a malicious repo cannot touch other tenants (PRD user story 6, ADR-027). Putting provisioning behind a port keeps fleet orchestration explicitly a later concern behind the same interface, and lets `pnpm dev` + CI run the whole skeleton with a plain child process (PRD user story 8).

## Done when

- `IRunnerProvisioner` service port lives in `workspaces` infrastructure with `provision(workspaceId) → RunnerHandle`, `terminate`, `status` (PRD Implementation decisions).
- Local child-process implementation spawns the real `apps/runner`; tests provision, complete the protocol handshake, and terminate cleanly.
- Docker implementation: docker CLI via execa (PRD Q1 — app/infra-tier placement, so no ADR-022 trace required); image `node:22-bookworm-slim` + git at a pinned digest (PRD Q3); container-per-workspace with no cross-tenant network (PRD security floor).
- The Docker path has a documented manual dev-machine check; CI uses the process provisioner (PRD Success criteria).
- `pnpm typecheck && pnpm lint && pnpm test && pnpm conformance && pnpm fallow:audit && pnpm coverage:diff` all pass after each task.

## In scope

- The port + `RunnerHandle` shape.
- Local child-process implementation + tests against the real runner.
- Single-host Docker implementation (docker CLI via execa) + tests against a stubbed docker CLI + documented manual verification steps.

## Out of scope

- Fleet orchestration, hibernation, egress policy hardening, resource-limit tuning (`workspaces-and-connections`).
- Quotas, metering, billing.
- Doctor-style runner image version checks (`workspaces-and-connections`, PRD Q3).

## Tasks

- [ ] Add the `IRunnerProvisioner` service port in `workspaces` infrastructure (`provision(workspaceId) → RunnerHandle`, `terminate`, `status`) + the local child-process implementation spawning `apps/runner`; tests provision a real runner, complete the protocol handshake, and terminate cleanly.
- [ ] Add the single-host Docker implementation (docker CLI via execa, app/infra-tier per PRD Q1; `node:22-bookworm-slim` + git at a pinned digest; container-per-workspace, no cross-tenant network) with unit tests against a stubbed docker CLI + documented manual dev-machine verification (CI stays on the process provisioner).
