II.
Page JSON
Structured · livepage:docs-specs-platform-gaps-research-delta-map
Research dossier: Interface delta map — fabric adapters/kradle/genty-shells vs t3code json
Inspect the normalized record payload exactly as the atlas UI reads it.
{
"id": "page:docs-specs-platform-gaps-research-delta-map",
"_kind": "Page",
"_file": "wiki/docs/specs/platform-gaps/research/delta-map.md",
"_cluster": "wiki",
"attributes": {
"nodeKind": "Page",
"sourcePath": "docs/specs/platform-gaps/research/delta-map.md",
"sourceKind": "repo-docs",
"title": "Research dossier: Interface delta map — fabric adapters/kradle/genty-shells vs t3code",
"displayName": "Research dossier: Interface delta map — fabric adapters/kradle/genty-shells vs t3code",
"slug": "docs/specs/platform-gaps/research/delta-map",
"articlePath": "wiki/docs/specs/platform-gaps/research/delta-map.md",
"article": "\n# Research dossier: Interface delta map — fabric adapters/kradle/genty-shells vs t3code\n\nDate: 2026-09-27 · Author: platform-gaps spec research run · Status: input to `10-t3code-migration.md` (and Gate A adoption-model proposal)\n\nBuilds on and does not repeat: `research/fabric-current-state.md` (R1, fabric HEAD `5e46b998`) and `research/t3code-architecture.md` (R2, snapshot 2026-09-27). Citations: `fabric:` paths are relative to `C:/work/fabric`; `t3:` paths are relative to the t3code snapshot at `C:/Users/tmusk/AppData/Local/Temp/claude/C--work-company/368e0399-fd11-4960-8b4d-b4dcf1d79c43/scratchpad/t3code`. All new `path:line` cites below were read at those revisions for this dossier; claims imported from R1/R2 carry their original cites.\n\n**Overlap % method (read this before quoting the numbers):** for each row I enumerated the functional sub-capabilities of both sides (the checklists in each section), classified each as SHARED (both implement a recognizable version), FABRIC-ONLY, or T3-ONLY, and computed overlap = SHARED / (SHARED + FABRIC-ONLY + T3-ONLY), rounded to 5%. It is a *capability-count* figure, not LOC — by LOC every overlap would round to ~0 because t3code's surfaces are 5–20× larger (R2 §2). The checklists are printed so the spec author can re-weight.\n\n---\n\n## 0. Master delta table\n\n| Row | Fabric side | t3code side | Overlap | Must-survive (fabric-unique) | Gained (t3-unique) | Primary ACP/interface seam |\n|---|---|---|---|---|---|---|\n| **A** | `adapters` harness layer: 22 drive-side codec adapters + 12 observe-side hook adapters + canonical 49-type `AgentEvent` union | `packages/contracts` (`providerRuntime.ts`) + `packages/effect-acp` + `apps/server/src/provider/*` (6 drivers, generic ACP runtime) | **~45%** | Hook/observe lane for foreign-driven sessions; journal/run binding; trust-signed policy gates; cost records; atlas graph coupling | ACP client+agent protocol impl; Codex app-server typed protocol; drive-side approvals (`CanUseTool`); provider installers/updaters; usage/quota ingestion | Fabric `ProviderAdapter`-equivalent contract: ACP lane (Cursor/Grok/Antigravity) + 3 bespoke lanes (Claude SDK, Codex app-server, OpenCode HTTP); `AgentEvent` becomes a projection of ACP/`ProviderRuntimeEvent` (D6) |\n| **B** | `kradle` control plane: 69 core controllers, 81 Next.js API route files under `orgs/[org]`, K8s CR resource model, plus `adapters/gateway` 17-frame WS protocol | `apps/server` (event-sourced decider/projector, SQLite) + `packages/contracts` RPC (144+8 WS methods) + environment auth | **~30%** | Multi-tenant org control plane (K8s namespaces, Helm/GKE); 7-action approval gate taxonomy; secrets/policy/exception-request/report surfaces; gitops; inference/virtual-model routing; journal-derived kanban | Event-sourced command/decider/projector/reactor core with replay-forever; typed single wire boundary (Effect Schema); capability-flag versioning; checkpoints; PR domain; DPoP auth; terminal; device control | t3code environment server becomes the **single-node environment** under kradle's multi-tenant plane; `contracts` environment descriptor + capability flags = the kradle↔environment boundary; approvals bridged to babysitter signed breakpoints |\n| **C** | `genty` client shells (web-app + Electron scaffold + 7 L0 device shells) + `genty/ui` GatewayClient + `kradle/web` REST/SSE data layer | `packages/client-runtime` (connection supervisor, ~30 atom state services) + `apps/web` (318k LOC) + `apps/desktop` (backend-bundling Electron) | **~20%** | Multi-org UI semantics; approval/policy/observability UI surfaces; org-admin REST/SSE pages; react-native WS transport; journal kanban views | Multi-environment connection catalog + supervisor; reactive atom state layer; composer/diff/terminal-wasm/checkpoint UI; desktop that bundles its own server | `client-runtime` `platform/` service interfaces = shell plug-point; connection registry treats each kradle-managed environment as a t3code environment; kradle-web keeps org-admin, thread/run UX moves to adapted `apps/web` |\n| **D** | Remote access: **absent** except gateway token auth + LAN short-code pairing frames | `packages/ssh`, `packages/tailscale`, `apps/server/src/cloud` + `infra/relay` (T3 Connect broker) | **~5%** | Trust-core key/chain machinery must become the signing substrate (not duplicated); org-awareness of any hosted relay | All four remote routes: DPoP direct pairing, tailscale endpoint, ssh launch+forward, hosted relay (broker-not-proxy, cloudflared) | Gateway `auth/` + `pairing/` replaced by t3code environment auth (DPoP + pairing grants); `ssh`/`tailscale` packages extractable as-is (dep: `effect` only) |\n\n---\n\n## Row A — fabric `adapters` harness layer vs t3code `contracts` + `effect-acp` + provider adapters\n\n### A.1 What fabric actually has (corrects a simplification in R1)\n\nR1 §3.1 describes the adapters family primarily through the hooks lane. The drive lane is real and larger than R1 implies:\n\n- **Drive-side adapter contract.** `fabric:packages/adapters/core/src/adapter-types.ts:24` defines `BaseAgentAdapterInterface` with identity, `capabilities` (`:35`), `detectAuth()` (`:42`), session-file parsing (`sessionDir`/`parseSessionFile`/`listSessionFiles`), config read/write, model discovery, and host-detection env signals; three adapter kinds: `SubprocessAdapter` (`:79`), `RemoteAdapter` with `connect/startServer/healthCheck` (`:93-104`), `ProgrammaticAdapter` (`:168-169`).\n- **RunHandle.** `adapter.run()` returns a `RunHandle` that is simultaneously `AsyncIterable<AgentEvent>`, a typed event emitter, and a thenable resolving `RunResult` (`fabric:packages/adapters/core/src/run-handle.ts:1-8`, interface at `:150`), including deferred-prompt steering (`DeferredPromptTarget = 'next-turn' | 'after-tool' | 'after-response'`, `run-handle.ts:44-51`).\n- **Canonical event model.** 49 event interfaces extending `BaseEvent` (measured: `grep -c \"extends BaseEvent\"` = 49) in `fabric:packages/adapters/core/src/events.ts` — session lifecycle (`:21-46`), turns/steps (`:57-75`), message/thinking deltas (`:85-115`), tool calls (`:124-153`), file ops (`:164-186`), shell (`:196-212`), MCP (`:222-238`), subagents (`:250-265`) — unioned as `AgentEvent` at `events.ts:411`. This is the \"current adapters event model\" that D6 demotes to an internal projection.\n- **22 concrete drive adapters** in `fabric:packages/adapters/codecs/src/` (measured: `ls *-adapter.ts | wc -l` = 22): incl. `claude-agent-sdk-adapter.ts`, `codex-sdk-adapter.ts`, `codex-websocket-adapter.ts`, `opencode-http-adapter.ts`, `cursor-adapter.ts`, plus subprocess adapters for gemini/copilot/droid/amp/omp/etc., self-registering via a global factory registry (`fabric:packages/adapters/codecs/src/base-adapter.ts:61`, base class `:75`).\n- **12 observe-side hook adapters** (`fabric:packages/adapters/hooks/adapter-{antigravity,claude,codex,copilot,cursor,gemini,genty,hermes,oh-my-pi,openclaw,opencode,pi}`, directory listing) that instrument a harness the *user* is driving and feed events/hooks back into runs — R1 §3.1.\n- **No ACP anywhere** (R1 §3.1: zero hits for ACP under `packages/adapters` — re-confirmed premise for D6 greenfield).\n\n### A.2 t3code side (from R2, key cites)\n\n`ProviderAdapter` contract (`t3:apps/server/src/provider/Services/ProviderAdapter.ts:1-60`) with typed capabilities — `sessionModelSwitch`, `promptlessTurnContinuation`, `supportsConversationRollback` (`:46-56`) — and a compaction contract (`native` start-call vs `slash-command`, `:36-44`); 6 built-in drivers (`t3:apps/server/src/provider/builtInDrivers.ts:49-56`); one generic ACP runtime + per-provider extension modules (R2 §4); `packages/effect-acp` implementing ACP **both directions** — client for driving agents, agent for being one (R2 §6); `packages/effect-codex-app-server` as the typed Codex lane (R2 §7); canonical `ProviderRuntimeEvent` surface in `t3:packages/contracts/src/providerRuntime.ts` (1,234 LOC, R2 §5).\n\n### A.3 Sub-capability checklist\n\n| Sub-capability | Fabric | t3code | Class |\n|---|---|---|---|\n| Per-harness adapter registry + factory | `base-adapter.ts:61` | `builtInDrivers.ts:49-56` + `ProviderInstanceRegistry` | SHARED |\n| Canonical normalized event stream | `events.ts:411` (49 types) | `providerRuntime.ts` + `Normalizer.ts` | SHARED |\n| Capability declaration per harness | `adapter-types.ts:35` | `ProviderAdapter.ts:46-56` | SHARED |\n| Auth detection / guidance | `adapter-types.ts:42-43` | `ProviderAuthService` + per-provider flows (R2 §4) | SHARED |\n| Harness install/update | `codecs/src/adapter-install.ts` (import at `base-adapter.ts:44`) | installers incl. Antigravity version-leased downloads (`AntigravityInstallation.ts`) | SHARED (t3 deeper) |\n| Session-file parsing of harness-native session dirs | `adapter-types.ts:46-49` | `agentSessions.ts` import (claudeAgent/codex only, R2 §5) | SHARED (fabric broader) |\n| Run steering (deferred prompts) | `run-handle.ts:44-51` | turn dispatch + async question protocol (R2 §4 Codex row) | SHARED |\n| Cost/token accounting on the event stream | `run-handle.ts:21-27` (`TokenUsageSummary`), `CostRecord` (`run-handle.ts:9`) | turn token usage in `providerRuntime.ts`; usage/quota ingestion subsystem (R2 §3) | SHARED (different shape) |\n| **ACP protocol implementation (client+agent)** | — | `effect-acp` (R2 §6) | T3-ONLY |\n| **Typed Codex app-server protocol** | — (fabric codex lane is CLI/hooks/WebSocket: `codecs/src/codex-websocket-adapter.ts`) | `effect-codex-app-server` (R2 §7) | T3-ONLY |\n| **Drive-side permission callbacks** (approve tool use mid-turn) | — in the drive lane (approvals live in hooks/policy/breakpoints, Row B) | Claude `CanUseTool`, ACP permission modes (R2 §4) | T3-ONLY |\n| **Workspace checkpoint coordination with conversation rollback** | — | `checkpointing/CheckpointStore.ts:1-15` + revert rules (R2 §3.4) | T3-ONLY |\n| **MCP endpoint injected into every provider session** | — (fabric has MCP plugins, `codecs/src/mcp-plugins.ts`, not an injected control endpoint) | `mcp/McpProviderSession.ts:1-12` | T3-ONLY |\n| **Observe-side hook adapters for foreign-driven sessions** | 12 hook adapters (dir listing above); R1 §3.1 | — (t3code only drives sessions it started) | FABRIC-ONLY |\n| **Journal/run binding of harness events** | stop-hook → session → run binding (`babysitter-sdk/src/harness/hooks/stopHookHandler.ts:209-225`, R1 H7) | — (events bind to t3code's own SQLite threads, not an external ledger) | FABRIC-ONLY |\n| **Trust-signed policy gating of tools/MCP** | `adapters/policy/src/proven-bridge.ts:92-119` (human-root chain), enforcement wiring R1 C3 | — (approvals are session-scoped UX, not signed) | FABRIC-ONLY |\n| **Model-proxy transport with attestation seam** | `adapters/transport/src/server.ts:1596-1607` (R1 H10) | — | FABRIC-ONLY |\n| **Graph-derived harness metadata (atlas)** | atlas dep in every hooks adapter (R1 §3.6) | — (`model-manifest.json` is static, R2 §4) | FABRIC-ONLY |\n\nCount: 8 SHARED, 5 FABRIC-ONLY, 5 T3-ONLY → **overlap ≈ 45%**.\n\n### A.4 Must-survive (fabric-unique, binding)\n\n1. **Journal/run binding**: every harness event lane must still terminate in the babysitter journal/run model (journal write path `fabric:packages/babysitter-sdk/src/storage/journal.ts:72-82`; hook→session→run resolution `stopHookHandler.ts:209-225`). t3code has no external ledger concept; the ACP re-platforming must not silently replace the journal with t3code's SQLite event store as source of truth for *runs*.\n2. **Observe lane**: the 12 hook adapters cover harnesses t3code does not (gemini, copilot, pi, oh-my-pi, openclaw, hermes, genty) and a mode t3code lacks entirely (instrumenting a user-driven session). They stay, feeding the same canonical projection.\n3. **Trust-signed gates**: `proven-bridge.ts:92-119` human-root verification and the policy enforcement wiring (R1 C3) must gate the new drive lane's permission callbacks, not be bypassed by them.\n4. **Cost records + attestation seam** (`run-handle.ts` cost types; `transport/src/server.ts:1596-1607`) survive as projection consumers.\n\n### A.5 Gained from t3code\n\nACP client+agent runtime (5.2k handwritten LOC, dep = `effect` only, R2 §18.2/§18.9); typed Codex app-server lane (3.8k handwritten); generic-runtime-plus-extension-modules pattern for per-harness ACP quirks (`t3:apps/server/src/provider/acp/{AcpSessionRuntime,CursorAcpExtension,XAiAcpExtension}.ts`, R2 §4); provider installer/updater machinery with ownership proofs (`providerMaintenance.ts`); usage/quota ingestion; ACP mock agent for protocol tests (`t3:apps/server/scripts/acp-mock-agent.ts`, R2 §18.11).\n\n### A.6 The seam, precisely (D6)\n\nD6 says ACP is canonical and the current adapters event model becomes a projection. The t3code evidence fixes the shape:\n\n1. **One adapter contract, four lanes.** Fabric `adapters` gets a `ProviderAdapter`-equivalent contract (successor of `adapter-types.ts:24` + `run-handle.ts:150`) with: an **ACP lane** (effect-acp client; covers Cursor `cursor-agent … acp`, Grok `grok … agent stdio`, Antigravity downloaded ACP release — R2 §18.1) and **three bespoke lanes behind the same contract**: Claude via `@anthropic-ai/claude-agent-sdk` in-process, Codex via app-server JSON-RPC stdio, OpenCode via HTTP server-per-thread (R2 §18.1). This is exactly t3code's shape; fabric adds its remaining harnesses (gemini, copilot, pi, …) as either new ACP lanes or retained subprocess codecs behind the same contract.\n2. **Projection direction.** ACP `session/update` notifications and bespoke-lane events → normalizer → **fabric `AgentEvent` (events.ts:411) as derived view** → existing consumers (RunHandle iterators, gateway `run.event` frames, journal binding, cost/attestation). Consumers keep compiling; only the producer side is re-platformed.\n3. **Fabric as ACP agent.** `effect-acp`'s `agent.ts` service (R2 §6) lets fabric expose babysitter runs/genty sessions *as* ACP sessions — the reciprocal seam that makes fabric drivable by other ACP clients. No fabric equivalent exists today.\n4. **Effect boundary (D5 input).** `effect-acp` and `effect-codex-app-server` depend only on `effect` (R2 §18.2) — they can be quarantined behind the lane boundary: the adapter contract surface stays plain-TS (Promise/AsyncIterable, as `run-handle.ts` already is), Effect lives inside the lane implementations.\n\n---\n\n## Row B — `kradle` control-surface APIs/UIs vs t3code `apps/server` (+ contracts RPC) / `apps/web`\n\n### B.1 Fabric side\n\nThree distinct control surfaces exist (a fact the spec must not blur):\n\n- **kradle/core**: 69 controller modules (dir listing; R1 §3.2) on a K8s CR resource model — dispatch, approvals, memory, persona, workspace, writeback, secrets, transport binding, triggers, subagents, gitops (`argocd-gitops.js`), gitea backend, event bus, control/data-plane split (`control-plane.js`, `data-plane.js`), org scoping via K8s namespaces (`fabric:packages/kradle/core/src/org-scoping.js:5` re-exporting `orgNamespaceName/normalizeOrgSlug/resolveResourceOrg/withOrgScope` from `kubernetes-controller.js`).\n- **kradle/web API**: **81 route files** under `app/api` (measured: `find app/api -name \"route.js\" -o -name \"route.ts\" | wc -l` = 81), org-scoped under `orgs/[org]/{agents,artifacts,assistant,external,hooks,inference,jitsi,pipelines,policies,policy-exception-requests,policy-reports,profile,repositories,resources,search,secrets,snapshot,views,webhooks,workspaces}` (dir listing) plus `auth/*`, `atlas/search`, `git-proxy`, and an SSE watch route streaming controller watch events (`fabric:packages/kradle/web/app/api/watch/[[...resource]]/route.js:1-20`, `createKradleApiController()` at `:1`). Routes are untyped `.js` — no schema layer.\n- **adapters/gateway**: the run-facing WS control surface — HTTP + WebSocketServer (`fabric:packages/adapters/gateway/src/server.ts:4,177,181,572`), a zod-validated **17-frame protocol v1** (`fabric:packages/adapters/gateway/src/protocol/v1.ts`, 151 lines: `auth:6`, `hello:11`, `subscribe:26`, `session.start:47`, `session.message:61`, `run.event:79`, `hook.request:87`, `hook.decision:96`, `hook.resolved:103`, `pairing.register:110`, `pairing.consume:117`, union `:151`), a run manager holding live `RunHandle`s with per-run event log + hook broker + webhook fan-out (`fabric:packages/adapters/gateway/src/runs/manager.ts:103-224`), token auth (`auth/tokens.ts`, `auth/middleware.ts`), and a kanban read-model built directly over `.a5c/runs/` journal directories (`fabric:packages/adapters/gateway/src/kanban/lib/source-discovery.ts:12-34`, routes registered `server.ts:24`).\n- **Approvals**: kradle's `AgentApproval` resource with **seven first-class gate actions** — `review, ai-review, tool-use, secret-access, write-back, release, escalation` (`fabric:packages/kradle/core/src/agent-approval-controller.js:15`, boundary decl `:3-9`), and babysitter's signed-breakpoint enforcement chained to human trust roots (`fabric:packages/adapters/policy/src/proven-bridge.ts:92-119`, R1 H9).\n\n### B.2 t3code side (R2 cites)\n\nSingle-user environment server: event-sourced engine (commands → pure decider → events → projector → reactors, one SQLite transaction — R2 §3.1, `t3:docs/internals/overview.md:56-72`); **144 `Rpc.make` WS methods + 8 orchestration methods** as the sole typed wire boundary (`t3:packages/contracts/src/rpc.ts:277,1394`; `orchestration.ts:35-44`); environment auth with DPoP + pairing grants + per-method RPC authorization (R2 §3.3); checkpoints as hidden git refs (R2 §3.4); PR domain across 4 providers (R2 §3); terminal, device control, resource telemetry, usage ingestion; approval policies + pending-approvals projection + sandbox modes in `contracts/orchestration.ts` (R2 §5).\n\n### B.3 Sub-capability checklist\n\n| Sub-capability | Fabric | t3code | Class |\n|---|---|---|---|\n| Create/dispatch agent run/thread | `agent-dispatch-controller.js`; gateway `session.start` frame (`v1.ts:47`) | `dispatchCommand` (`orchestration.ts:35-44`) | SHARED |\n| Live event streaming to clients | gateway `run.event` fan-out (`manager.ts:103-110`) | `subscribeThread`/`subscribeShell` + `ThreadLiveEventCoalescer` (R2 §3.1) | SHARED |\n| Human approval gates | 7-action `AgentApproval` (`agent-approval-controller.js:15`) + gateway `hook.request/decision` (`v1.ts:87,96`) + signed breakpoints (`proven-bridge.ts:92-119`) | approval policies + pending-approvals projection + `ProviderApprovalDecision` (R2 §5, `ProviderAdapter.ts` imports) | SHARED (fabric taxonomy richer; t3 UX deeper) |\n| Project/repo registry + source control | `agent-project-controller.js`, `repository-reconciler.js`, gitea backend | `project/` + `sourceControl/` + `vcs/` (R2 §3) | SHARED |\n| Session transcript access | `agent-session-transcript-controller.js` | projections (threads/messages/turns) (R2 §3.2) | SHARED |\n| Secrets handling | `agent-secret-config-grant-controller.js` + `orgs/[org]/secrets` routes | `ServerSecretStore` + keyring (R2 §3.3) | SHARED (different scope: org grants vs host keyring) |\n| Server config/probe/update surface | `agent-gateway-config-controller.js`, `api-controller.js` | `contracts/server.ts` (891 LOC) + selfUpdate (R2 §5, §3.6) | SHARED |\n| Auth for the control surface | gateway bearer tokens (`auth/tokens.ts`); kradle web `auth/[provider]` OAuth routes | DPoP + pairing grants + scoped sessions (R2 §3.3) | SHARED (t3 stronger for device pairing; fabric has org SSO) |\n| **Multi-tenant org control plane** (K8s namespaces, CR reconcilers, Helm/GKE) | `org-scoping.js:5`; 81 org-scoped routes; charts + GKE deploy (R1 §3.2) | — (one environment = one user's machine) | FABRIC-ONLY |\n| **Policy engine surfaces** (policies, exception requests, reports) | `orgs/[org]/{policies,policy-exception-requests,policy-reports}` routes | — | FABRIC-ONLY |\n| **Inference/virtual-model routing** | `kradle-inference-service-controller.js`, `virtual-model-controller.js`, infer route (R1 CAP5) | — | FABRIC-ONLY |\n| **GitOps/CI runners/jitsi realtime** | `argocd-gitops.js`, `runners-ci.js`, `jitsi-*.js` | — | FABRIC-ONLY |\n| **Journal-derived kanban read model** | `kanban/lib/source-discovery.ts:12-34` | — | FABRIC-ONLY |\n| **Event-sourced core with replay-forever discipline** | — (kradle state = K8s CRs + gateway SQLite event log without decider/projector split) | R2 §3.1, `overview.md:70-72` | T3-ONLY |\n| **Typed contract package as sole wire boundary** | — (81 untyped `.js` routes; gateway zod frames are the only typed slice) | `contracts` 48 modules, Effect Schema (R2 §5) | T3-ONLY |\n| **Capability-flag client/environment version negotiation** | — | `environment.ts:1-3` + doctrine (`overview.md:24-44`) | T3-ONLY |\n| **Workspace checkpoints / turn diff / restore** | — | `getTurnDiff`/`getFullThreadDiff` (`orchestration.ts:35-44`), CheckpointStore (R2 §3.4) | T3-ONLY |\n| **PR lifecycle domain (4 providers), terminal, device control, resource telemetry** | — (kradle has repos, not PR stacks; no PTY surface; no device control) | R2 §3, §5 | T3-ONLY |\n\nCount: 8 SHARED, 5 FABRIC-ONLY, 5 T3-ONLY → **≈ 45%** by raw count, **but** the five t3-only entries bundle whole subsystems (PR/terminal/device/telemetry counted once). Weighting those as four distinct capabilities gives 8/(8+5+8) → **~30%**, the honest figure used in the master table.\n\n### B.4 Must-survive (fabric-unique, binding)\n\n1. **Multi-tenant control plane**: org scoping (`org-scoping.js:5`), the 81 org-scoped API routes, K8s CR reconcilers and Helm/GKE deployment (R1 §3.2) are the product's SaaS spine; t3code's single-user environment model must slot *under* it, never replace it.\n2. **Approval taxonomy + signed breakpoints**: the 7 gate actions (`agent-approval-controller.js:15`) and human-root-chained breakpoint proofs (`proven-bridge.ts:92-119`) are a strict superset of t3code approvals; the migrated surface must map t3code's pending-approvals projection *onto* `AgentApproval`, preserving `secret-access`/`write-back`/`release`/`escalation` semantics t3code has no notion of.\n3. **Journal as run source-of-truth**: gateway kanban and run manager derive from `.a5c/runs` journals (`source-discovery.ts:12-34`, `manager.ts:110`); t3code's SQLite store may own *its* thread/turn projections but run identity/provenance stays with the babysitter journal.\n4. **Process orchestration**: babysitter `defineTask`/breakpoints exports (`fabric:packages/babysitter-sdk/src/index.ts:16`) and the run lifecycle (R1 §3.4) are the orchestration substrate; t3code's decider orchestrates chat turns, not long-running processes with quality gates.\n5. **Trust signing substrate**: `trust-core` sign/verify families (`fabric:packages/trust-core/src/index.ts:1-7`: payload, model-response, model-decision, agent-request/prompt, tool-result/permission-evidence, chain).\n\n### B.5 Gained from t3code\n\nEvent-sourced orchestration core with single-transaction commit and replay-forever discipline; a typed contract package with 144+8 methods and the capability-flag/schema-transform compat doctrine (R2 §18.5) — the direct cure for kradle's 81 untyped routes; checkpoint/diff/restore; PR stacks; terminal; DPoP/pairing auth; receipts + drainable-worker test pattern (R2 §18.11).\n\n### B.6 The seam, precisely\n\n- **Topology**: kradle (multi-tenant, K8s) ⟷ *N* t3code-style **environments** (one per workspace/runner). The boundary contract is t3code's environment descriptor + capability flags + `environmentHttp.ts` HttpApi groups (R2 §5). Kradle's `agent-dispatch-controller`/`agent-workspace-controller` become environment *clients* dispatching `OrchestrationCommand`s instead of driving adapters directly.\n- **Gateway fate**: the 17-frame gateway protocol (`v1.ts`) is the projection ancestor of the contracts RPC surface — `session.start/message` ↔ `dispatchCommand`, `run.event` ↔ `subscribeThread`, `hook.request/decision` ↔ pending-approval flow. The spec must choose (D1, per-component): extend `contracts` with fabric's run/hook/pairing groups (tracked fork per D9) vs keep the gateway as a thin ACP-facing shim. Evidence favors the former: the gateway's zod frames are the only typed slice fabric has, and they are 151 lines vs contracts' 26,979.\n- **ACP touchpoint**: the environment server hosts Row A's four-lane provider layer; kradle never speaks ACP directly — ACP terminates inside the environment (mirrors t3code, where web/desktop never see ACP, only contracts RPC).\n\n---\n\n## Row C — `genty` client shells + `kradle-web` data layer vs t3code `apps/*` + `client-runtime`\n\n### C.1 Fabric side\n\n- **genty/ui client layer**: `GatewayClient` + provider/hooks/store exports (`fabric:packages/genty/ui/src/gateway.ts:1-8`: `useGateway/useAgents/useRun/useHookRequests/useConnection`), WS transports for browser/node/react-native (`fabric:packages/genty/ui/src/client/transports/{ws-browser,ws-node,ws-react-native}.ts`), backoff logic (`client/backoff.ts`), and a **mirror copy of the gateway protocol** (`fabric:packages/genty/ui/src/protocol/v1.ts:1-15`, 151 lines, 18 exported interfaces — duplicated type-for-type from the gateway package rather than imported from a shared contracts unit).\n- **Shells**: `genty/web-app` = thin Vite shell (`src/{App.tsx,main.tsx,layout,pages}`, dir listing) — the only Playwright-gated shell (R1 §3.3); `genty/desktop-app` = 10-file Electron scaffold (`fabric:packages/genty/desktop-app/package.json:9-13`: `electron .` / `electron-builder`); 7 device shells at L0 (R1 §3.3, Spec input 7).\n- **kradle/web data layer**: Next.js server components + REST fetch to the 81 routes + **SSE** live updates — `EventSource` on `/api/orgs/${org}/agents/events/stream` with manual retry/refresh debounce (`fabric:packages/kradle/web/app/components/agent/live-updates.jsx:30`, retry state `:8-14`) and the `[[...resource]]` SSE watch route (`route.js:1-20`). No shared client runtime: kradle-web and genty-ui have zero common data-layer code (separate packages, different protocols — REST/SSE vs gateway WS).\n\n### C.2 t3code side (R2 cites)\n\n`client-runtime` (256 files / 65.8k LOC): single connection supervisor owning transport retry, per-environment connection registry, compatibility negotiation, ~30 atom-based state services, credential refresh decoupled from socket lifetime, `platform/` service interfaces that shells implement (R2 §8, `t3:docs/internals/connection-runtime.md:1-27`). `apps/web` 318k LOC (React 19, TanStack Router, composer, ghostty-wasm terminal, hosted app as pure client with browser-held catalog — R2 §11). `apps/desktop` 81k LOC Electron 44 that **bundles and spawns the server** (DesktopBackendManager/Pool, R2 §11). Mobile deferred (D13) but consumes the same stack (R2 §11).\n\n### C.3 Sub-capability checklist\n\n| Sub-capability | Fabric | t3code | Class |\n|---|---|---|---|\n| WS client with typed frames + backoff | `genty/ui/src/client/{GatewayClient,backoff}.ts` | `client-runtime/connection/supervisor.ts` | SHARED |\n| React hooks/state over live runs | `gateway.ts:1-8` hooks + store | `state/` atom services (R2 §8) | SHARED |\n| Web shell for run interaction | `genty/web-app` (Playwright-gated) | `apps/web` chat/threads (R2 §11) | SHARED |\n| Desktop shell | `genty/desktop-app` Electron scaffold (`package.json:9-13`) | `apps/desktop` (81k LOC, bundles server) | SHARED (fabric = scaffold only) |\n| React-native transport | `transports/ws-react-native.ts` | Expo mobile app (deferred D13) | SHARED (both exist; both out-of-depth here) |\n| **Org-admin UI over the control plane** (policies, secrets, webhooks, inference, pipelines) | kradle/web pages over 81 routes | — | FABRIC-ONLY |\n| **Observability dashboards** (activity feed, health monitor) | `kradle/web/app/components/observability/{activity-feed,health-monitor}.jsx`; genty-ui `ActivityFeed.tsx` | agentActivity exists relay-side only (R2 §12) | FABRIC-ONLY |\n| **Journal/kanban + run-history views** | gateway kanban UI routes (`kanban/routes.ts`); observer-dashboard (R1 §3.8) | — | FABRIC-ONLY |\n| **Multi-environment connection catalog + supervisor** | — (genty-ui connects to one gateway) | `connection/registry.ts` + browser-held catalog (R2 §8, §11) | T3-ONLY |\n| **Composer/diff/terminal/checkpoint UX** | — | tiptap, `@pierre/diffs`, ghostty wasm, checkpointDiff state (R2 §8, §11) | T3-ONLY |\n| **Credential refresh decoupled from socket; compat negotiation** | — | `authorization/service.ts`, catalog compat (R2 §8) | T3-ONLY |\n| **Desktop-as-host-environment** (spawns bundled server) | — (fabric desktop scaffold renders only) | `DesktopBackendManager.ts` (R2 §11) | T3-ONLY |\n\nCount: 5 SHARED, 3 FABRIC-ONLY, 4 T3-ONLY → ~40% by count, but three of the five SHARED rows are fabric scaffolds vs t3code production systems (desktop 10 files vs 258; web-app thin shell vs 1,258 files; hooks/store vs 30 services). Discounting the scaffold rows to half-credit: **~20-25%** — the master table says ~20%.\n\n### C.4 Must-survive (fabric-unique, binding)\n\n1. **Org-admin surfaces**: policies/exception-requests/secrets/webhooks/inference/pipelines pages have no t3code analogue and stay on kradle-web (REST/SSE is adequate for admin CRUD).\n2. **Observability/journal views**: activity feeds, health monitor, kanban-over-journal, observer-dashboard — these render fabric-unique data (journal runs, org events) and must be re-pointed at whatever client runtime wins, not dropped.\n3. **The genty-ui hook API** (`useRun`/`useHookRequests`, `gateway.ts:1-8`) is the only fabric client code with real consumers *and* tests (genty-ui 18 test files, R1 §4.4); its semantics (hook-request surfacing = approvals UX) must be reproduced in any client-runtime adoption.\n4. Per D2c the 7 device shells + desktop scaffold are **retired**, destroying ~0 tested functionality (R1 Spec input 7) — nothing to survive there beyond the react-native transport learning.\n\n### C.5 Gained from t3code\n\nA real client runtime: one supervisor for reconnects across all surfaces (the exact bug-class genty-ui's per-client backoff and kradle-web's hand-rolled EventSource retry (`live-updates.jsx:8-30`) both re-implement, divergently — R2's design rationale at `connection-runtime.md:1-27` names this failure mode); multi-environment catalog; production web app with composer/diff/terminal; a desktop app that *is* a host environment (directly serves D3 single-node UX).\n\n### C.6 The seam, precisely\n\n- **Plug point** = `client-runtime`'s `platform/` service interfaces (R2 §8): fabric shells (adapted web app; kradle-web where it embeds run views) implement platform services; everything above them is shared.\n- **Connection model**: each kradle-managed environment (Row B seam) appears as one entry in the client-runtime connection registry — the hosted-web pattern (browser-held catalog, direct connection to each environment, `t3:docs/internals/remote.md:28-38`) is exactly the multi-tenant fabric topology, with kradle acting as catalog *source*.\n- **Protocol duplication ends**: genty-ui's copied `protocol/v1.ts` (151 lines duplicated from gateway) is the anti-pattern the contracts package eliminates — one schema package, imported by both sides (R2 §5 doctrine).\n- **ACP touchpoint**: none direct — clients speak contracts RPC; ACP stays inside the environment (Row A). The only client-visible ACP artifact is normalized activity/permission events, already typed in `providerRuntime.ts`.\n\n---\n\n## Row D — fabric remote story (absent) vs t3code ssh / tailscale / T3 Connect relay\n\n### D.1 Fabric side\n\nR1 §3.10 confirmed: zero tailscale/relay/ssh-tunnel code in fabric. What *does* exist, and counts as the 5% seed:\n\n- Gateway bearer-token auth (`fabric:packages/adapters/gateway/src/auth/{tokens,middleware,bootstrap,hashing}.ts`, dir listing) — same-host/LAN trust only, no proof-of-possession.\n- LAN pairing: `pairing.register/consume/consumed` frames (`v1.ts:110-122`) backed by an in-memory 8-digit short-code store with 5-minute TTL (`fabric:packages/adapters/gateway/src/pairing/short-code.ts:1-20`).\n- kradle is *cloud-deployed* (GKE, R1 §3.2) — but that is hosted control plane, not remote access to a user's local environment; the D12 gap (reach my machine's agents from anywhere) is untouched.\n\n### D.2 t3code side (R2 §10, §12, §18.6)\n\nFour routes: (1) direct/LAN pairing hardened with DPoP proofs + pairing grants + scoped sessions; (2) Tailscale as \"an endpoint for ordinary pairing\" (`t3:packages/tailscale`, 763 LOC, wraps user's tailscale CLI with secret-scrubbing errors); (3) SSH bootstrap + port-forward with desktop-owned lifecycle (`t3:packages/ssh`, 4,143 LOC, downloads server via `cliRelease`); (4) T3 Connect hosted relay — Cloudflare Worker + Postgres + Clerk, broker-not-proxy (relay never sees session tokens; one-time bootstrap credential bound to client DPoP key; cloudflared managed tunnels; `t3:docs/internals/t3-connect.md:3-33`).\n\n### D.3 Delta\n\n| Sub-capability | Fabric | t3code | Class |\n|---|---|---|---|\n| Short-lived pairing codes | `short-code.ts:1-20` (random digits, no key binding) | pairing grants bound to DPoP keys (R2 §3.3) | SHARED (fabric version is a toy by comparison) |\n| Everything else — DPoP, tailscale, ssh, relay, tunnel lifecycle, self-update handoff | — | R2 §10, §12, §3.6 | T3-ONLY (4+ capabilities) |\n\n**Overlap ≈ 5%.**\n\n### D.4 Must-survive / must-integrate (fabric-unique)\n\n1. **trust-core as signing substrate**: the relay protocol uses `@noble/curves` signing both directions (R2 §12); fabric already owns key-pair/chain machinery with human-root semantics (`trust-core/src/index.ts:1-7`, `chain.ts`). The spec must decide integration (relay envelopes verified against fabric trust chains) rather than shipping two parallel PKIs.\n2. **Org-aware relay**: T3 Connect identity is per-user Clerk (R2 §12); a fabric relay must scope environments to kradle orgs (`org-scoping.js:5`) — the multi-tenant control plane is the natural place to anchor environment↔org linking, replacing Clerk.\n3. Gateway pairing frames (`v1.ts:110-122`) are the migration shim: same UX slot, upgraded to DPoP-bound grants.\n\n### D.5 Gained\n\nThe entire D12 mandate, pre-built: extractable `ssh`/`tailscale` packages (deps: `effect` only, R2 §18.2), the environment-side `cloud/` module (managed cloudflared tunnels, CLI tokens, self-update), and a reference relay whose trust model (broker-not-proxy, `t3-connect.md:3-6`) is the design fabric should adopt verbatim. Operational cost: Cloudflare Worker + Postgres + Clerk-or-replacement stack (R2 §16).\n\n### D.6 The seam\n\nRemote access terminates at **environment auth** (Row B's boundary): every route (LAN, tailscale, ssh, relay) ultimately performs the same DPoP pairing against the environment server — t3code's discipline that \"tailscale is not a separate environment type\" (`t3:docs/internals/remote.md:43-45`) should be adopted as-is. ACP is untouched by this row: remote access is about reaching the environment's contracts-RPC surface, inside which ACP lanes run (Row A).\n\n---\n\n## CONFIRMED vs INFERRED\n\n**CONFIRMED** (read at cited lines for this dossier): fabric adapter contract shape and 3 adapter kinds (`adapter-types.ts:24,79,93,168`); RunHandle triple nature and deferred prompts (`run-handle.ts:1-8,44-51,150`); 49-interface `AgentEvent` union (`events.ts`, count measured); 22 codec adapters + factory registry (measured; `base-adapter.ts:61,75`); 12 hook adapter dirs (listing); gateway 17-frame protocol with cited frame lines (`v1.ts`), server WS wiring (`server.ts:4,177,181,572`), run manager binding (`manager.ts:103-224`), journal-sourced kanban (`source-discovery.ts:12-34`), short-code pairing (`short-code.ts:1-20`); kradle 81 API route files (measured) and org-route inventory (listing); approval action set (`agent-approval-controller.js:15`); org-scoping exports (`org-scoping.js:5`); SSE data layer (`live-updates.jsx:8-30`, `watch/[[...resource]]/route.js:1-20`); genty-ui exports/transports/protocol copy (`gateway.ts:1-8`, transport files, `protocol/v1.ts` 151 lines/18 interfaces); desktop-app Electron scripts (`package.json:9-13`); trust-core export surface (`index.ts:1-7`); babysitter breakpoints export (`index.ts:16`); t3code `ProviderAdapter` capabilities/compaction (`ProviderAdapter.ts:29-56`).\n\n**INFERRED** (flagged): the overlap percentages (judgment over the printed checklists — method stated in §0); the claim that genty-ui's `protocol/v1.ts` is a *copy* of the gateway's (identical length and frame names read on both sides; a diff was not run line-by-line); the B.6 recommendation that contracts-extension beats gateway-retention (an adoption-model argument for Gate A, not a fact); the weighting notes applied to rows B and C overlap figures.\n\n---\n\n## Spec inputs\n\nConcrete facts the spec author (10-t3code-migration.md and 20-functionality-coverage.md) must use:\n\n1. **Fabric already has a drive-side adapter contract** — `BaseAgentAdapterInterface` + `SubprocessAdapter`/`RemoteAdapter`/`ProgrammaticAdapter` (`fabric:packages/adapters/core/src/adapter-types.ts:24,79,93,168`) and `RunHandle` (`run-handle.ts:150`) with 22 codec implementations. The D6 re-platforming is a *contract replacement with lane restructuring*, not a first drive-layer build; migration WPs must enumerate the 22 codec adapters and the 12 hook adapters as distinct migration units.\n2. **The projection target is fixed**: `AgentEvent` union at `fabric:packages/adapters/core/src/events.ts:411` (49 event interfaces) becomes the derived view; its existing consumers (RunHandle iteration, gateway `run.event` fan-out at `manager.ts:103-110`, journal binding, cost summaries) define the projection's acceptance tests.\n3. **Four-lane shape is copied from t3code**: ACP lane (Cursor/Grok/Antigravity) + Claude-SDK, Codex-app-server, OpenCode-HTTP bespoke lanes behind one contract (`t3:apps/server/src/provider/builtInDrivers.ts:49-56`, `ProviderAdapter.ts:1-60`); fabric's extra harnesses (gemini, copilot, pi, oh-my-pi, openclaw, hermes, droid, amp, omp, genty) need a per-harness lane decision (ACP / retained-subprocess-codec / retired) — a mandatory WP table.\n4. **`effect-acp` gives both directions**: adopt the agent side (`t3:packages/effect-acp/src/agent.ts`) to expose fabric runs as ACP sessions — a new capability, zero fabric precedent, and the cleanest early win (dep = `effect` only).\n5. **Kradle↔environment boundary**: adopt t3code's environment descriptor + capability flags (`t3:packages/contracts/src/environment.ts:1-3`) as the interface between kradle's multi-tenant plane and per-workspace environment servers; kradle dispatch/workspace controllers become environment clients.\n6. **Typed-contract debt is quantified**: kradle-web has **81 untyped route files** (measured) vs the gateway's 151-line zod protocol as fabric's only typed wire slice (`gateway/src/protocol/v1.ts`) vs contracts' 26,979 LOC / 144+8 methods. The migration spec must map each of the 17 gateway frames to a contracts RPC group (`session.start/message`→dispatchCommand, `run.event`→subscribeThread, `hook.request/decision`→pending approvals, `pairing.*`→pairing grants) and schedule route-by-route typing (or replacement) of the 81.\n7. **Approval mapping table required**: t3code `ProviderApprovalDecision`/pending-approvals ↔ kradle's 7 gate actions (`agent-approval-controller.js:15`) ↔ babysitter signed breakpoints with human-root chains (`proven-bridge.ts:92-119`). `secret-access`, `write-back`, `release`, `escalation` have no t3code counterpart and must be preserved as fabric extensions of the approval contract.\n8. **Journal sovereignty rule**: t3code's SQLite event store may own thread/turn projections inside an environment, but run identity, provenance, and replay stay with the babysitter journal (`storage/journal.ts:72-82`; kanban reads `.a5c/runs` at `source-discovery.ts:12-34`). Any WP that lets the environment store become run source-of-truth violates this dossier.\n9. **Client-runtime adoption anchor**: genty-ui's hook API (`useRun`/`useHookRequests`, `gateway.ts:1-8`) is the tested fabric client surface to reproduce; genty-ui's duplicated `protocol/v1.ts` (151 lines mirroring the gateway package) is the concrete anti-pattern the shared contracts package removes.\n10. **Retirement inventory (D2c)**: 7 device shells + `desktop-app` scaffold (`package.json:9-13`) retire; `apps/desktop`'s DesktopBackendManager pattern (bundling a host environment) becomes the single-node desktop story (also serves D3); kradle-web survives as org-admin (REST/SSE acceptable there — `live-updates.jsx:30`), run/thread UX moves to the adapted web app.\n11. **Remote-access WPs start from the gateway pairing shim**: upgrade `pairing.register/consume` (`v1.ts:110-122`) + `ShortCodeStore` (`short-code.ts:1-20`) to DPoP-bound pairing grants; extract `t3:packages/{ssh,tailscale}` as-is; relay WP must specify Clerk-replacement by kradle org identity and trust-core-based envelope verification (`trust-core/src/index.ts:1-7`) instead of a second PKI.\n12. **Overlap figures for sizing** (capability-count method, §0): A ≈45%, B ≈30%, C ≈20%, D ≈5%. Inverse reading for effort: Row D is pure adoption (nothing to merge), Row A is a true merge (two live adapter systems), Rows B/C are graft-under/graft-over operations where fabric-unique planes (multi-tenant, approvals, journal) wrap adopted t3code cores.\n13. **Effect boundary rule candidates (D5)**: keep the fabric-facing adapter contract plain-TS (Promise/AsyncIterable as `run-handle.ts` today); Effect allowed inside lane implementations (`effect-acp`, `effect-codex-app-server`, ssh, tailscale — all `effect`-only deps per R2 §18.2); contracts adoption forces Effect Schema at the wire boundary — the one place Effect must be allowed to appear in kradle-adjacent code.\n",
"documents": []
},
"outgoingEdges": [],
"incomingEdges": [
{
"from": "page:docs",
"to": "page:docs-specs-platform-gaps-research-delta-map",
"kind": "contains_page"
}
]
}