ds-review-bot delta-round finding, verified: cordis hands the carrier to listeners as `this`, and the event declarations type it Scoped<Agent> — so driving the subject through it (this.send(...) in an agent/* listener) is a SUPPORTED shape. The withProps-based carrier delegated gets with the PROXY as receiver, so ReactLoopAgent's send/steer/cancel — which read the native-private #carrier through a getter — threw TypeError when called that way (private members do not exist on proxy receivers). scopeTarget now builds its own proxy: overlay props (the composed filter and the carrier mark) answer from a null-shadowed literal via hasOwn (`in` would let Object.prototype's toString/constructor shadow the subject's), every other get delegates with the BASE as receiver (getters see the real object) and returns functions bound to the base (method calls execute on the real receiver), sets land on the base. A proxy-invariant guard reports frozen own function props unchanged (binding them would violate the get invariant). This kills the class at the seam — any subject with native privates works, today's agents and whatever carries them next — instead of patching the one #carrier field. Pinned both ways: a scope.spec matrix (native-#private method/getter through the carrier mutates the real object; set delegation; frozen-own-prop invariant; overlay non-shadowing) and the bot's exact end-to-end scenario (an agent/session-start listener calling this.send drives a real turn) — both fail with TypeError against the withProps carrier.
Packages
Harness packages, all under the @deepseek-ai/dsh-* scope. Each package is a Cordis plugin (microkernel-style): it exports either a default Service subclass or a functional plugin, declares its ctx key/events through declaration merging, and exposes extension points through ctx.effect(), ctx.on(), and ctx.waterfall(). Authoring conventions: AGENTS.md (subtree) and the root AGENTS.md § Conventions.
Hierarchy
Packages are grouped by modular role at packages/<group>/<pkg>/. The group directory is a pure container (no package.json of its own); the package name stays @deepseek-ai/dsh-<pkg> regardless of group. Each group README is the canonical per-package map — package roles, ctx keys, and the product-vs-support split live there, next to the code.
| Group | Role | Release expectation |
|---|---|---|
core/ |
Product API spine: session, system-prompt, tools, agent, and the concrete loop | Product — stable surface |
llm/ |
LLM capability family: the abstract service + provider adapters | Product — stable surface |
bash/ |
Bash capability family: the executor seam, a local impl, and the model-facing tool | Product — stable surface |
code-runtime/ |
Code-execution capability family: the abstract runtime seam for model-written programs | Product — stable surface |
fs/ |
Filesystem capability family: the abstract seam, a local impl, and the model-facing file tools | Product — stable surface |
compact/ |
Compaction capability family: the abstract seam + a basic backend (tool deferred) | Product — stable surface |
subagent/ |
Subagent capability family: the provider-registry seam and the model-facing delegation tool | Product — stable surface |
web/ |
Web capability family: the abstract seam, search/fetch provider impls, and the model-facing web tools | Product — stable surface |
todo/ |
Todo/planning family: the model-facing todo_write tool (whole-list task tracking on the session log) |
Product — stable surface |
hooks/ |
Hook bridges + the shared Claude Code / Codex wire-protocol library | Product — stable surface |
session-persistence/ |
Persistence capability family: the seam + JSONL/SQLite backends | Product — stable surface |
ui/ |
Editor/client integration surfaces (the ACP bridge) + the app packages | Product — stable surface |
support/ |
Dev/test/example infrastructure (invariants, replay adapter, subagent mock) | Support — lower compatibility expectations |
util/ |
Low-level zero-dependency utilities shared across groups (the Branded<B> primitive) |
Support — small, stable, harness-dep-free |
The split is the point: a package's group says whether it is part of the product API or support/test/example infrastructure, so release and removal decisions do not treat every package as an equal public contract. New packages join an existing group; adding a new top-level group is a deliberate act (extend the group READMEs and this table).
Dependencies
The inter-package dependency graph is generated: docs/module-graph.md (pnpm run gen-module-graph, freshness-gated in CI).
The rule it must obey: extension plugins depend on interfaces, never on the concrete loop. dsh-agent-loop is swappable — UI/hook/tool plugins keep working against the dsh-agent vocabulary if the loop is replaced. The sanctioned exception is a composition/bundle package like dsh-agent-core, whose whole job is to assemble the concrete spine: it depends on dsh-agent-loop (and the other concrete spine plugins) on purpose. The rule constrains plugins that EXTEND the system, not the bundle that COMPOSES it — swapping the loop means shipping a different bundle, not rewiring every extension. A swappable capability splits into interface / implementation / consumer packages (the bash trio is the template — see capability seams).
Each package has its own README.md with purpose, service API, events, extension points, and deliberate non-goals (TODOs).