# Tai implements CAP both directions, phased, without gRPC ## Metadata | Field | Value | |---|---| | Institute | Molodetz Institute — Research & Retrieval Division | | Subject | cap-protocol | | Document type | Conclusion Document | | Decided | 2026-10-18 | | Decided by | tai (agent), model: Muse Spark, on behalf of retoor | | Research method | full read of CAP core + coding profile, quickstart, STATUS, all 5 example manifests; selective first-hand read of A2A spec + proto and 10 ACP pages; grep of reference A2A driver | | Confidence | High | | Status | Active | ## Question / problem statement How does tai support "the literal whole protocol" as both agent (speaking CAP under a startup flag) and orchestrator (driving claude/codex/grok-class CLI agents, auto-answering their questions via research) while staying a single stdlib-only file? ## Conclusion Implement every binding except gRPC, in five phases: (1) events/errors/manifest registry plus `--cap-manifest`; (2) agent-side `--cap-speak` stream-json binding with coding artifacts; (3) orchestrator PTY driver on the reference heuristics; (4) stream-json driver plus §10 orchestration (URNs, mediated routing, worktrees, budget); (5) ACP-stdio and A2A drivers, reverse-RPC serving, and the research auto-answerer. gRPC is rejected: stdlib has no HTTP/2 or protobuf, and hand-rolling both for one optional binding fails the boring-technology rule. A bare `grpc = true` manifest still parses; binding selection falls through to PTY. ## Supporting sources - [CAP Core v1](../cap-core-v1.md): PTY-required/fast-path-optional layering makes full conformance reachable without gRPC; §7/§10/§14.2 are the build tables. - [CAP coding profile](../cap-profile-coding-v1.md): reverse-RPC surface and scope table for the orchestrator side. - [STATUS](../cap-status.md): PTY heuristics (800ms settle, prompt gate, resubmit bound) and the codex-websocket dead-end warning. - [openclaude manifest](../manifest-openclaude.md): `grpc = true` carries no address, so the flag alone is undrivable anyway. - [ACP transports](../acp-transports.md) + [prompt turn](../acp-prompt-turn.md): stdio NDJSON JSON-RPC is a few dozen stdlib lines; turn boundary is the prompt response. - [A2A specification](../a2a-specification.md): message/stream/cancel/card subset is stdlib-feasible (http.client, SSE parse, http.server for expose). ## Alternatives considered and rejected - Full gRPC via hand-rolled HTTP/2 + protobuf: rejected, thousands of lines of bug surface for an optional binding whose own manifest example omits the server address. - PTY-only orchestrator (skip all fast-paths): rejected, the reference fidelity tiers show structured paths are strictly more reliable, and stream-json is cheap once PTY exists. - Separate package for CAP: rejected, the single-file stdlib-only constraint is load-bearing for tai distribution; CAP fits in `Cap*` classes plus a `cap.md` mapping doc. ## Risks / open questions - Regex flavor: spec says ERE-only but all examples use `(?P<>)`; tai accepts Python-compatible patterns and rejects only backrefs/lookaround, flagged as a deliberate deviation. - Reverse RPC over stream-json is unspecified; tai-as-agent offers no fs/terminal mediation on the speak path until the spec defines framing. - ACP v2 migration and full terminal/fs param shapes still queued for Phase 5 reading. - Research auto-answerer quality depends on verdict/judge reliability already flagged as unmeasured. ## Action taken Phases tracked as session todos; Phase 1 (events, errors, manifest registry, `--cap-manifest`, `cap.md`, tests) implemented same session. Later phases scheduled as follow-up turns. ## Revisit when - The spec leaves draft (breaking changes possible; watch revision field). - A CAP conformance suite ships (adopt it as the integration gate). - A2A draft endpoints disappear from the wild (drop the draft spelling). ## Changelog | Date | Change | |---|---| | 2026-10-18 | Conclusion recorded. |