Files
deepseek-harness/docs/rfc
Tianyi Cui c658f4d155 fix(hooks): address Codex review — tighten codec to the reference schemas, preserve stdout
Codex's PR-E review found three protocol-fidelity blockers + two doc gaps, all
verified against ~/repos/refs:

- (A) Top-level `decision` accepted allow/deny/ask, but both reference schemas
  reserve those for hookSpecificOutput.permissionDecision — the legacy top-level
  decision is approve/block ONLY. Split topLevelDecisionOf (approve/block) from
  permissionDecisionOf (allow/deny/ask), so an out-of-band {"decision":"deny"} is
  now invalid and ignored instead of becoming a real blocking decision.
- (A) hookSpecificOutput was parsed without its hookEventName discriminator.
  HookOutput now surfaces hookEventName so a bridge can discard a block whose
  claimed event doesn't match the firing one (the schemas key the block by event).
- (A) runHook discarded raw stdout. HookOutput now carries `stdout` (trimmed,
  verbatim) so a bridge can reproduce CC's plain-stdout rendering / Codex's
  plain-stdout-as-additionalContext behavior.
- (B) hook/* SessionEventMap variants were only named in prose; added a payload/role
  table to core-data-structures/session.md (a maintained catalog surface).
- (B) Removed PR-stack-position references (PR-F / "future bridge packages") from a
  test comment and the RFC, per the current-state-wording rule.

New codec tests: top-level allow/deny/ask invalid+ignored, hookEventName capture,
raw stdout preserved on plain + JSON + empty stdout. 51 tests, per-file 100%.
2026-07-01 01:12:04 +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

Every RFC has two axes, both encoded in its path{lifecycle}/{class}/yyyy-mm-dd-topic-title.md:

  • Lifecycle (the top-level folder) is the RFC's status, and an RFC moves between folders as that 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, and is kept current with what actually shipped: when the code later moves a file, renames a package, or changes a key/default, the RFC is updated in the same change to match (facts only — paths, names, structure — not the decision itself). See implemented/AGENTS.md.
    • rejected/ — the proposal was considered and declined. Kept for the record so the rejection isn't re-litigated.
  • Class (the nested folder) is the kind of decision — see Classification below.

The date in the filename is when the topic was first proposed (per git history). Cross-references between RFCs use relative markdown links ([topic](../../implemented/architecture/2026-…-….md)) — never bare prose or numbers — so they are mechanically checkable and survive moves between folders.

Classification

Each RFC is filed under exactly one class — the kind of decision it records. The class is encoded in the path (the folder is the label, so a file's location declares its class) and the set is closed: scripts/verify-rfc-classification.ts rejects any folder outside the set and asserts this index lists every RFC under the heading matching its path. Adding a new class means amending that gate and this section, not just dropping a new folder. See the classification RFC for why the taxonomy is path-encoded and gated.

Class What it covers
feature A new user- or model-facing capability.
bug-fix Corrects a defect or closes a gap a postmortem surfaced.
simplification Removes code, behavior, or surface area without adding a capability.
architecture A structural decision about the shipped source — how packages relate, what the runtime vocabulary is.
process Tooling, policy, or workflow around the code — gates, the package manager, vendoring — not runtime behavior.
testing Test infrastructure and strategy.

The architecture / process line: architecture is about the source we ship; process is the surrounding tooling and workflow. (refactor is deliberately absent — it overlaps simplification, whose discriminator, "does observable behavior change?", already covers it.)

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/. Pick the class folder that matches the decision (see Classification).

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. (Editing an implemented/ RFC to track where its already-made decision now lives — a moved file, a renamed package — is not a different decision and is required, not forbidden; see implemented/AGENTS.md.)

Proposed

Feature

Title First proposed
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
Compaction as a capability seam (abstract contract + basic backend) 2026-06-18
Pre-tool input rewrite — a consistent design 2026-06-30

Simplification

Title First proposed
Unify the agent id and the session id 2026-06-20
Stop mirroring durable boundaries as agent events 2026-06-20

Architecture

Title First proposed
Runtime schemas for the event vocabulary (Zod vs the merge-extensible-map pattern) 2026-06-16
Extract a generic long-running tool runtime 2026-06-20

Process

Title First proposed
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
Discover package inventories instead of maintaining static lists 2026-06-20

Testing

Title First proposed
Mutation testing as the coverage counterweight 2026-06-11
Deterministic tests, the replay invariant fixture, and race stress 2026-06-11

Implemented

Feature

Title First proposed
Rich ACP bash rendering — the terminal card (_meta) and command classification 2026-06-18
Subagent capability seam 2026-06-21
ACP subagent backend (out-of-process delegation) 2026-06-22
The todo_write tool — model task list as event-sourced session state 2026-06-29
Interception seams — the typed-Decision surface a hook programs against 2026-06-30
Subagent lifecycle enrichment — agentType + lastAssistantMessage (observe-only) 2026-06-30
dsh-hook-protocol — the shared Claude Code / Codex hook wire-protocol core 2026-06-30

Simplification

Title First proposed
Drop the mutable session summary 2026-06-19
Drop unconsumed assembled LLM convenience surfaces 2026-06-20
Drop the unconsumed llm/adapter-change event 2026-06-20
Prune dead methods from the persistence seam 2026-06-20
Keep one public stop primitive 2026-06-20
Fold trace-only session facts into load-bearing events 2026-06-20

Architecture

Title First proposed
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
Runtime arg validation at the model boundary 2026-06-11
Dev-mode invariants over compile-time deep-readonly 2026-06-11
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
Shared persistence write coordinator 2026-06-18
Agent lifecycle and ownership seams 2026-06-18
Session surface — a linked list over the event log for LLM message derivation 2026-06-18
Reorganize packages into a modular hierarchy 2026-06-20
Branded IDs everywhere they belong 2026-06-20
Extract example apps into packages 2026-06-20
Event-domain semantics — session is the fact log, agent is the live surface 2026-06-30
stdin + extra env on the bash seam — a trusted-plugin surface 2026-06-30

Process

Title First proposed
Vendor Cordis as source, not npm dependencies 2026-06-11
Mechanical quality gates over prose guidelines 2026-06-11
tsdown for JS bundling instead of dumble 2026-06-11
Doc-sync enforcement 2026-06-11
pnpm as the package manager instead of Yarn 4 2026-06-16
TSC-first build and one tsconfig 2026-06-17
Markdown cross-link validity linting 2026-06-18
Core-data-structures catalog and the ts type-equiv drift gate 2026-06-20
Generated cordis events + services catalog 2026-06-20
Classify RFCs by kind via path-encoded subdirectories 2026-06-20

Testing

Title First proposed
Property-based testing for protocol-shaped code 2026-06-11
ACP snapshot tests — record-once / replay-deterministic 2026-06-19
Real-API e2e in CI against the external DeepSeek API 2026-06-19
Use session.jsonl as the only snapshot session-log artifact 2026-06-20
Per-session snapshot replay for nested agents 2026-06-22
Persist the seed boundary so fork-child replay routes correctly 2026-06-22
Record fork and mixed spawn+fork snapshot scenarios 2026-06-22

Rejected

Simplification

Title First proposed
Persist assembled assistant messages, not stream chunks 2026-06-20
Drop ACP session/load until resume has a product shape 2026-06-20
Drop ACP terminal _meta rendering 2026-06-20
Drop bash full-output spill files 2026-06-20
Drop durable step boundary events 2026-06-20
Drop unused session lineage metadata 2026-06-20
Fold the persistence interface into dsh-session 2026-06-20
Collapse tool-owned UI presentation 2026-06-20
Retire mid-turn steering 2026-06-20
Return the ACP bridge to one live session per connection 2026-06-20
Truncate interrupted final turns on load 2026-06-20

Architecture

Title First proposed
Deep-readonly public surfaces 2026-06-11
Make the shared example base providerless 2026-06-20