# Tasks — WASI-stdio ABI variant for the WASM host bridge ## 0. Pre-flight (non-negotiable) - [x] 0.1 Clean working tree; account for every `.claude/worktrees/agent-*` (active, work-pending-merge, stale-and-prune) - [x] 0.2 `MANIFEST.md` package count matches `find packages -maxdepth 3 -name package.json` - [x] 0.3 §0a Sync: worktree-isolated agents fast-forward to orchestrator-supplied SHA before any work ## 1. Shared protocol contract in `@suaveplan/api-types/sandbox-bridge` - [x] 1.1 Add `wasi-stdio-protocol.types.ts` exporting `PluginEnvelopeIn` and `PluginEnvelopeOut` discriminated unions + `WASI_STDIO_PROTOCOL_VERSION: 1` constant - [x] 1.2 Paired `.md` documenting wire format ([u32 BE length][JSON]) + frame ordering invariants - [x] 1.3 Paired `.test.ts` proving the types-only invariant (byte-size guard already enforces) - [x] 1.4 Re-export from `packages/api-stack/api/api-types/src/sandbox-bridge/index.ts` + root `src/index.ts` - [x] 1.5 `bunx --bun turbo lint typecheck test:coverage --filter=@suaveplan/api-types` green ## 2. Bridge runtime — WASI-stdio variant - [x] 2.1 `src/wasi-stdio/wasi-stdio-frame.ts` — Zod-validated length-prefix encoder/decoder - [x] 2.2 `src/wasi-stdio/wasi-stdio-runner.ts` — drives the sandbox via fd 0 / fd 1; surfaces stderr to logger - [x] 2.3 `src/wasi-stdio/wasi-stdio-routes.ts` — issues `{kind:"routes"}` at bridge-init, captures the response into the BridgedPlugin - [x] 2.4 `src/abi-wasi-stdio/wasi-stdio-validate.ts` — variant-specific ABI validator (memory + `_start` + WASI imports allowlist) - [x] 2.5 `src/abi-direct/` (existing direct-i32-i64 path) — moved existing `src/wasm-abi/` + `src/memory/` + `src/marshal/` modules under this folder so the variant split is structural, not parameterised - [x] 2.6 `src/bridge/bridge.ts` — `switch (abiVariant)` dispatch; default remains `"direct-i32-i64"` - [x] 2.7 New error codes appended: `SAND_WASM_BRIDGE.FRAME_OVERSIZE`, `SAND_WASM_BRIDGE.PROTOCOL_MISMATCH`, `SAND_WASM_BRIDGE.STDIO_TIMEOUT` (10 codes total) - [x] 2.8 Lifecycle (start/dispose) routes through stdio envelopes when `abiVariant === "wasi-stdio"` - [x] 2.9 Trap classification preserved across both variants - [x] 2.10 OTel instruments labelled with `abi_variant` attribute on every counter and histogram ## 3. Conformance harness - [x] 3.1 `runWasmHostBridgeConformance({ buildBridge, abiVariant })` gains the new parameter; both variants run all five invariants - [x] 3.2 New WASI-stdio fixture WASM under `tests/fixtures/wasi-stdio/build-wasm.ts` — hand-encoded, no `wabt` - [x] 3.3 Fixture exercises route-discovery, request round-trip, lifecycle, trap (`unreachable` mid-frame), capability-gate ## 4. Integration test - [x] 4.1 `tests/integration/wasi-stdio-flow.test.ts` — full round-trip + assertBridgeThrowsOnTrap for both variants - [x] 4.2 `tests/integration/full-flow.test.ts` (existing direct variant) — left untouched; proves the split didn't regress - [x] 4.3 100% istanbul coverage on every touched module - [x] 4.4 No `// biome-ignore`; every test file imports from `@suaveplan/testing/runner`; public-constructor preserved ## 5. Gate - [x] 5.1 `bunx --bun turbo lint typecheck test:coverage --filter=@suaveplan/api-types --filter=@suaveplan/api-sandbox-wasm --filter=@suaveplan/api-sandbox-wasm-host-bridge --filter=@suaveplan/api-sandbox-vm-host-bridge --concurrency=4` green (vm-bridge included to prove the api-types additive change doesn't regress it) ## 6. Archive (orchestrator step) - [ ] 6.1 Fold delta into `openspec/specs/api-sandbox-wasm-host-bridge/spec.md` (creating the spec if it doesn't exist yet — the original wasm host-bridge proposal still awaits its first archive) - [ ] 6.2 Fold delta into `openspec/specs/api-types/spec.md` for the additive protocol types - [ ] 6.3 Move folder → `openspec/archive/2026-05-27-api-sandbox-wasm-stdio-abi/` - [ ] 6.4 Refresh `MANIFEST.md`