page:docs-specs-platform-gaps-10-t3code-migration
Spec 10 — t3code migration (WP-T3-*) reference
Date: 2026-09-27 · Status: Gate-B draft · Binding decisions: D1, D2, D5, D6, D9, D10, D13, D15 and amendment D17–D21 (docs/specs/platform-gaps/00-intent.md:19-46).
Spec 10 — t3code migration (WP-T3-*)
Date: 2026-09-27 · Status: Gate-B draft · Binding decisions: **D1, D2, D5, D6, D9, D10, D13, D15** and amendment **D17–D21** (docs/specs/platform-gaps/00-intent.md:19-46).
Inputs consumed in full: the Gate-A-approved adoption proposal research/synthesis-adoption-proposal.md (per-component decisions §1, boundary rules B1–B6 §2.1, per-package stance table §2.2, the planned 33-WP inventory §4.1); dossiers R1 research/fabric-current-state.md, R2 research/t3code-architecture.md, R3 research/packaging-state.md, R4 research/delta-map.md; and spec 15 15-private-isolation-rename.md, whose **§3.3 name matrix is this spec's naming source of truth** (D21, WP-RN-08). Citations: fabric: paths relative to C:/work/fabric at HEAD 5e46b998e; t3: paths relative to the MIT t3code snapshot at C:/Users/tmusk/AppData/Local/Temp/claude/C--work-company/368e0399-fd11-4960-8b4d-b4dcf1d79c43/scratchpad/t3code.
**ID convention.** Work packages here are WP-T3-01 … WP-T3-33. The short form T-<n> used by the Gate-A proposal and by specs 15/20/30/40/50 refers to the same packages one-to-one (T-02 ≡ WP-T3-02, etc.). The count matches the proposal's planned 33 (synthesis-adoption-proposal.md §4.1); no WPs were added or removed — the two adjustments made against the proposal are internal to existing WPs and justified in §3.2 (oh-my-pi/omp aliasing resolved: one harness, not two) and §3.4 (the codec disposition table covers 22 codec files as measured at HEAD, including four files the dossiers did not characterize: babysitter, adapters-remote, claude-remote-control, pi-sdk, plus the qwen codec).
---
1. Scope, invariants, non-goals
In scope (D2, all four surfaces): (a) the adapters harness-driving layer re-platformed onto ACP-canonical lanes (D6); (b) kradle control-surface interfaces aligned to the t3code contracts/environment model; (c) genty client shells retired in favor of adapted t3code server/web/desktop apps + client-runtime; (d) the remote-access stack (ssh/tailscale/hosted relay).
Binding invariants:
1. **Public repo untouched (D17).** No WP in this spec reads from, writes to, renames, or republishes anything in public a5c-ai/babysitter. All work lands fabric-only. Upstream intake of t3code snapshots is governed by WP-T3-01; upstream intake of public-babysitter fixes is spec 15 §1.4 and out of scope here. 2. **No double rename (D21, spec 15 interaction rule 1).** Every migrated unit lands directly under its 15-private-isolation-rename.md §3.3 name, scope @fabricstack, directory, and bin — never under a @t3code/*, t3-*, or @a5c-ai/* name, even transiently. The WP-RN-08 CI gate enforces this mechanically and blocks WP-T3-01. 3. **Registry (D19).** Every new package's publishConfig.registry is the GCP Artifact Registry npm URL (spec 15 §4.1); guards G1–G6 (spec 15 §4.3) apply from the first landed commit. 4. **Later rename phases do not block migration (spec 15 interaction rule 3).** WPs below reference existing fabric code by its **current** paths/names (packages/adapters/..., .a5c/, KRADLE_*); RN-2/RN-3 sweeps rename migrated units together with the rest of the tree. New units use §3.3 names from birth. 5. **Mobile deferred (D13).** t3:apps/mobile is not adapted. Nothing below forecloses it: the adopted stack (contracts + client-runtime) is exactly what mobile consumes upstream (R2 §11), and 19 of t3code's 23 pnpm patches are mobile-only friction this program never imports (R2 §11). 6. **Break freely (D10).** No compatibility shims anywhere. Every in-repo consumer of a broken API is migrated inside the same WP or an explicitly-dependent WP (§7 inventory). The major version bump lands with RN-1/P-01 in one train (spec 15 §5 interaction rule 6). 7. **No implementation in this run (D4).** This document specifies; implementation is later babysitter runs executing the WPs.
Non-goals: public-facing branding (D14); functionality-coverage debt (spec 20 — e.g. journal checksum verification C1/F-01 is *referenced* by the journal-sovereignty rule but *fixed* by F-01); testing floors (spec 30); packaging forms (spec 40, though §2 rows note where a unit's landing is owned there).
---
2. Per-unit adoption matrix (D1/D5/D9/D15/D21)
This table is the intent's acceptance-criterion-4 artifact: per migrated unit — adoption model, Effect stance, fork posture, license/attribution, target location under the new private name.
| # | Unit (t3code origin) | Adoption model (D1) | Effect stance (D5, §2.1 rule) | Fork posture (D9) | License/attribution (D15) | Lands as (spec 15 §3.3) | WP |
|---|---|---|---|---|---|---|---|
| 1 | t3:packages/contracts (74 modules, 26,979 LOC, 98% Effect — R2 §5) | Extract-packages; extended with fabric RPC groups | **Adopt** — Effect Schema is the wire language, surfaces only at the wire boundary (B3) | **Tracked fork** (protocol-churny; capability-flag doctrine tracks upstream — R2 §18.5) | MIT notice + upstream pin; row in third-party-licenses.config.json | @fabricstack/contracts · packages/contracts | WP-T3-02 |
| 2 | t3:packages/effect-acp (15,546 LOC, 10,375 generated — R2 §6) | Extract-packages | **Adopt** (100% Effect, B2) | **Tracked fork** + schema regeneration pipeline | same | @fabricstack/acp · packages/acp | WP-T3-03 |
| 3 | t3:packages/effect-codex-app-server (61,816 LOC, 58,004 generated — R2 §7) | Extract-packages | **Adopt** (100%, B2) | **Tracked fork** + regeneration pipeline | same | @fabricstack/codex-protocol · packages/codex-protocol | WP-T3-04 |
| 4 | t3:packages/ssh (4,143 LOC — R2 §10) | Extract-packages, near-verbatim | **Adopt** (100%, B2); plain-TS facade at call sites (B1) | **Tracked fork** | same | @fabricstack/ssh · packages/ssh | WP-T3-28 |
| 5 | t3:packages/tailscale (763 LOC — R2 §10) | Extract-packages, near-verbatim | **Adopt** (B2); plain-TS facade (B1) | **Tracked fork** | same | @fabricstack/tailscale · packages/tailscale | WP-T3-29 |
| 6 | t3:apps/server subset: orchestration/ persistence/ auth/ checkpointing/ terminal/ provider/ cloud/ vcs/ git/ sourceControl/ project/ usage/ textGeneration/ mcp/ resourceTelemetry/ (R2 §3) | Vendor-adapt as the **environment server** under kradle's plane | **Adopt internally** (88% Effect; de-Effecting 398.6k LOC infeasible — R2 §2); plain-TS seams to journal/trust-core (B1/B4) | **Hard fork** (org boundary, journal sovereignty, approval mapping, trust gates are permanent divergence — R4 §B.4/§B.6) | same; per-file provenance headers kept | @fabricstack/environment · apps/environment · bin environment-server | WP-T3-19 (auth: WP-T3-30; provider lanes: WP-T3-06…13; cloud: WP-T3-31) |
| 7 | t3:packages/client-runtime (256 files, 65,846 LOC, 54% Effect — R2 §8) | Vendor-adapt | **Quarantine** — Effect in atom/data layer; platform/ interfaces + hook API surface plain (B1/B6) | **Hard fork** (kradle-sourced catalog, 7-action approval UX diverge immediately — R4 §C.6) | same | @fabricstack/client-runtime · packages/client-runtime | WP-T3-24 |
| 8 | t3:apps/web (1,258 files, 318,401 LOC, 17% Effect — R2 §11) | Vendor-wholesale, adapted | **Quarantine** (components plain React, B6) | **Hard fork** (D9 names apps) | same | @fabricstack/console-web (private) · apps/console-web | WP-T3-25 |
| 9 | t3:apps/desktop (258 files, 81,239 LOC, 66% Effect — R2 §11) | Vendor-wholesale, adapted | **Quarantine** (Effect concentrated in backend manager, B2/B6) | **Hard fork** | same | @fabricstack/console-desktop (private) · apps/console-desktop | WP-T3-26 |
| 10 | t3:infra/relay (78 files, 27,381 LOC, 91% Effect — R2 §12) | Vendor-adapt with two mandatory substitutions (Clerk→kradle org identity; noble-PKI→trust-core envelopes) | **Adopt** (B2) | **Hard fork** (substitutions are structural) | same | @fabricstack/relay (private) · infra/relay | WP-T3-31 |
| 11 | t3:packages/shared selected modules: nodeSqliteClient, DrainableWorker, relaySigning/relayClient, cliRelease (R2 §9) | **Cherry-pick** individual subpath modules | Per module (B2 where Effect) | Hard fork of individual modules | same (module-level provenance headers) | **No new package minted** — modules land inside their adopters: apps/environment/src/shared/, infra/relay/src/shared/, packages/client-runtime/src/shared/ (keeps spec 15 §3 closed under its own matrix) | WP-T3-19/24/31 |
| 12 | Install/service/self-update machinery (t3:scripts/install.sh, serviceLauncher.ts, cloud/selfUpdate.ts — R2 §14) | Vendor-adapt | Adopt where Effect-based | Hard fork | same | Landing owned by **spec 40** (P-03…P-08); this spec only lands cloud/selfUpdate.ts as part of unit 6 and hands the rest over | (spec 40) |
| 13 | Provider maintenance: installers/updaters with ownership proofs, usage/quota ingestion, model-manifest.json (t3:apps/server/src/provider/providerMaintenance.ts, usage/ — R2 §4) | Vendor-adapt inside the harness layer | Adopt inside lanes (B2) | Hard fork (rides unit 6's tree) | same | inside packages/harness/* lane implementations and apps/environment | WP-T3-33 |
| 14 | Fabric-native successor surfaces (adapter contract + projection) | Implement-contracts (fabric-authored) | **Plain TS** (B1/B4) | n/a — fabric-native | n/a | current packages/adapters/core (renamed to packages/harness/core by RN-3, spec 15 §3.1 row 10) | WP-T3-05, WP-T3-14 |
Excluded from adoption, permanently or for this program: t3:apps/mobile (D13); t3:apps/marketing; t3:apps/server/src/{pullRequest,device,preview,desktopUpdate} and t3:native/{browser-secret,hyprland-snap-shot,kde-snap-shot} (pruned at WP-T3-19 landing; recoverable later from the WP-T3-01 import snapshot without re-import); t3:.repos/* vendored references (never imported upstream either — R2 §2); Clerk and every Clerk-dependent path (substituted per row 10); oxlint-plugin-t3code, vite-plus, TS7/tsgo toolchain (re-platformed instead — WP-T3-32). native/libghostty-vt + native/resource-monitor ride WP-T3-25/WP-T3-19 respectively as vendored assets (see those WPs).
2.1 Effect boundary rules (D5) — binding, restated from the approved proposal
The Gate-A rules synthesis-adoption-proposal.md §2.1 apply verbatim to every WP below:
- **B1** — the fabric-facing adapter contract exposes Promise/AsyncIterable only, as
RunHandledoes today (fabric:packages/adapters/core/src/run-handle.ts:150). No Effect type crosses it. - **B2** — Effect is unrestricted inside lane implementations and adopted/forked packages.
- **B3** — Effect Schema surfaces only at the wire boundary (the contracts fork); kradle controllers and web routes consume decoded plain objects.
- **B4** — fabric core (babysitter-sdk, trust-core, kip-sdk, atlas, kradle-core, observer-dashboard) adopts no Effect in this program.
- **B5** — one pinned Effect (
effect@4.0.0-rc.115+ the single local patch,t3:patches/effect@4.0.0-rc.115.patch— R2 §2), centrally owned by WP-T3-32; no per-package Effect versions. - **B6** — UI components stay plain React; Effect lives in the atom/data layer (proven viable at 17–21% penetration — R2 §15).
Every WP whose acceptance criteria mention a "boundary check" means: a CI lint/architecture rule (extending the existing architecture boundary gate, fabric:.github/workflows/ci.yml:114-117) asserting no import ... from "effect" (or effect/*) in the files the rule names as plain-TS.
2.2 Fork-posture mechanics
- **Tracked fork** (units 1–5): WP-T3-01 lands each with an
UPSTREAM.jsonat the package root recording {upstream repo URL, snapshot commit SHA, snapshot date, local-divergence log}. Divergence is allowed but every divergent hunk is listed. A quarterly upstream-diff review item (recorded per package inUPSTREAM.json) re-pulls the upstream package, regenerates schemas (units 2–3), and cherry-picks protocol updates. Tracked forks build with plaintscand haveeffectas their only runtime dep (R2 §18.2, §18.12) — no toolchain import. - **Hard fork** (units 6–13): one-time import, attribution preserved, **no** upstream tracking obligation; upstream divergence is expected and undocumented beyond the initial
UPSTREAM.jsonpin. - **Cherry-pick** (unit 11): module files copied with a provenance header (
// Adapted from t3code <path> @ <sha>, MIT © 2026 T3 Tools Inc.); no package-level tracking.
2.3 License and attribution (D15)
t3code is MIT, © 2026 T3 Tools Inc. (t3:LICENSE; intent D15). Binding attribution work, distributed across WPs and centralized in WP-T3-01:
1. Every landed unit carries the upstream MIT license text in a LICENSE-THIRD-PARTY (tracked forks) or an entry in the repo-level third-party notice file (hard forks/cherry-picks). 2. Fabric adopts t3code's own attribution machinery: t3:third-party-licenses.config.json + t3:scripts/sync-third-party-license-notices.ts (R2 §14), landed by WP-T3-01 and extended by spec 40's P-12 to cover all adopted units; the config gains one entry per §2 row. 3. Generated files (units 2–3) keep their generator provenance banners so regeneration does not orphan attribution. 4. No copyright headers are stripped; adapted files get the §2.2 provenance header **added**, never substituted.
---
3. The ACP-canonical adapters re-platforming (D6)
3.1 Contract: one `ProviderAdapter`-equivalent, plain TS, five lanes
D6 makes ACP fabric's canonical harness protocol and demotes the current adapters event model to an internal projection. The concrete shape, fixed by evidence (R4 §A.6, R2 §18.1):
1. **ACP lane** (WP-T3-06): generic runtime + per-harness extension modules, adapted from t3:apps/server/src/provider/acp/{AcpSessionRuntime,AcpAdapterSupport,AcpCoreRuntimeEvents,AcpRuntimeModel,AcpStderr}.ts with extensions in the CursorAcpExtension/XAiAcpExtension pattern (R2 §4), speaking ACP through @fabricstack/acp's client side. 2. **Claude SDK lane** (WP-T3-10): @anthropic-ai/claude-agent-sdk in-process (t3:apps/server/src/provider/Layers/ClaudeAdapter.ts:5-27), history/fork in a child worker (t3:apps/server/src/claudeHistoryWorker.ts:1-11). 3. **Codex app-server lane** (WP-T3-11): codex app-server JSON-RPC stdio (t3:apps/server/src/provider/Layers/codexLaunchArgs.ts:13), typed by @fabricstack/codex-protocol. 4. **OpenCode HTTP lane** (WP-T3-12): server-per-thread via @opencode-ai/sdk/v2 (t3:apps/server/src/provider/Layers/OpenCodeAdapter.ts:32; rationale t3:docs/internals/providers.md:14-22). 5. **Retained-subprocess lane** (WP-T3-13, fabric-only): the surviving codec adapters for harnesses t3code does not cover, migrated behind the new contract.
- **The contract** (WP-T3-05) succeeds
BaseAgentAdapterInterface(fabric:packages/adapters/core/src/adapter-types.ts:24, kinds at:79,:93,:168) andRunHandle(fabric:packages/adapters/core/src/run-handle.ts:150), modeled ont3:apps/server/src/provider/Services/ProviderAdapter.ts:29-56: typed capability declarations (sessionModelSwitch,promptlessTurnContinuation,supportsConversationRollback—ProviderAdapter.ts:46-56), compaction semantics (nativevsslash-command,:36-44), turn dispatch, drive-side permission callbacks, auth detection, session-file parsing (fabric is broader here and keeps its surface — R4 §A.3). It is **plain TS** (B1): Promise/AsyncIterable, no Effect exports. Deferred-prompt steering (run-handle.ts:44-51) is preserved as a contract capability. - **Five lanes** behind that one contract:
- Plus the **observe lane** (WP-T3-15): the 12 hook adapters (
fabric:packages/adapters/hooks/adapter-{antigravity,claude,codex,copilot,cursor,gemini,genty,hermes,oh-my-pi,openclaw,opencode,pi}— R1 §3.1) survive unchanged in role, re-bound to feed the same projection. t3code has no observe mode (R4 §A.3); this is a fabric-only plane and is **not** retired by anything below.
3.2 Lane decision for all 16 harness rows (15 distinct harnesses + 1 codec-only addition)
The Gate-A table is adopted with the aliasing question **resolved from code**: the oh-my-pi hook adapter and the omp codec/live-stack id are the **same harness** — the hook adapter's own tests key sessions on OMP_SESSION_ID and omp- prefixes (fabric:packages/adapters/hooks/adapter-oh-my-pi/src/__tests__/session-resolver.test.ts:8,28,40,134), the codec registers factory id omp (fabric:packages/adapters/codecs/src/omp-adapter.ts:248-249), and the live-stack agent map carries a single omp entry (fabric:.github/workflows/live-stack.yml:169). Rows 10–11 therefore collapse to one harness (15 distinct); the WP-T3-13 disposition table records the resolution.
| # | Harness | Today in fabric | Lane (binding) | Evidence |
|---|---|---|---|---|
| 1 | Claude Code | codec claude-agent-sdk-adapter.ts + claude-adapter.ts + hook adapter; live-stack GREEN (R1 §4.3) | **Claude SDK lane** | t3:apps/server/src/provider/Layers/ClaudeAdapter.ts:5-27 |
| 2 | Codex | codecs codex-adapter.ts/codex-sdk-adapter.ts/codex-websocket-adapter.ts + hook adapter; GREEN | **Codex app-server lane** | t3:apps/server/src/provider/Layers/codexLaunchArgs.ts:13; R2 §7 |
| 3 | Cursor | codec cursor-adapter.ts + hook adapter; lane failing (#562, R1 §4.3) | **ACP lane** | cursor-agent … acp (t3:apps/server/src/provider/acp/CursorAcpSupport.ts:56-60) |
| 4 | Grok Build | **nothing** (no adapter, no lane — R1 §3.1) | **ACP lane — net-new build** (mandatory for D7(a)) | grok --permission-mode <m> agent stdio (t3:apps/server/src/provider/acp/GrokAcpSupport.ts:33-41) |
| 5 | OpenCode | codecs opencode-adapter.ts/opencode-http-adapter.ts + hook adapter; lane skipped/failing | **OpenCode HTTP lane** | t3:docs/internals/providers.md:14-22 |
| 6 | Antigravity | hook adapter; lane failing (#945) | **ACP lane + managed installer** | identity check agentInfo.name === "antigravity-acp", protocolVersion 1 (t3:apps/server/src/provider/AntigravityInstallation.ts:484-502); revert-rejection rule (R2 §3.4) |
| 7 | Gemini CLI | codec + hook adapter | **Retained-subprocess** (re-evaluate for ACP promotion post-migration; no ACP evidence in dossiers) | R1 §3.1 |
| 8 | Copilot CLI | codec + hook adapter | **Retained-subprocess** | R1 §3.1 |
| 9 | Pi | codecs pi-adapter.ts + pi-sdk-adapter.ts (programmatic) + hook adapter; live-stack push default | **Retained-subprocess** (both codecs) | R1 §4.3 |
| 10–11 | Oh-My-Pi ≡ OMP (one harness, resolved above) | hook adapter adapter-oh-my-pi + codec omp-adapter.ts + live-stack id omp | **Retained-subprocess** | session-resolver.test.ts:8,40; omp-adapter.ts:248-249; live-stack.yml:169 |
| 12 | OpenClaw | codec + hook adapter | **Retained-subprocess** | R4 §A.3 (no t3code counterpart) |
| 13 | Hermes | codec + hook adapter | **Retained-subprocess** | R1 §3.1 |
| 14 | Droid | codec + live-stack lane, no hook adapter | **Retained-subprocess** | R1 §4.3 vs §3.1 |
| 15 | Amp | codec + live-stack lane, no hook adapter | **Retained-subprocess** | R1 §4.3 |
| 16 | Genty (fabric's own runtime) | codec + hook adapter + runtime-cli lane | **ACP-agent lane**: genty exposed *as* an ACP agent via @fabricstack/acp's agent service, then driven through the standard ACP lane | t3:packages/effect-acp/src/agent.ts:31; R4 spec input 4 |
| +1 | Qwen (codec-only, found at HEAD; absent from all dossier inventories) | codec qwen-adapter.ts, no hook adapter, no live-stack lane | **Retained-subprocess** (no live-stack obligation added) | fabric:packages/adapters/codecs/src/qwen-adapter.ts (dir listing at HEAD) |
3.3 Projection direction (D6, binding)
ACP session/update notifications and bespoke-lane events → normalizer (pattern: t3:apps/server/src/orchestration/Normalizer.ts, R2 §3.1) → the **67-member** AgentEvent union (all members extend BaseEvent — 49 defined in events.ts plus 18 in events-control.ts; the research dossier's 49 counted only events.ts) (fabric:packages/adapters/core/src/events.ts:411) as **derived view**. Existing consumers keep compiling and become the projection's acceptance suite (WP-T3-14):
- RunHandle iteration/emitter/thenable semantics (
run-handle.ts:1-8,150); - gateway
run.eventfan-out (fabric:packages/adapters/gateway/src/runs/manager.ts:103-110); - journal binding (
fabric:packages/babysitter-sdk/src/storage/journal.ts:72-82; hook→session→run resolutionfabric:packages/babysitter-sdk/src/harness/hooks/stopHookHandler.ts:209-225); - cost records (
run-handle.ts:9,21-27) and the model-proxy attestation seam (fabric:packages/adapters/transport/src/server.ts:1596-1607).
The inverse direction is forbidden: no WP may make the 67-member union the source of truth with ACP as "one more codec" (the rejected alternative, synthesis-adoption-proposal.md §1.1).
3.4 Fabric-unique planes preserved (binding, R4 §A.4)
1. **Journal/run binding** — every lane terminates in the babysitter journal (§4.4 rule). 2. **Observe lane** — all 12 hook adapters survive (§3.1). 3. **Trust-signed gates** — fabric:packages/adapters/policy/src/proven-bridge.ts:92-119 (human-root chain) gates the new drive-side permission callbacks; never bypassed by them (WP-T3-17). 4. **Cost + attestation seam** — projection consumers (§3.3). 5. **Atlas graph coupling** — every hooks adapter depends on atlas (R1 §3.6); lane implementations keep deriving harness metadata from the graph, and the ~201-literal backlog (fabric:docs/hard-coded-and-should-be-in-graph-gaps-backlog.md) is not worsened: new lanes introduce no new hardcoded harness literals (checked in each lane WP). 6. **7-action approval taxonomy superset** — preserved via the approval mapping (§4.3, WP-T3-23).
The full 22-file codec disposition table is the WP-T3-13 deliverable; its terminal states are fixed here: retire (cursor, claude-agent-sdk, claude-adapter, claude-remote-control, codex, codex-sdk, codex-websocket, opencode, opencode-http — each inside its replacing lane WP after live-stack parity), retain-behind-contract (gemini, copilot, pi, pi-sdk, omp, openclaw, hermes, droid, amp, qwen, babysitter, adapters-remote), infrastructure superseded (base-adapter.ts retired when the last codec migrates to the WP-T3-05 contract).
---
4. kradle control-surface alignment (D2b)
4.1 Topology: environment server under the multi-tenant plane
Adopted per Gate A (synthesis-adoption-proposal.md §1.2): kradle (multi-tenant, K8s, org-scoped — fabric:packages/kradle/core/src/org-scoping.js:5) ⟷ N environment servers (one per workspace/runner). Kradle's agent-dispatch-controller/agent-workspace-controller become environment **clients** dispatching OrchestrationCommands over contracts RPC (t3:packages/contracts/src/orchestration.ts:35-44). The kradle↔environment boundary contract is the environment descriptor + capability flags (t3:packages/contracts/src/environment.ts:1-3) + the environmentHttp.ts HttpApi groups. **ACP terminates inside the environment; kradle never speaks it** (R4 §B.6) — mirroring t3code, where web/desktop only ever see contracts RPC.
4.2 Contracts adoption over the 81 untyped routes
kradle-web has 81 untyped .js route files (measured — R4 §B.1) against contracts' 144 Rpc.make definitions + 8 orchestration methods (the 139-entry WS_METHODS map — t3:packages/contracts/src/rpc.ts:277,1394; orchestration.ts:35-44). Program (WP-T3-21/22):
- **Run/thread/session surfaces**: replaced by contracts RPC against environments (the gateway fold-in, §4.5).
- **Org-admin CRUD** (
orgs/[org]/{policies,policy-exception-requests,policy-reports,secrets,webhooks,inference,pipelines,profile,repositories,resources,views,workspaces,artifacts,assistant,external,hooks,jitsi,search,snapshot,agents}+auth/*,atlas/search,git-proxy, and the SSE watch routefabric:packages/kradle/web/app/api/watch/[[...resource]]/route.js:1-20): typed **in place** — REST/SSE stays acceptable for admin surfaces (R4 spec input 10) — with request/response schemas defined in fabric-only RPC/HTTP groups added to the contracts fork, so there is exactly one schema source (B3: routes consume decoded plain objects). - The capability-flag/schema-transform compat doctrine (
t3:docs/internals/overview.md:24-44; legacy-field transform exampleorchestration.ts:60-74) is adopted as the versioning discipline for the new boundary — the structural cure for the untyped-route class and for D10's client/environment version skew.
4.3 Approval mapping (binding table, WP-T3-23)
t3code's pending-approvals projection maps **onto** kradle's 7-action AgentApproval taxonomy (fabric:packages/kradle/core/src/agent-approval-controller.js:15), chained to babysitter signed breakpoints with human trust roots (proven-bridge.ts:92-119):
| kradle gate action | t3code counterpart | Mapping rule |
|---|---|---|
tool-use | drive-side permission requests: Claude CanUseTool, ACP permission modes, ProviderApprovalDecision (R2 §4, §5) | bidirectional: lane permission callback → pending approval → AgentApproval(tool-use) → decision → callback resolution; decision evidence signed via proven-bridge |
review | proposed-plans projection + approval policies (t3:packages/contracts/src/orchestration.ts, R2 §5) | t3code plan approvals surface as review gates |
ai-review | none | **fabric extension, preserved** |
secret-access | none | **fabric extension, preserved** |
write-back | none | **fabric extension, preserved** |
release | none | **fabric extension, preserved** |
escalation | none | **fabric extension, preserved** |
The approval contract extension (fabric RPC group in the contracts fork) types all seven; the four/five t3code-blind actions flow through the same pending-approvals plumbing as first-class variants, not stringly-typed extras.
4.4 Journal sovereignty rule (binding on every WP)
The environment's SQLite event store (t3:packages/shared/src/nodeSqliteClient.ts:1-7; t3:apps/server/src/persistence/Layers/Sqlite.ts:6,37) owns **thread/turn projections inside an environment**. Run identity, provenance, and replay stay with the babysitter journal (fabric:packages/babysitter-sdk/src/storage/journal.ts:72-82); the kanban read model keeps deriving from .a5c/runs journal directories (fabric:packages/adapters/gateway/src/kanban/lib/source-discovery.ts:12-34). **Any WP that lets the environment store become run source-of-truth violates this spec** (R4 spec input 8). WP-T3-16 makes the rule mechanical.
4.5 Gateway fold-in (17 frames → contracts)
The gateway's zod protocol v1 (fabric:packages/adapters/gateway/src/protocol/v1.ts, 151 lines, union at :151) is the projection ancestor, not the destination (Gate-A ratified — synthesis-adoption-proposal.md §1.2 alternative 3). Mapping (WP-T3-21):
Gateway frame (v1.ts) | Contracts destination |
|---|---|
auth (:6) | environment auth handshake: DPoP-bound session (WP-T3-30), not a frame |
hello (:11) | environment descriptor + capability flags (t3:packages/contracts/src/environment.ts:1-3) |
subscribe (:26) | subscribeThread/subscribeShell (orchestration.ts:35-44) |
session.start (:47) | dispatchCommand (thread-start command) |
session.message (:61) | dispatchCommand (user-message command) |
run.event (:79) | subscribeThread stream carrying the AgentEvent projection payloads (§3.3) |
hook.request (:87) | pending-approvals projection subscription (§4.3) |
hook.decision (:96) | approval-decision command via dispatchCommand |
hook.resolved (:103) | pending-approvals projection update |
pairing.register/consume/consumed (:110-122) | DPoP pairing grants (WP-T3-30) |
remaining ack/error/keepalive frames (balance of the 17-frame union, :151) | native RPC response/error/heartbeat envelopes of the effect/unstable/rpc runtime (t3:packages/contracts/src/rpc.ts:1-3) — no bespoke equivalents retained |
Run/hook/pairing/org-admin become **fabric-only RPC groups in the contracts fork** (WP-T3-02); the gateway package is then reduced to what has no contracts equivalent: the kanban read model and webhook fan-out (manager.ts:103-224), re-hosted per WP-T3-21.
---
5. genty shell retirement (D2c, D13)
Retired: the 7 device shells (mobile-android 23 files, mobile-ios 22, tv-androidtv 18, tv-appletv 16, watch-watchos 25, watch-wearos 22, desktop-app 10 — all L0, ~0 tests, no CI, R1 §3.3) and, **after Playwright parity**, genty/web-app (the only e2e-gated shell). Replacements: adapted apps/console-web (WP-T3-25), apps/console-desktop bundling the fabric environment server (WP-T3-26), on @fabricstack/client-runtime (WP-T3-24). kradle/web survives as the org-admin surface only (spec 15 §3.2: @fabricstack/admin-console); run/thread UX moves to console-web. Mobile deferred (D13). Preserved through parity layers: the genty-ui hook API semantics (useRun/useHookRequests, fabric:packages/genty/ui/src/gateway.ts:1-8, 18 test files — the only tested fabric client surface, R4 §C.4), approval UX, org/observability/journal views. The duplicated protocol copy (fabric:packages/genty/ui/src/protocol/v1.ts:1-15, 151 lines mirroring the gateway package — R4 §C.1) is deleted, replaced by the single contracts import (R4 spec input 9). The T-27 retirement list is the single exemption list for all rename completeness checks (spec 15 interaction rule 4).
6. Remote-access stack (D2d, D12)
Four routes, one auth (R4 §D.6): direct/LAN pairing (DPoP proofs + pairing grants + scoped sessions, t3:apps/server/src/auth/), Tailscale as "an endpoint for ordinary pairing", not a separate environment type (t3:docs/internals/remote.md:43-45), SSH bootstrap + port-forward with client-owned lifecycle (t3:packages/ssh), hosted relay with the broker-not-proxy trust model adopted verbatim (relay mints nothing, sees no session tokens; one-time bootstrap credential bound to the client's DPoP key; cloudflared managed tunnels expose only a validated loopback origin — t3:docs/internals/t3-connect.md:3-33). Two mandatory substitutions (Gate A §1.4): Clerk → kradle org identity (org-scoping.js:5); @noble/curves relay PKI → trust-core key/chain machinery (fabric:packages/trust-core/src/index.ts:1-7) so fabric ships one PKI. The gateway's short-code pairing (fabric:packages/adapters/gateway/src/pairing/short-code.ts:1-20, 8-digit/5-minute in-memory) is the upgrade seed, not deleted-and-reinvented: same UX slot, upgraded to DPoP-bound grants (WP-T3-30). Fabric has zero ssh/tailscale/relay code today (R1 §3.10) — rows here are pure adoption.
7. Break-freely policy (D10) and the in-repo consumer inventory
No compatibility shims; major bump lands with RN-1/P-01. Every consumer broken by this program, with its migrating WP:
| Broken surface | In-repo consumers | Migrated by |
|---|---|---|
BaseAgentAdapterInterface/RunHandle replaced by the WP-T3-05 contract | 22 codec files (fabric:packages/adapters/codecs/src/*-adapter.ts, listing at HEAD); @a5c-ai/comm-adapter type importers across codecs (e.g. babysitter-adapter.ts:12-24); genty-platform createRun orchestration (fabric:packages/genty/platform/src/harness/internal/createRun/orchestration/policy-enforcement-wiring.ts:123-150); gateway run manager (manager.ts:103-224) | WP-T3-05/06/10/11/12/13 (codecs), WP-T3-17 (policy wiring), WP-T3-21 (gateway) |
AgentEvent production path (union stays; producers re-platformed) | journal binding, cost/attestation, observer-dashboard event views | WP-T3-14 (consumers are its acceptance suite) |
| Gateway protocol v1 frames | genty-ui GatewayClient + hooks (gateway.ts:1-8), its protocol copy (genty/ui/src/protocol/v1.ts); kanban UI routes (fabric:packages/adapters/gateway/src/kanban/routes.ts region, registered server.ts:24) | WP-T3-21 (server side), WP-T3-24 (client side), WP-T3-27 (copy deletion) |
| kradle dispatch/workspace controllers driving adapters directly | fabric:packages/kradle/core/src/agent-dispatch-controller.js, agent-workspace-controller.js | WP-T3-20 |
| kradle-web untyped route handlers | the 81 route files (R4 §B.1) | WP-T3-22 |
| Gateway token auth + short-code pairing | fabric:packages/adapters/gateway/src/auth/{tokens,middleware,bootstrap,hashing}.ts, pairing/short-code.ts:1-20 | WP-T3-30 |
| genty shells and genty-ui as shipped surfaces | web-app/desktop-app/device shells; tui/ui keep operating against contracts via the parity layer until console-web parity, then per retirement list | WP-T3-24/25/27 |
apps/commander (mock-only backend by design, zero CI references — R1 §3.9) consumes **frozen mirrors** of these contracts, not live imports; its disposition is F-17 (spec 20), not a migration item here. observer-dashboard reads journal artifacts, not the adapter contract, and is untouched except as a WP-T3-14 acceptance consumer.
8. Sequencing
- **Naming/registry preconditions**: WP-RN-01…04 + WP-RN-08 precede WP-T3-01 (spec 15 interaction rule 2). All WP-T3-* depend on WP-T3-01 transitively unless noted.
- **Critical path**: WP-T3-32(pin) → WP-T3-01 → WP-T3-02/03/04 → WP-T3-05/14 → lanes (06…13) → 15/16/17/18; in parallel WP-T3-19 → 20/21/22/23 → 30 → 31; client chain 24 → 25 → 26 → 27; remote extractions 28/29 anytime after 01/32.
- **D11**: this migration is roadmap priority 1; spec 50's R-01 owns the merged cross-spec graph.
---
9. Work packages
WP-T3-01: Fork intake — import machinery, upstream pins, attribution (D15/D17/D21)
- **Objective**: Land the intake mechanics for all §2 units: pristine-snapshot import branch, per-unit
UPSTREAM.jsonpins, MIT attribution files, and the adopted third-party-license machinery — so every subsequent WP lands code with provenance, under@fabricstack/*names only. - **Affected paths**: new orphan branch
vendor/t3code-snapshotholding the unmodified snapshot (tree fromC:/Users/tmusk/AppData/Local/Temp/claude/.../t3code, pinned by commit SHA recorded in-branch); newdocs/THIRD-PARTY-NOTICES.md;third-party-licenses.config.json+scripts/sync-third-party-license-notices.cjsadapted fromt3:third-party-licenses.config.json+t3:scripts/sync-third-party-license-notices.ts(R2 §14);UPSTREAM.jsontemplate; intake PR template gaining the §3.3-names checklist. - **Acceptance criteria**: (1) the snapshot branch exists with the upstream SHA +
t3:LICENSEverbatim; (2) the license-sync script runs in CI and fails when a §2 unit lacks its config entry (negative fixture proves it); (3) zero manifests anywhere introduce@t3code/*/t3-*/@a5c-ai/*names — the WP-RN-08 gate passes un-waived on this WP's output; (4)docs/THIRD-PARTY-NOTICES.mdcarries the MIT © 2026 T3 Tools Inc. notice; (5) no file in the public babysitter repo is touched (PR audit note). - **Test requirements**: license-sync negative-fixture test; WP-RN-08 gate fixture run; docs-quality gate green.
- **Dependencies**: WP-RN-03, WP-RN-04, WP-RN-08 (spec 15); WP-T3-32 stage 1 (Effect pin exists so imported manifests resolve).
- **Size**: M
WP-T3-02: Contracts tracked fork — `@fabricstack/contracts` + fabric RPC groups + capability-flag doctrine
- **Objective**: Land
t3:packages/contracts(74 modules, 26,979 LOC — R2 §5) as@fabricstack/contractsatpackages/contracts; add fabric-only RPC/HTTP groups (runs, hooks/approvals incl. the 7-action taxonomy §4.3, pairing, org-admin schemas for WP-T3-22); adopt the capability-flag + schema-transform versioning doctrine (t3:docs/internals/overview.md:24-44;orchestration.ts:60-74) as the boundary discipline. - **Affected paths**: new
packages/contracts/(fork of all 48 non-test modules incl.rpc.ts,orchestration.ts,providerRuntime.ts,environment.ts,environmentHttp.ts,auth.ts,settings.ts,terminal.ts— R2 §5 inventory); new fabric-group modulespackages/contracts/src/fabric/{runs,approvals,pairing,orgAdmin}.ts;UPSTREAM.json; pruned modules recorded as divergence (ipc.tsstays for WP-T3-26;pullRequest.ts/device.ts/preview*.tsretained-dark per §2 exclusions with a divergence note, since deleting them would poison future tracked-fork pulls). - **Acceptance criteria**: (1) package builds with plain
tscunder fabric's npm workspace,effectas the sole runtime dep (R2 §18.2); (2) the 139-entryWS_METHODSmap and the file's 144Rpc.makedefinitions (t3:packages/contracts/src/rpc.ts:277; both counts measured in the pinned snapshot — the AC includes re-verifying both numbers against the forked source at fork time and recording them inUPSTREAM.json) and the 8 orchestration methods (orchestration.ts:35-44) compile unmodified; (3) fabric groups type all 7 approval actions ofagent-approval-controller.js:15as first-class variants; (4) a capability-flag negotiation unit test proves an old client degrades against a new environment descriptor without error; (5)publishConfig.registry= AR URL (guard G1); WP-RN-08 gate green. - **Test requirements**: upstream test files retained and green under fabric's vitest; new schema round-trip tests for every fabric group; legacy-wire-transform regression test replicating the
orchestration.ts:60-74pattern on one fabric field. - **Dependencies**: WP-T3-01, WP-T3-32 (pin).
- **Size**: L
WP-T3-03: `@fabricstack/acp` tracked fork + schema regeneration pipeline
- **Objective**: Land
t3:packages/effect-acp(15,546 LOC, 10,375 generated — R2 §6) as@fabricstack/acpatpackages/acp, with the generator wired so upstream ACP-spec churn is a regeneration, not a hand-merge. - **Affected paths**: new
packages/acp/—_generated/schema.gen.ts,meta.gen.ts,rpc.ts(22Rpc.make—t3:packages/effect-acp/src/rpc.ts:8-40),protocol.ts(:23-80JSON-RPC stdio, client+server from one child stdio),client.ts(AcpClient—client.ts:49),agent.ts(AcpAgent—agent.ts:31),errors.ts,terminal.ts(:6-25); the five subpath exports (client/agent/schema/protocol/errors) preserved; regeneration script adapted fromt3:packages/effect-acppackage.json"generate" (@effect/openapi-generator);UPSTREAM.json. - **Acceptance criteria**: (1) builds with plain tsc, dep =
effectonly; (2) regeneration run against the pinned ACP schema reproduces_generated/*byte-identically (proves the pipeline, not just the copy); (3) the ACP mock agent (adapted fromt3:apps/server/scripts/acp-mock-agent.ts) completes an initialize → session/new → prompt-turn → session/update cycle againstclient.tsin CI; (4) both directions exported: client (drive) and agent (be-driven). - **Test requirements**: upstream tests green; mock-agent protocol suite (the Q-07 pattern, spec 30) wired as this package's CI job.
- **Dependencies**: WP-T3-01, WP-T3-32.
- **Size**: M
WP-T3-04: `@fabricstack/codex-protocol` tracked fork + regeneration pipeline
- **Objective**: Land
t3:packages/effect-codex-app-server(61,816 LOC, 58,004 generated — R2 §7) as@fabricstack/codex-protocolatpackages/codex-protocol, regenerable from the Codex app-server schema. - **Affected paths**: new
packages/codex-protocol/—_generated/{schema.gen.ts,namespaces.gen.ts},meta.gen.ts,client.ts(262 LOC, spawnscodex app-server),protocol.ts(485 LOC), re-exportrpc.ts(t3:packages/effect-codex-app-server/src/rpc.ts:1); regeneration script; probe example adapted fromt3:packages/effect-codex-app-server/test/examples/codex-app-server-probe.ts;UPSTREAM.jsonadditionally recording the upstream schema source once confirmed (R2 §17 flags the generator source as INFERRED — confirming it is an acceptance item here, closing that dossier gap). - **Acceptance criteria**: (1) builds with plain tsc, dep =
effectonly; (2) regeneration reproduces_generated/*; (3) the probe example completes a handshake against a locally installedcodexbinary in the live-stack lane (skippable-by-absence, asserted in the WP-T3-11 lane run); (4)UPSTREAM.jsonnames the confirmed schema provenance. - **Test requirements**: upstream tests green; regeneration determinism test in CI.
- **Dependencies**: WP-T3-01, WP-T3-32.
- **Size**: M
WP-T3-05: The `ProviderAdapter`-equivalent plain-TS contract (successor of `BaseAgentAdapterInterface`/`RunHandle`)
- **Objective**: Define fabric's one adapter contract per §3.1: typed capabilities + compaction semantics modeled on
t3:apps/server/src/provider/Services/ProviderAdapter.ts:29-56, retaining fabric's broader surfaces (auth detectionadapter-types.ts:42, session-file parsing:46-49, deferred promptsrun-handle.ts:44-51, cost typesrun-handle.ts:9,21-27) and adding drive-side permission callbacks routed to §4.3 approvals. Plain TS only (B1). - **Affected paths**:
fabric:packages/adapters/core/src/adapter-types.ts(superseded),run-handle.ts(retained shape, re-exported by the new contract), newpackages/adapters/core/src/contract/{provider-adapter.ts,lanes.ts,permissions.ts};fabric:packages/adapters/codecs/src/base-adapter.ts:61,75(registry migrates to lane-aware factory). - **Acceptance criteria**: (1) contract module has zero
effectimports (boundary check per §2.1); (2)RunHandle's triple nature (AsyncIterable + emitter + thenable,run-handle.ts:1-8) is preserved verbatim in the new contract's run surface; (3) capability set includes at minimumsessionModelSwitch,promptlessTurnContinuation,supportsConversationRollback, compaction mode, deferred-prompt targets; (4) permission-callback type routes through the approval contract of WP-T3-02 (compile-time proof: shared type import); (5) all five lane kinds declared (acp,claude-sdk,codex-app-server,opencode-http,subprocess) plus the observe lane binding point. - **Test requirements**: contract unit tests incl. a fake lane exercising run/steer/cancel/permission flows; architecture-gate rule added (no Effect in
packages/adapters/core/src/contract/**). - **Dependencies**: WP-T3-02 (approval/event vocabulary types).
- **Size**: M
WP-T3-06: Generic ACP lane runtime + per-harness extension modules
- **Objective**: Implement the ACP lane: one generic session runtime over
@fabricstack/acp's client, with per-harness extension modules, adapted fromt3:apps/server/src/provider/acp/{AcpSessionRuntime,AcpAdapterSupport,AcpCoreRuntimeEvents,AcpRuntimeModel,AcpStderr}.ts(R2 §4), exposed through the WP-T3-05 contract (Effect quarantined inside, B2/B1). - **Affected paths**: new
packages/adapters/codecs/src/lanes/acp/{runtime.ts,support.ts,events.ts,stderr.ts}+extensions/directory (Cursor/Grok/Antigravity modules land in WP-T3-07/08/09); wiring into the lane-aware registry (WP-T3-05). - **Acceptance criteria**: (1) the runtime drives the WP-T3-03 mock agent end-to-end through the plain-TS contract: start session → prompt → streamed
session/update→ permission request surfaced via the contract callback → terminal completion; (2) no Effect type escapes the lane boundary (boundary check); (3) ACP permission requests reach the WP-T3-02 approval types; (4) stderr and crash taxonomy normalized into projection-ready events. - **Test requirements**: mock-agent lane suite in PR CI; permission round-trip test; kill/cancel propagation test (child process actually terminates — the H5-class behavior must hold in the new lane even though H5 itself is F-05/spec 20).
- **Dependencies**: WP-T3-03, WP-T3-05.
- **Size**: L
WP-T3-07: Cursor ACP lane
- **Objective**: Cursor drives via
cursor-agent [permission args] acp(t3:apps/server/src/provider/acp/CursorAcpSupport.ts:56-60) with the CursorAcpExtension pattern; thecursor-adapter.tscodec retires after parity; the red live-stack lane (#562 — R1 §4.3) goes green on the new lane (shared objective with F-18, spec 20). - **Affected paths**: new
packages/adapters/codecs/src/lanes/acp/extensions/cursor.ts(fromt3:.../CursorAcpExtension.ts+CursorAcpSupport.ts); deletefabric:packages/adapters/codecs/src/cursor-adapter.ts; live-stack agent map entrycursorre-pointed at the lane (live-stack.ymlCompute Matrix agents map). - **Acceptance criteria**: (1) live-stack cursor lane green with lane artifacts (
adapters-events, trace ids — R1 §4.3 artifact set); (2) hook adapteradapter-cursorcontinues to feed the projection for user-driven sessions (observe lane untouched); (3) codec file deleted, registry has nocursorsubprocess factory; (4) Cursor's self-updater constraint honored: fabric never attempts to update the Cursor binary (t3:docs/internals/providers.md, updates section). - **Test requirements**: lane unit tests against recorded ACP transcripts; live-stack dispatch run linked in the WP closing note.
- **Dependencies**: WP-T3-06, WP-T3-14.
- **Size**: M
WP-T3-08: Grok Build ACP lane — net-new harness (D7(a))
- **Objective**: Build fabric's first Grok support: ACP lane via
grok --permission-mode <mode> agent stdio(t3:apps/server/src/provider/acp/GrokAcpSupport.ts:33-41,55-56) with the XAi extension pattern (XAiAcpExtension.ts,XAiBackgroundTasks.ts); add the live-stack lane the D7(a) matrix requires (fabric has zero grok code today — R1 §3.1). - **Affected paths**: new
packages/adapters/codecs/src/lanes/acp/extensions/grok.ts; live-stack agents map gainsgrok; setup probe logic honoring the no-side-effects rule (t3:docs/internals/providers.md, setup section). - **Acceptance criteria**: (1) live-stack grok lane runs and produces the standard artifact set; (2) permission modes map onto the approval contract; (3) background-task events normalize into the projection; (4) probe performs no auth/session mutation.
- **Test requirements**: recorded-transcript unit suite; live-stack lane added to the dispatch matrix (push-default inclusion decided by spec 30's Q-03).
- **Dependencies**: WP-T3-06, WP-T3-14.
- **Size**: M
WP-T3-09: Antigravity ACP lane + managed installer
- **Objective**: Replace the failing Antigravity integration (#945 — R1 §4.3) with the t3code model: fabric-downloaded release with immutable versions + version leases, identity verified as
agentInfo.name === "antigravity-acp"/protocolVersion === 1(t3:apps/server/src/provider/AntigravityInstallation.ts:484-502), OAuth loopback-callback forwarding (AntigravityAuth.ts), per-instance profile isolation, and the revert-rejection rule (cannot roll back conversation ⇒ reject revert before touching files — R2 §3.4). - **Affected paths**: new
packages/adapters/codecs/src/lanes/acp/extensions/antigravity.ts+installers/antigravity.ts(fromAntigravityInstallation.ts, spawn builderantigravityAuthSupport.ts:434); hook adapteradapter-antigravityunchanged; live-stackantigravityentry re-pointed. - **Acceptance criteria**: (1) installer downloads, verifies identity, and leases a version in an integration test with a stubbed release feed; (2) live-stack antigravity lane green; (3) revert requests against an antigravity session are rejected with a typed error before any file mutation (unit test); (4) installer work reuses WP-T3-33's ownership-proof machinery, not a parallel implementation.
- **Test requirements**: installer integration test; lane transcript suite; live-stack run.
- **Dependencies**: WP-T3-06, WP-T3-14, WP-T3-33.
- **Size**: L
WP-T3-10: Claude SDK lane
- **Objective**: Claude drives via
@anthropic-ai/claude-agent-sdkin-processquery()(t3:apps/server/src/provider/Layers/ClaudeAdapter.ts:5,14-27): permission callbacks via SDKCanUseTool, usage limits fromSDKRateLimitInfo(Layers/claudeUsageLimits.ts), session history/fork in a **child worker** so the SDK sees the provider environment without mutating the server's (t3:apps/server/src/claudeHistoryWorker.ts:1-11). Replaces codecsclaude-agent-sdk-adapter.ts,claude-adapter.ts, andclaude-remote-control-adapter.tsafter parity. - **Affected paths**: new
packages/adapters/codecs/src/lanes/claude-sdk/{lane.ts,history-worker.ts,usage-limits.ts}; delete the three claude codec files after the acceptance run; hook adapteradapter-claudeunchanged. - **Acceptance criteria**: (1) live-stack claude-code lane green on the new lane (it is GREEN today — R1 §4.3 — so this is a no-regression bar with the same artifact set); (2)
CanUseToolcallbacks route through WP-T3-17's trust-gated approvals; (3) history worker runs out-of-process (asserted by PID inequality in test); (4) the three retired codecs deleted and unregistered; (5) parity checklist againstclaude-remote-control-adapter.tscapabilities recorded in the WP closing note before its deletion (it imports programmatic-run types —fabric:packages/adapters/codecs/src/claude-remote-control-adapter.ts:7-24— so remote-control-mode coverage must be explicitly confirmed or consciously dropped with a note, not silently lost). - **Test requirements**: lane unit suite with SDK mocked; live-stack claude lane (push default — R1 §4.3); permission round-trip e2e.
- **Dependencies**: WP-T3-05, WP-T3-14, WP-T3-17.
- **Size**: L
WP-T3-11: Codex app-server lane
- **Objective**: Codex drives via
codex app-serverJSON-RPC stdio typed by@fabricstack/codex-protocol(t3:apps/server/src/provider/Layers/CodexAdapter.ts:45-46,CodexSessionRuntime.ts; launch argscodexLaunchArgs.ts:13), honoring the async-question protocol traps (notifications answered by a new user message; blocking questions via request/response —t3:docs/internals/providers.md, protocol-traps). Retires codecscodex-adapter.ts,codex-sdk-adapter.ts,codex-websocket-adapter.ts. - **Affected paths**: new
packages/adapters/codecs/src/lanes/codex-app-server/lane.ts; delete the three codex codecs; hook adapteradapter-codexunchanged. - **Acceptance criteria**: (1) live-stack codex lane green (no-regression, GREEN today — R1 §4.3); (2) async questions surface as approval/steering events, blocking questions as contract permission callbacks; (3) the three codecs deleted and unregistered; (4) protocol typed end-to-end — no untyped JSON handling outside
@fabricstack/codex-protocol. - **Test requirements**: probe handshake (WP-T3-04) in lane CI; recorded app-server transcript suite; live-stack codex lane (push default).
- **Dependencies**: WP-T3-04, WP-T3-05, WP-T3-14.
- **Size**: L
WP-T3-12: OpenCode HTTP lane
- **Objective**: OpenCode drives via
@opencode-ai/sdk/v2with one fabric-managedopencodeserver **per thread** (or an external server) — the per-directory MCP registration constraint forces server-per-thread (t3:apps/server/src/provider/Layers/OpenCodeAdapter.ts:32;t3:docs/internals/providers.md:14-22); shared instance-owned helper for catalog/text-gen perOpenCodeServerOwner.ts. Retires codecsopencode-adapter.ts,opencode-http-adapter.ts; turns the skipped/failing lane green (with F-18). - **Affected paths**: new
packages/adapters/codecs/src/lanes/opencode-http/{lane.ts,server-owner.ts}; delete the two opencode codecs; hook adapteradapter-opencodeunchanged. - **Acceptance criteria**: (1) live-stack opencode lane green; (2) server lifecycle owned per thread with leak-free teardown (test asserts zero orphan
opencodeprocesses after suite); (3) external-server mode configurable; (4) codecs deleted and unregistered. - **Test requirements**: lane suite against a local opencode server in CI; process-leak assertion; live-stack run.
- **Dependencies**: WP-T3-05, WP-T3-14.
- **Size**: M
WP-T3-13: Retained-subprocess lane migration — the full 22-codec disposition table
- **Objective**: Migrate the retained codecs behind the WP-T3-05 contract as the fifth lane and execute the terminal disposition of **all 22** codec files (listing at HEAD,
fabric:packages/adapters/codecs/src/*-adapter.ts), including the four undossiered files and qwen, with the oh-my-pi/omp aliasing resolved per §3.2. Dispositions (binding): **retain-behind-contract** —gemini,copilot,pi,pi-sdk(programmatic —fabric:packages/adapters/codecs/src/pi-sdk-adapter.ts:1-7,25),omp(≡ oh-my-pi),openclaw,hermes,droid,amp,qwen,babysitter(self-driving orchestrator harness —babysitter-adapter.ts:1-6; long-term successor is the WP-T3-18 ACP-agent lane, retained until that lands and proves parity),adapters-remote(nesting pass-through emittingadapters runspawn args for docker/ssh/k8s wrapping —adapters-remote-adapter.ts:1-18; retained now, re-evaluated against WP-T3-19/30 remote connectivity in the WP closing note); **retired by other WPs** — cursor (T3-07), claude×3 (T3-10), codex×3 (T3-11), opencode×2 (T3-12); **infrastructure** —base-adapter.ts(:61,75) retired here once the last retained codec runs on the new contract. - **Affected paths**: the 12 retained codec files (mechanical port to the lane API);
base-adapter.tsdeletion; registry finalization; live-stack agents map (14 ids — R1 §4.3) re-verified against the final lane inventory. - **Acceptance criteria**: (1) the disposition table lands in-code as a checked test fixture (every codec file at HEAD accounted for; adding an unlisted codec fails the test); (2) all retained harness lanes produce identical projection output before/after migration on recorded fixtures (golden diff); (3)
base-adapter.tsdeleted; zero imports of the oldBaseAgentAdapterInterfaceremain repo-wide; (4) live-stack push-default lanes (claude-code, codex, pi, antigravity, genty — R1 §4.3) green post-migration; (5) the aliasing resolution recorded: exactly one lane idomp, hook adapteradapter-oh-my-pimapped to it. - **Test requirements**: golden projection fixtures per retained codec; full live-stack dispatch matrix run; registry completeness test.
- **Dependencies**: WP-T3-05, WP-T3-14; retirement entries depend on WP-T3-07/10/11/12.
- **Size**: L
WP-T3-14: AgentEvent projection layer — 67-member union as derived view + consumer acceptance suite
- **Objective**: Build the normalizer that projects ACP
session/update+ bespoke-lane events into the existing 67-memberAgentEventunion (all members extend BaseEvent — 49 defined inevents.tsplus 18 inevents-control.ts; the research dossier's 49 counted onlyevents.ts) (fabric:packages/adapters/core/src/events.ts:411; families at:21-46,:57-75,:85-115,:124-153,:164-186,:196-212,:222-238,:250-265) as a **derived view** (D6), with the four consumer families of §3.3 compiled and tested unchanged. - **Affected paths**: new
packages/adapters/core/src/projection/{normalizer.ts,acp.ts,claude.ts,codex.ts,opencode.ts,subprocess.ts};events.tsuntouched (the union is the target, not the casualty); consumer test harness underpackages/adapters/core/src/projection/__tests__/. - **Acceptance criteria**: (1) golden tests: for each lane, recorded native transcripts project to expected
AgentEventsequences — golden coverage scoped to the **full 67-member union membership derived from theAgentEventtype itself**: a completeness test enumerates the union's discriminants from the type (not from anextends BaseEventgrep — the 67 members are split acrossevents.tsandevents-control.ts, so a file-scoped grep can silently undercount) and fails when any member lacks either a golden fixture or an explicit, reviewed not-producible-by-any-lane annotation; (2) the four consumer families pass unmodified: RunHandle iteration semantics (run-handle.ts:1-8), gateway fan-out (manager.ts:103-110), journal binding (journal.ts:72-82write path receives identical event payload shapes), cost/attestation (transport/src/server.ts:1596-1607seam receives cost records); (3) a reverse-dependency check proves no producer writesAgentEventexcept through the normalizer (architecture-gate rule); (4) token-usage projection covers t3code's turn-usage shape (t3:packages/contracts/src/providerRuntime.tsturn token usage — R2 §5) mapped toTokenUsageSummary(run-handle.ts:21-27). - **Test requirements**: golden fixture suite (this is spec 30's Q-09 anchor); consumer compile+test gate in PR CI.
- **Dependencies**: WP-T3-02 (ProviderRuntimeEvent vocabulary), WP-T3-05.
- **Size**: L
WP-T3-15: Observe-lane rebind — 12 hook adapters feed the projection unchanged
- **Objective**: Re-bind the 12 hook adapters (R1 §3.1 listing) so their observe-side events enter the WP-T3-14 normalizer instead of the legacy event plumbing — with zero behavior change to the adapters themselves (t3code has no observe mode; this plane is fabric-only and survives whole — R4 §A.3).
- **Affected paths**:
packages/adapters/hooks/coreevent-emission seam; hook→session→run resolution untouched (stopHookHandler.ts:209-225is F-06 territory, spec 20); the 12adapter-*packages: dependency bumps only. - **Acceptance criteria**: (1) all 12 adapters' existing test suites green without source changes inside the adapters; (2) an observe-lane event for a user-driven session reaches the same
AgentEventconsumers as a drive-lane event (integration test per adapter family); (3) live-stackbabysitter-plugininstall-mode lanes (R1 §4.3) green. - **Test requirements**: hooks-adapter suites (already PR-gated —
ci.ymltest job, R1 §4.1); one new observe→projection integration test. - **Dependencies**: WP-T3-14.
- **Size**: M
WP-T3-16: Journal sovereignty enforcement across all lanes
- **Objective**: Make §4.4 mechanical: run identity, provenance, and replay live in the babysitter journal for every lane; the environment SQLite store is projection-only for threads/turns.
- **Affected paths**: lane→journal binding in
packages/adapters/codecs/src/lanes/*(each lane's run termination writes throughjournal.ts:72-82exactly as today's codecs do);apps/environmentpersistence layer annotated: run-scoped tables carry ajournalRunRef, never the inverse; a CI architecture rule forbidding imports fromapps/environment/src/persistenceintopackages/babysitter-sdk. - **Acceptance criteria**: (1) for each of the five lanes, an e2e run produces a journal under
.a5c/runs/whose event sequence replays (existing replay engine, R1 §3.4) and whose run id appears in the kanban source discovery (source-discovery.ts:12-34); (2) deleting the environment SQLite DB mid-suite loses no run identity/provenance (journal replay reconstructs run state; thread projections rebuild); (3) the architecture rule trips on a negative fixture. - **Test requirements**: per-lane journal e2e; DB-deletion recovery test; replay determinism assertion (checksum-level verification itself remains F-01, spec 20 — this WP asserts presence and replayability, not tamper-proofing).
- **Dependencies**: WP-T3-14, WP-T3-19.
- **Size**: M
WP-T3-17: Trust-signed policy gating wired into drive-lane permission callbacks
- **Objective**: Every drive-side permission callback (Claude
CanUseTool, ACP permission requests, Codex blocking questions) is gated by the proven-bridge human-root chain (fabric:packages/adapters/policy/src/proven-bridge.ts:92-119) — the new lanes must not create an approval path that bypasses trust-signed breakpoints (§3.4.3). - **Affected paths**:
packages/adapters/policy/src/proven-bridge.ts(new entry point for lane callbacks); lane permission plumbing (lanes/*/); genty-platform policy wiring (policy-enforcement-wiring.ts:123-150) consuming the contract callback instead of legacy seams. - **Acceptance criteria**: (1) a lane permission grant without a valid human-root-chained signature is rejected when
POLICY_CONFIG_ROOT_FPis pinned (mirrors the fail-closed behavior atpolicy-enforcement-wiring.ts:139-150); (2) with no anchor pinned, behavior matches today's back-compat posture (:132-137) — flipping the default is F-03, spec 20, not this WP; (3) no lane contains a code path resolving a permission callback without consulting the policy bridge (architecture-gate rule + negative test); (4) approval decisions carry signature evidence into the WP-T3-23 approval records. - **Test requirements**: tamper test (forged decision rejected); policy-adapter suite (PR-gated today,
ci.yml:171-183) extended and green. - **Dependencies**: WP-T3-05, WP-T3-14; consumed by WP-T3-06/10/11.
- **Size**: M
WP-T3-18: Fabric-as-ACP-agent — runs and genty sessions drivable by external ACP clients
- **Objective**: Adopt
@fabricstack/acp's agent side (t3:packages/effect-acp/src/agent.ts:31) to expose babysitter runs and genty sessions as ACP sessions — zero fabric precedent, the reciprocal seam of D6 (R4 spec input 4); genty (harness row 16) becomes the first consumer, driven through the standard ACP lane. - **Affected paths**: new
packages/adapters/gateway/src/acp-agent/(ACP agent service bridging session/new → run dispatch, session/update ← projection events, permission requests ← approval gates); genty lane registration switching from thegentysubprocess codec to the ACP-agent lane;packages/adapters/codecs/src/lanes/acp/extensions/genty.ts. - **Acceptance criteria**: (1) an external ACP client (the WP-T3-03 mock client harness inverted) initializes, starts a session, and receives streamed updates for a real babysitter run; (2) permission requests surface as ACP requests and resolve through WP-T3-17 gates; (3) live-stack
gentylane green via the ACP path; (4) thebabysitterself-driving codec's parity is evaluated against this lane and the result recorded (WP-T3-13 cross-item). - **Test requirements**: ACP conformance suite over the agent side (mock client); live-stack genty lane.
- **Dependencies**: WP-T3-03, WP-T3-05, WP-T3-14.
- **Size**: L
WP-T3-19: Environment server hard fork — `@fabricstack/environment`
- **Objective**: Land the
t3:apps/serversubset (§2 row 6: orchestration 38 files/20.4k LOC, persistence 84/7.6k, checkpointing, terminal 4/3.5k, vcs/git/sourceControl/project/usage/textGeneration/mcp/resourceTelemetry — R2 §3 table) as@fabricstack/environmentatapps/environment, binenvironment-server: the single-node environment that runs under kradle's plane, hosting the WP-T3-05 lane layer. Pruned at landing:pullRequest/,device/,preview/,desktopUpdate/, marketing/mobile-adjacent code (§2 exclusions). Cherry-picked shared modules (nodeSqliteClient,DrainableWorker—t3:packages/shared/src/{nodeSqliteClient.ts:1-7,DrainableWorker.ts}) land underapps/environment/src/shared/. - **Affected paths**: new
apps/environment/(event-sourced engine: commands → pure decider → events → projector → reactors, single SQLite transaction —t3:docs/internals/overview.md:56-72; state under the fabric data dir,.a5c/today,.fabric/after RN-3);UPSTREAM.json; the resource-monitor Rust helper (t3:native/resource-monitor, stdin/stdout protocol v3 —main.rs:11) vendored underapps/environment/native/resource-monitoras an optional sidecar. - **Acceptance criteria**: (1)
environment-serverstarts under fabric's npm workspace on Node ≥22.16 (engines pert3:apps/server/package.json;node:sqlitefloor ≥22.5 — R2 §15), serves contracts RPC, and completes dispatchCommand → decider → projector → subscribeThread round-trip; (2) replay-forever discipline holds: a persisted event log from the acceptance run replays cleanly on restart (overview.md:68-70); (3) checkpoints work as hidden git refs with capture/restore/diff (t3:apps/server/src/checkpointing/CheckpointStore.ts:1-15) and never add commits to the user's branch; (4) terminal subsystem serves a PTY oversubscribeShell(node-pty as the only new native build dep); (5) pruned subsystems absent from the shipped tree (grep gate); (6) journal sovereignty holds (WP-T3-16 tests pass against this server); (7) runtime-receipt test bus operational (overview.md:89-92) — production layer no-op. - **Test requirements**: upstream test suites of adopted subsystems green under the fabric toolchain; receipts/DrainableWorker-based integration suite (no sleeps — Q-07 pattern); replay determinism test.
- **Dependencies**: WP-T3-01, WP-T3-02, WP-T3-32 (stage 2).
- **Size**: L
WP-T3-20: Kradle↔environment boundary — controllers become environment clients
- **Objective**: Kradle's
agent-dispatch-controller/agent-workspace-controllerdispatchOrchestrationCommands to environment servers over contracts RPC instead of driving adapters directly; the boundary is the environment descriptor + capability flags (t3:packages/contracts/src/environment.ts:1-3) +environmentHttp.tsgroups; kradle never speaks ACP (§4.1). - **Affected paths**:
fabric:packages/kradle/core/src/agent-dispatch-controller.js,agent-workspace-controller.js(become clients); new environment-registry controller (which environments exist per org, descriptor cache, capability negotiation); org scoping preserved (org-scoping.js:5). - **Acceptance criteria**: (1) a kradle-dispatched run executes inside an
apps/environmentinstance and streams back throughsubscribeThread, with the run journaled per WP-T3-16; (2) capability negotiation proven: a controller degrades gracefully against an environment lacking a flag (unit test per theoverview.md:24-44doctrine); (3) zero ACP imports underpackages/kradle(grep gate); (4) org boundary enforced: an environment registered to org A is not dispatchable from org B (test); (5) K8s CR reconcilers, Helm/GKE deployment, and the 7-action approval controller continue functioning (kradle-core suite green —publish.yml:565-568). - **Test requirements**: kradle-core node:test suite green; new dispatch-through-environment e2e in the deployed-stack lane (
publish.yml:423-424). - **Dependencies**: WP-T3-02, WP-T3-19.
- **Size**: L
WP-T3-21: Gateway fold-in — 17 frames → contracts RPC; gateway reduced
- **Objective**: Execute the §4.5 mapping table: every gateway frame's function is served by contracts RPC groups on the environment; the gateway package is reduced to its fabric-only residue (journal-derived kanban read model + webhook fan-out), re-hosted behind typed routes.
- **Affected paths**:
fabric:packages/adapters/gateway/src/protocol/v1.ts(deleted at completion),server.ts:4,177,181,572(WS server retired),runs/manager.ts:103-224(run-event fan-out re-platformed ontosubscribeThread; webhook fan-out kept);kanban/retained, reading.a5c/runsas today (source-discovery.ts:12-34), served via a typed fabric HTTP group from WP-T3-02. - **Acceptance criteria**: (1) each row of the §4.5 table demonstrated by an equivalence test (same stimulus, equivalent observable result on old frame vs new RPC — spec 30 Q-09's gateway-frame↔contracts suite); (2)
protocol/v1.tsdeleted; repo-wide grep shows no gateway-frame type imports outside historical docs; (3) kanban UI functions against the typed route; (4) webhook fan-out fires on projection events with unchanged payloads (golden test); (5) the gateway-node-engine CI job (ci.yml:319) is retargeted or retired with its floor assertions moved toapps/environment. - **Test requirements**: frame↔RPC equivalence suite; kanban source-discovery tests green; webhook golden tests.
- **Dependencies**: WP-T3-02, WP-T3-19, WP-T3-20; client side in WP-T3-24.
- **Size**: L
WP-T3-22: kradle-web route program — type-or-replace the 81 untyped routes
- **Objective**: Execute §4.2 over the measured 81 route files (R4 §B.1): run/thread/session routes replaced by contracts RPC; org-admin CRUD routes typed in place against the WP-T3-02 fabric org-admin schemas; the SSE watch route (
watch/[[...resource]]/route.js:1-20) typed; zero untyped route handlers remain. - **Affected paths**:
fabric:packages/kradle/web/app/api/**(all 81 files); shared schema-decode helper consuming@fabricstack/contracts(B3: routes receive decoded plain objects); route-by-route disposition ledger committed aspackages/kradle/web/ROUTE-DISPOSITIONS.mdlisting each file → {typed-in-place | replaced-by-RPC | deleted} . - **Acceptance criteria**: (1) the disposition ledger covers exactly the 81 files (CI test derives the list from the tree and diffs); (2) every surviving route validates request+response against contracts schemas (middleware test hits each route with a malformed payload and asserts a typed 4xx); (3) kradle-web's 30 spec files pass (their CI gating is Q-01/Q-05, spec 30 — here they must merely be green locally); (4) no
effectimports in route files (B3 boundary check); (5) org scoping semantics unchanged (org-scoped route test matrix). - **Test requirements**: route validation matrix; SSE watch typed-event test; disposition-ledger completeness test.
- **Dependencies**: WP-T3-02, WP-T3-20.
- **Size**: L
WP-T3-23: Approval mapping — pending approvals ↔ 7-action AgentApproval ↔ signed breakpoints
- **Objective**: Implement the §4.3 table: t3code's pending-approvals projection surfaces as kradle
AgentApprovalresources; the four fabric-only actions (secret-access,write-back,release,escalation) plusai-reviewflow as first-class variants; every decision is chained to signed breakpoints (proven-bridge.ts:92-119). - **Affected paths**:
fabric:packages/kradle/core/src/agent-approval-controller.js(consumes the approval RPC group); environment pending-approvals projection (from WP-T3-19); the WP-T3-02 approval contract; babysitter breakpoint enforcement (fabric:packages/babysitter-sdk/src/breakpoints/enforce-signed-breakpoint.ts) as the signature spine. - **Acceptance criteria**: (1) a drive-lane tool-permission request round-trips: lane callback → environment pending approval → kradle
AgentApproval(tool-use)→ human decision → signed evidence → callback resolution — asserted end-to-end in the deployed-stack e2e; (2) each of the 7 actions has a typed round-trip test; the 5 t3code-blind actions verified to carry their fabric semantics (e.g.secret-accessgates a secret-config grant —agent-secret-config-grant-controller.jspath); (3) an unsigned or non-human-root decision is rejected (tamper test, mirroringenforce-signed-breakpoint.test.tspatterns — R1 TEST2 note); (4) t3code plan proposals surface asreviewgates. - **Test requirements**: 7-action round-trip matrix; tamper suite; deployed-stack approval e2e.
- **Dependencies**: WP-T3-02, WP-T3-17, WP-T3-19, WP-T3-20.
- **Size**: L
WP-T3-24: client-runtime hard fork — `@fabricstack/client-runtime`
- **Objective**: Land
t3:packages/client-runtime(256 files — R2 §8) as@fabricstack/client-runtimeatpackages/client-runtime: single connection supervisor (connection/supervisor.ts), per-environment registry (connection/registry.ts) with **kradle as catalog source** (each kradle-managed environment = one entry — the hosted-web pattern,t3:docs/internals/remote.md:28-38), ~30 atom state services, credential refresh decoupled from socket lifetime (authorization/service.ts),platform/service interfaces as the shell plug-point; plus a **genty-ui hook-API parity layer** reproducinguseRun/useHookRequests/useGateway/useAgents/useConnectionsemantics (fabric:packages/genty/ui/src/gateway.ts:1-8). - **Affected paths**: new
packages/client-runtime/(fork, minus relay/device modules deferred to WP-T3-31/never); newpackages/client-runtime/src/compat/genty-ui-hooks.ts(parity layer); cherry-picked shared modules undersrc/shared/; approval UX mapped to the 7-action taxonomy. - **Acceptance criteria**: (1) genty-ui's 18 test files pass against the parity layer (the R4 §C.4 bar) with only import-path changes; (2) one supervisor owns all reconnect behavior — the divergent-backoff bug class (
genty/ui/src/client/backoff.tsvskradle/web/app/components/agent/live-updates.jsx:8-30) is demonstrably unified (chaos test: drop/restore transport, all surfaces reconnect through the supervisor); (3) connection catalog populated from kradle's environment registry (WP-T3-20); (4) Effect quarantined to the atom/data layer;platform/interfaces and the hook API are plain TS (boundary check, B1/B6); (5) noprotocol/v1types anywhere in the package. - **Test requirements**: genty-ui parity suite; supervisor chaos test; catalog integration test against a stub kradle.
- **Dependencies**: WP-T3-02, WP-T3-21, WP-T3-32.
- **Size**: L
WP-T3-25: Web app hard fork — `@fabricstack/console-web`
- **Objective**: Land
t3:apps/web(1,258 files — R2 §11) as@fabricstack/console-webatapps/console-web: run/thread UX, tiptap composer,@pierre/diffsrendering, ghostty-wasm terminal (t3:apps/web/src/terminal/ghostty/core.ts:13-15; headers pinned byt3:native/libghostty-vt/VERSION— the wasm artifact build provenance, flagged INFERRED in R2 §17, is resolved as an acceptance item), checkpoint UI, settings — re-pointed at@fabricstack/client-runtime+@fabricstack/contracts, with fabric org semantics and approval views for all 7 actions. Clerk paths removed (hosted identity is kradle's — §6). Deployment forms: server-served local client (fromapps/environment) and the kradle-hosted multi-tenant client. - **Affected paths**: new
apps/console-web/(fork, Clerk-dependent modules deleted as divergence); vendorednative/libghostty-vtheaders + a documented wasm build step; theming/branding neutralized (D14: no public branding work, neutral defaults only). - **Acceptance criteria**: (1) Playwright parity bar met: every scenario in
genty/web-app's existing Playwright e2e (theci.yml"adapters webui browser e2e" step — R1 §4.1) has an equivalent green console-web scenario — this is the precondition WP-T3-27 consumes; (2) run/thread views work against a live environment (create → stream → approve → diff → checkpoint restore); (3) approval UI renders all 7 actions incl. the fabric-only four; (4) terminal renders via the wasm build whose provenance is scripted in-repo (INFERRED gap closed); (5) zero Clerk imports (grep gate); (6) org-scoped views respect kradle org boundaries; (7) builds on the fabric toolchain (WP-T3-32 stage 2 — stock Vite), not vite-plus. - **Test requirements**: Playwright parity suite in PR CI; component tests for approval views; wasm terminal smoke test.
- **Dependencies**: WP-T3-24, WP-T3-32.
- **Size**: L
WP-T3-26: Desktop app hard fork — `@fabricstack/console-desktop`
- **Objective**: Land
t3:apps/desktop(258 files — R2 §11) as@fabricstack/console-desktopatapps/console-desktop: Electron shell wrapping the console-web renderer, with the DesktopBackendManager/Pool pattern (t3:apps/desktop/src/backend/{DesktopBackendManager,DesktopBackendPool,DesktopServerExposure}.ts) bundling and spawning the **fabric** environment server — fabric's single-node desktop story (serves D3 Form A; packaging productization is spec 40 P-03…P-08). IPC stays typed by the contracts fork'sipc.ts(1,388 LOC — R2 §5). Native-module discipline preserved: Electron main loads no native modules; native capability in deadline-bounded children (t3:docs/internals/overview.md:105-110). Snapshot/browser-import native helpers (browser-secret, hyprland/kde snap-shot) are pruned per §2 exclusions. - **Affected paths**: new
apps/console-desktop/(fork:src/backend/,src/electron/,src/ssh/,src/wsl/;src/snapShot/,src/preview/pruned); bundlesapps/environmentbuild output. - **Acceptance criteria**: (1) desktop app launches, spawns its bundled environment server, and drives a full run locally with no external services; (2) IPC surface compiles against
@fabricstack/contractsipc.ts; (3) Electron main native-module import graph is empty (build-time assertion); (4) ssh remote-connect flow works against WP-T3-28's package (desktop-owned lifecycle —t3:docs/internals/remote.md:47-50); (5) pruned trees absent (grep gate). - **Test requirements**: Electron smoke e2e (launch → local run → quit, no orphan processes); backend-manager lifecycle unit tests; IPC type-compile gate.
- **Dependencies**: WP-T3-19, WP-T3-25; ssh flow needs WP-T3-28.
- **Size**: L
WP-T3-27: genty shell retirement + protocol-copy deletion
- **Objective**: Execute §5: delete the 7 device shells +
genty/desktop-appscaffold (fabric:packages/genty/desktop-app/package.json:9-13) immediately; deletegenty/web-appafter WP-T3-25's Playwright parity bar is met; delete genty-ui's protocol copy (fabric:packages/genty/ui/src/protocol/v1.ts:1-15); publish the retirement list as the single rename-exemption list (spec 15 §3.2/interaction rule 4). - **Affected paths**: delete
packages/genty/{desktop-app,web-app}and the mobile/tv/watch shell workspaces (R1 §3.3 inventory);packages/genty/uiretained but its protocol/transport layer replaced by@fabricstack/client-runtimeimports (tui keeps working through the same parity layer); rootpackage.jsonworkspaces pruned;RETIREMENT-LIST.mdat repo root consumed by the WP-RN completeness checks. - **Acceptance criteria**: (1) shells deleted; workspace install/build green; (2)
web-appdeletion gated on the recorded parity run (link in closing note) — if parity is not yet green, web-app survives and this WP closes partially with the survivor named on the retirement list (spec 15 §3.2 contingency); (3) repo-wide grep forgenty/ui/src/protocolimports returns zero; genty-ui + tui suites green on client-runtime imports; (4) wildcard deps that pointed at retired shells are gone (genty/desktop-app/package.json:16,genty/web-app/package.json:15— R1 HYG2 partial relief, remainder is P-02); (5)RETIREMENT-LIST.mdmatches exactly what was deleted/kept. - **Test requirements**: full PR CI on the deletion commit; genty-tui/ui suites; Playwright parity evidence attached.
- **Dependencies**: WP-T3-24, WP-T3-25.
- **Size**: M
WP-T3-28: `@fabricstack/ssh` extraction (tracked fork)
- **Objective**: Land
t3:packages/ssh(10 files, 4,143 LOC, 100% Effect — R2 §10) as@fabricstack/sshatpackages/ssh: auth, command execution, config, tunnels; remote bootstrap downloads the **fabric** environment server via fabric's release URLs (replacing thecliReleasebase URL seam —t3:packages/ssh/src/tunnel.ts:9; fabric's release-asset story is spec 40 P-03/P-04, so bootstrap-download activation is gated on those artifacts existing); client-owned lifecycle: cleanup stops a remote server only if it started it (t3:docs/internals/remote.md:47-50). - **Affected paths**: new
packages/ssh/+UPSTREAM.json; plain-TS facade module for non-Effect call sites (B1); thecliReleaseURL builder cherry-picked and re-pointed at fabric release endpoints (inert until P-03 ships assets — the facade exposes port-forward/exec/tunnel immediately, bootstrap behind a capability check). - **Acceptance criteria**: (1) builds with plain tsc, dep =
effectonly; (2) port-forward + remote-exec integration test against a local sshd container green; (3) lifecycle rule tested: a pre-existing remote server is not stopped by cleanup; (4) facade exports Promise-based API with zero Effect types (boundary check); (5) bootstrap path unit-tested against a stub release endpoint and marked capability-gated pending P-03. - **Test requirements**: sshd-container integration suite in CI; facade type test.
- **Dependencies**: WP-T3-01, WP-T3-32.
- **Size**: M
WP-T3-29: `@fabricstack/tailscale` extraction (tracked fork)
- **Objective**: Land
t3:packages/tailscale(763 LOC — R2 §10) as@fabricstack/tailscaleatpackages/tailscale: wraps the user'stailscaleexecutable (status,serve) with the schema-validated, secret-scrubbing error taxonomy (t3:packages/tailscale/src/tailscale.ts:10-31); doctrine adopted as-is — tailscale is "an endpoint for ordinary pairing", not a separate environment type (t3:docs/internals/remote.md:43-45). - **Affected paths**: new
packages/tailscale/+UPSTREAM.json; plain-TS facade (B1); environment-server integration point (advertise the environment on the tailnet, pairing terminates in WP-T3-30 auth). - **Acceptance criteria**: (1) builds with plain tsc, dep =
effectonly; (2) error taxonomy scrubbing verified: a fixturetailscale statusoutput containing auth keys yields errors with secrets redacted (unit test); (3)servewrapper integration-tested against a stubbed CLI; (4) no separate environment type introduced — pairing over tailscale uses the identical WP-T3-30 grant flow (integration test). - **Test requirements**: stub-CLI unit suite; secret-scrub fixtures; pairing-equivalence test with WP-T3-30.
- **Dependencies**: WP-T3-01, WP-T3-32; equivalence test needs WP-T3-30.
- **Size**: S
WP-T3-30: Environment auth — DPoP + pairing grants replacing gateway token auth + short-code pairing
- **Objective**: Adopt
t3:apps/server/src/auth/(DPoP proofsdpop.ts, pairing grantsPairingGrantStore.ts, persisted auth sessions with scopes/thumbprint/expiry —t3:apps/server/src/persistence/AuthSessions.ts:1-30,AuthPairingLinks.ts:19-31, per-method RPC authorizationRpcAuthorization.ts; "authentication of a socket does not authorize every method on it" —t3:docs/internals/overview.md:18-19) as the environment's auth, **upgrading in place** the gateway's short-code pairing UX slot (fabric:packages/adapters/gateway/src/pairing/short-code.ts:1-20; framesv1.ts:110-122) to DPoP-bound grants, and retiring gateway bearer tokens (fabric:packages/adapters/gateway/src/auth/{tokens,middleware,bootstrap,hashing}.ts). - **Affected paths**:
apps/environment/src/auth/(landed in WP-T3-19's tree, activated and integrated here); deletion of the gateway auth/pairing modules with WP-T3-21; client pairing flow inpackages/client-runtime(pairing UX slot preserved: short human-friendly code initiates a grant, but the grant is DPoP-bound, one-time, TTL'd, scoped). - **Acceptance criteria**: (1) pairing e2e: client generates DPoP keypair → enters short code → receives grant → establishes scoped session; replayed grant fails (one-time); expired grant fails (TTL); (2) per-method authorization enforced: a standard-scope session calling an admin-scoped RPC is rejected (matrix test over scope×method samples); (3) stolen-token uselessness: a captured session token without the DPoP private key fails proof verification (test); (4) zero bearer-token auth code remains in the serving path (grep gate after WP-T3-21 completes); (5) secrets stored via the OS credential store seam (
t3:apps/server/src/auth/ServerSecretStore.ts+@napi-rs/keyring— R2 §3.3). - **Test requirements**: auth conformance suite (grant lifecycle, DPoP proofs, scope matrix); client-runtime pairing e2e.
- **Dependencies**: WP-T3-19, WP-T3-21, WP-T3-24.
- **Size**: L
WP-T3-31: Relay hard fork — `@fabricstack/relay` with kradle org identity + trust-core envelopes
- **Objective**: Land
t3:infra/relay(78 files, 27,381 LOC — R2 §12) as@fabricstack/relayatinfra/relaywith the two Gate-A substitutions: (a) Clerk replaced by kradle org identity — the relay scopes environments to orgs (org-scoping.js:5) and authenticates against the kradle control plane; (b) the@noble/curvessigning protocol re-anchored on trust-core key/chain machinery (fabric:packages/trust-core/src/index.ts:1-7) so fabric ships one PKI. The broker-not-proxy trust model is adopted verbatim: relay mints nothing, never sees session tokens, one-time bootstrap credential bound to the client's DPoP key, cloudflared managed tunnels expose only a validated loopback origin, no application-traffic proxying after bootstrap (t3:docs/internals/t3-connect.md:3-33); tunnel lifetime rules pert3-connect.md:41-56. Environment-sidecloud/module (managed tunnel runtimet3:apps/server/src/cloud/ManagedEndpointRuntime.ts:77, startup reconciliation, CLI tokens, self-update handoff) activates inapps/environment. - **Affected paths**: new
infra/relay/(Cloudflare Worker +@effect/sql-pg/drizzle persistence; Clerk modules deleted as divergence;relaySigningcherry-picked underinfra/relay/src/shared/and rebuilt on trust-core primitives);apps/environment/src/cloud/activation; kradle org-identity federation endpoint (environment↔org linking anchored in the control plane — R4 §D.4.2); ops story (Worker + Postgres + cloudflared) documented for spec 40/50 consumption. - **Acceptance criteria**: (1) full broker flow e2e on a staging deployment: environment publishes → client (authenticated via kradle org identity) requests access → relay brokers one-time DPoP-bound bootstrap credential → client redeems **directly** with the environment → session established; relay logs prove it never held a session token; (2) envelope signatures verify against trust-core chains both directions; a foreign-signed envelope is rejected (tamper test); (3) org scoping: client of org A cannot discover/bootstrap org B's environments; (4) managed tunnel exposes only the validated loopback origin (probe test against other ports); (5) zero Clerk and zero standalone-noble-PKI code (grep gates;
@noble/*may remain as a crypto primitive only where trust-core itself uses it); (6) after bootstrap, application traffic bypasses the relay (network assertion in e2e). - **Test requirements**: relay unit suite (forked upstream tests adapted); staging broker e2e; tamper suite; org-isolation matrix.
- **Dependencies**: WP-T3-19, WP-T3-30; identity federation needs WP-T3-20.
- **Size**: L
WP-T3-32: Effect toolchain baseline — pin ownership, npm-workspaces integration, app-build re-platform, engine floors
- **Objective**: Own B5 and the toolchain divergence (R2 §18.12) in two stages. **Stage 1 (blocks WP-T3-01)**: single workspace-wide pin
effect@4.0.0-rc.115+ the one local patch (t3:patches/effect@4.0.0-rc.115.patch) and patched@effect/vitest, ported from pnpmpatchedDependenciesto an npm-workspaces-compatible patch mechanism; inventory of the 23 upstream patches with the 19 mobile-only ones dropped; unstable-namespace usage register (effect/unstable/{rpc,sql,process,cli,http}— R2 §15) with a named owner and an rc→stable transition watch item. **Stage 2 (blocks WP-T3-19/25/26)**: apps re-platform decision executed — stock Vite + vitest + fabric's tsc replace vite-plus (vite: npm:@voidzero-dev/vite-plus-coreis Voidzero-private — R2 §15) and TS7/tsgo; Node floors encoded: workspace engines ≥22.16 (environment server^22.16 || ^23.11 || >=24.10— R2 §15),node:sqlite≥22.5, SEA-build-host ≥25.7 recorded for spec 40's P-03 (R3 spec input 5). - **Affected paths**: root
package.json(overrides + patch wiring + engines),patches/directory, CI setup steps (Node version matrix inci.yml/live-stack.yml); per-appvite.config.tsreplacements inapps/console-web,apps/console-desktop,apps/environmentbuild scripts;docs/EFFECT-BASELINE.md(pin, patch provenance, unstable-namespace register, upgrade playbook). - **Acceptance criteria**: (1) exactly one resolved
effectversion across the workspace (npm ls effectsingleton test in CI); (2) the local patch applies and a patched-behavior regression test passes (the test encodes what the patch changes, so an upgrade that silently drops it fails); (3) all five tracked forks +apps/environmentcompile and test under stage-1 tooling; (4) console-web production build succeeds on stock Vite with no@voidzero-dev/*in the dependency graph (grep gate); (5) CI Node matrix enforces the floors (a sub-floor Node run fails the engines check); (6) the baseline doc names the pin owner and the rc→stable criteria. - **Test requirements**: singleton-version test; patch-regression test; toolchain build matrix over the three apps.
- **Dependencies**: stage 1: WP-RN-03/04 (registry + guards); stage 2: WP-T3-01.
- **Size**: L
WP-T3-33: Provider maintenance adoption — installers/updaters, usage/quota ingestion, model manifest
- **Objective**: Adopt the cross-cutting provider services (R2 §4): installer/updater machinery with updater-ownership proofs (
t3:apps/server/src/provider/providerMaintenance.ts), the usage/quota ingestion subsystem (t3:apps/server/src/usage/, 11 files/3.9k LOC — R2 §3),ModelManifest.ts+model-manifest.jsonclassification,RuntimeInstructions.tsper-provider prompt injection, and the injected MCP control endpoint (t3:apps/server/src/mcp/McpProviderSession.ts:1-12) — integrated with fabric's existing surfaces: install flows merge withfabric:packages/adapters/codecs/src/adapter-install.ts(import atbase-adapter.ts:43today), usage records flow into fabric cost records (run-handle.ts:9,21-27), and model metadata **feeds from the atlas graph where fabric already derives it** rather than forking a second static source (§3.4.5; the staticmodel-manifest.jsonbecomes an atlas-fed projection, not a rival registry — guards the ~201-literal backlog from growing). - **Affected paths**:
apps/environment/src/provider/maintenance/usage/mcp modules (activated from the WP-T3-19 tree);packages/adapters/codecs/src/lanes/*/install.tsseams; atlas-fed manifest bridge inpackages/adapters/core; per-provider auth flows (ProviderAuthServicepattern) wired to lane auth detection (adapter-types.ts:42successor). - **Acceptance criteria**: (1) one-click provider update honors ownership proofs: fabric updates only binaries it installed; user-managed installs (e.g. Cursor's self-updater — WP-T3-07) are surfaced-but-not-touched (test per policy); (2) usage/quota ingestion produces rolling-window records surfaced through contracts (
providerUsageLimits.tsshapes — R2 §5) **and** projected into fabric cost summaries (one source, two views — golden test); (3) the injected MCP endpoint appears in each drive-lane session with a scoped bearer, and tool calls through it are policy-gated via WP-T3-17 (test); (4) model classification resolves through the atlas bridge withmodel-manifest.jsonas fallback fixture only (grep: no lane reads the JSON directly); (5) new lanes introduce zero new hardcoded harness literals (backlog diff againstdocs/hard-coded-and-should-be-in-graph-gaps-backlog.mdcategories). - **Test requirements**: installer ownership-proof suite; usage-ingestion golden tests; MCP-injection policy-gate e2e.
- **Dependencies**: WP-T3-05, WP-T3-06, WP-T3-17, WP-T3-19.
- **Size**: L
---
10. Cross-spec obligations honored (D21 checklist)
- Every landed unit uses a spec 15 §3.3 name; WP-T3-01 is gated by WP-RN-08; WP-T3-02…33 depend transitively (spec 15 §5 rules 1–2 satisfied).
- No WP waits on RN-2…RN-5 (rule 3); migrated units join those sweeps.
- The WP-T3-27 retirement list is the single rename-exemption list (rule 4).
- No WP touches the public repo (intent acceptance criterion 7); publishing targets only Artifact Registry (D19).
- Spec 20 cross-refs: F-16 (remote-access coverage) ↔ WP-T3-28…31; F-18 (red lanes) ↔ WP-T3-07/08/09/12; F-17 (commander) explicitly not a migration item (§7). Spec 30 cross-refs: Q-07 (receipts/DrainableWorker/mock-agent patterns) seeded by WP-T3-03/19; Q-09 (projection goldens, frame↔RPC equivalence, hook-API parity) anchored by WP-T3-14/21/24. Spec 40: P-03…P-08 consume WP-T3-26/28 and §2 row 12; P-12 extends WP-T3-01's license machinery.
Work-package count in this spec: **33** (WP-T3-01 … WP-T3-33).