Files
deepseek-harness/docs/rfc
Tianyi Cui 149ab1bba4 feat(acp): render bash as a terminal card via the _meta convention
When the client advertises clientCapabilities._meta.terminal_output (Zed), a
bash tool call now renders as a real TERMINAL card — a cwd header + the command
+ its output — instead of the plain ```console text block. Keeps agent-side
dsh-bash execution; rejects the spec's client-side terminal/create (which would
bypass sandbox/env-scrub/ownership/cwd). Matches what claude-agent-acp and
codex-acp do; wire contract verified against Zed's source.

- dsh-tools: a provider-neutral ToolTerminal shape ({ cwd?, output? }) on
  ToolCallPresentation/ToolResultPresentation — a tool asks "render me as a
  terminal"; no ACP types leak in.
- dsh-tool-bash: bash presentCall marks terminal (cwd from an explicit absolute
  workdir, else left for the bridge to fill from the session cwd); presentResult
  carries the output alongside the ```console fallback.
- dsh-acp: initialize reads/remembers the _meta.terminal_output capability;
  streamSessionEventUpdate maps a terminal presentation to
  content:[{type:'terminal',terminalId}] + _meta.terminal_info on the call and
  _meta.terminal_output on the update WHEN capable — else the unchanged text
  path. terminalId is the callId; cwd defaults to the session header. The pure
  translator gained a TerminalRendering {enabled,cwd} param (off by default).

Tests via the REAL tool-bash + bash-local: capability ON -> terminal content +
_meta; OFF -> no _meta (text path). The with-key e2e adds a real-model terminal
card case (echo over ACP with the capability on). 773 tests, 100% coverage.

The exit-status pill (_meta.terminal_exit), live streaming
(_meta.terminal_output_delta), and command classification are RFC follow-ups.
2026-06-18 17:25:09 +08:00
..

RFCs

One kind of design doc lives here. An RFC records a decision or proposal that shapes this codebase — the why and what we gave up, the parts code and docs can't carry. (Earlier this split into separate "ADR" and "RFC" trees; they were unified, since most ADRs were simply implemented RFCs.)

Layout and naming

Files are grouped by lifecycle into three folders, and an RFC moves between them as its status changes:

  • proposed/ — proposals reviewed before implementation; not yet built (or only partly).
  • implemented/ — the decision shipped. The file records what was decided and what was rejected.
  • rejected/ — the proposal was considered and declined. Kept for the record so the rejection isn't re-litigated.

Each file is named yyyy-mm-dd-topic-title.md, where the date is when the topic was first proposed (per git history). Cross-references between RFCs use relative markdown links ([topic](../implemented/2026-…-….md)) — never bare prose or numbers — so they are mechanically checkable and survive moves between folders.

When to write one

Write an RFC when a decision is durable (it shapes the codebase beyond a single function or package), contested (there was a real alternative a reasonable engineer might have chosen), and surprising (a future reader would otherwise ask "why on earth is it done this way?"). A proposal for substantial future work starts in proposed/; a decision already made starts in implemented/.

Do NOT write one for a mechanical or local choice (a variable name, a one-file refactor), for anything already enforced and explained by a gate or a convention in AGENTS.md, or for a still-provisional decision tagged TODO(...) in the code — record those as TODOs and promote to an RFC only once they settle. An RFC is never edited into a different decision: supersede it with a new one and cross-link.

Proposed

Title First proposed
Mutation testing as the coverage counterweight 2026-06-11
Deterministic tests, the replay invariant fixture, and race stress 2026-06-11
Architectural conformance — dependency rules and the adapter kit 2026-06-11
API extractor reports 2026-06-11
Supply chain checks and vendor drift verification 2026-06-11
Agent Client Protocol (ACP) support for external editors 2026-06-14
Multiplex concurrent ACP sessions over one connection 2026-06-14
Optional Code Mode — model writes TypeScript against an SDK of all tools 2026-06-15
Runtime schemas for the event vocabulary (Zod vs the merge-extensible-map pattern) 2026-06-16

Implemented

Title First proposed
Vendor Cordis as source, not npm dependencies 2026-06-11
Microkernel: extension via Cordis event taxonomy, one concrete loop 2026-06-11
Event-sourced sessions with derived message history 2026-06-11
Provider-neutral content-block vocabulary owned by dsh-llm 2026-06-11
Custom typed tool-schema DSL instead of schemastery 2026-06-11
Tool schemas are part of the system-prompt assembly 2026-06-11
Mechanical quality gates over prose guidelines 2026-06-11
tsdown for JS bundling instead of dumble 2026-06-11
Runtime arg validation at the model boundary 2026-06-11
Dev-mode invariants over compile-time deep-readonly 2026-06-11
Property-based testing for protocol-shaped code 2026-06-11
Doc-sync enforcement 2026-06-11
Markdown cross-link validity linting 2026-06-18
Structured error taxonomy 2026-06-11
Capability seams — interface / implementation / consumer split 2026-06-13
Two LLM adapters as a design-verification twin 2026-06-13
Session persistence as an abstract service over SessionEvent 2026-06-14
Every session event is enclosed in a turn 2026-06-15
pnpm as the package manager instead of Yarn 4 2026-06-16
Rich ACP bash rendering — the terminal card (_meta) and command classification 2026-06-18

Rejected

Title First proposed
Deep-readonly public surfaces 2026-06-11