Files
deepseek-harness/packages/AGENTS.md
T
imccyu 73dbbb751c docs: give architecture review rules a per-artifact home
Move `docs/defensive-patterns.md` into `docs/defensive-patterns/`, one page per
artifact plus a README router, and state each rule as its requirement, the
condition a reviewer judges it by, its boundary and approver, and a correct and
a wrong example.

- `general.md` (the moved page): the existing bug-class rules plus timing,
  value representation, shared-state ownership, decentralization, performance
  evidence, and migrations.
- `package-surface.md`, `remote-and-api.md`, `client-components.md`,
  `conversation-and-session.md`: the review requirements for those artifacts,
  linking type definitions and semantics to `docs/subsystems/` instead of
  restating them.
- `README.md`: the habits behind the rules and the route from artifact to page.
- `dsh-code-review` reads the owning pages before judging a diff; the
  `dsh-architecture-discipline` routing skill is retired in favour of the
  directory, and every inbound reference is repaired.
- Chinese counterparts, pairing records, and the documentation tier table are
  updated together.
2026-10-09 23:03:56 +08:00

6.2 KiB

AGENTS.md — Harness Packages

These package-specific rules supplement the repo-wide conventions.

  • Plugin exports: service packages default-export their service class; function plugins named-export name / inject / Config / apply and have no default export. Mixing the forms makes the Loader discard the function plugin's namespace (postmortem).
  • Optional services use ctx.get(name). Reserve ctx.<name> for declared injections; the property proxy is topology-sensitive, while strict ctx.get reads the global service store (postmortem).
  • Product-visible plugins require a non-unit REAL-composition test. Hand-built ctx.plugin(...) suites are insufficient. Boot test-only cordis.yml through the Loader and app/process; mock only external services or nondeterministic inputs and assert model-visible, durable, or user-visible output. Keep opt-ins out of shipped defaults. Policy.
  • Initiator-owned private chains derive, then capture. Under ctx.agents.withInitiator(), recover the Agent at each orchestration entry, derive agent.session, and let operation-local helpers close over it. Keep Agent and Session explicit at lifecycle, session-log, service, authority, worker/process, persistence, and wire interfaces; do not widen a leaf helper from Session to Context merely to hide a parameter (rationale).
  • Represent one asynchronous operation with one lifecycle controller or transaction. Separate readiness, cancellation, disposal, reservation, or sentinel state requires an independent owner or settlement point; otherwise fold it while preserving rollback, callback containment, and quiescence.
  • Design Service Definitions for all current Consumers. Keep tool-schema, Loader, UI, transport, and provider-specific behavior in the Consumer or provider; do not let one Consumer dictate the service contract (capability-seam rationale). Inverse smell: a public service method with one internal caller — pass a private capability closure instead (RunCodeBridgeOptions).
  • Require a current owner and need. Tie each abstraction, state machine, option, defensive copy, and compatibility path to a current contract or production consumer, and keep behavior in its owning plugin or service.
  • Require evidence for public choices. Configurability does not justify an unsupported default, public operation set, format, or imported external concept. Use current-consumer evidence or relevant prior art; otherwise require an explicit value or defer the choice.
  • Give shared state an owner. Hang shared state on a service or instance. A module-level cache, a singleton, a global WeakMap, or a Symbol.for / globalThis / window.__X__ bypass hides that owner; add no new global current, active, or selection singleton, and derive context from the current scope instead.
  • Keep business rules in their own package. A runtime, controller, manager, gateway, or API dispatch layer carries generic orchestration; a business branch belongs to an independent package and attaches through a registration surface or projected data (where new behavior goes).
  • Write model-facing contracts from the model's perspective. Prompts, tool schemas, results, and diagnostics contain only task-relevant concepts, not UI, transport, or implementation vocabulary. Pin stable model-visible text verbatim and dynamic behavior through snapshots or end-to-end coverage.
  • Enforce a decision in the operation that makes it. Schema omission, prompt filtering, facades, wrappers, and listener order are not enforcement when direct or alternate callers can bypass them; test denial through the executor.
  • Publish state only at its commit point. Emit each notification and update derived state only after the operation succeeds; derive caches, prompts, UI echoes, replay, and query views from one authoritative source.
  • Apply bounds to the complete result. Enforce byte, token, item, and time limits where the complete emitted or retained value, including wrappers and metadata, is known; test tiny and exact limits, oversized single chunks, and multibyte byte limits.
  • Registry contributions prove disposal through the HMR-safety test required by testing policy: dispose the fiber and observe removal.
  • Specs run concurrently in forked workers beside other gate processes. Own each acquired port, path, and child process through teardown; a spec that passes only when run alone is a defect in the spec (execution model).

Naming rules:

  • Package tsconfig: extends tsconfig.base.json (Client: tsconfig.base.client.json), sets rootDir: src and outDir: lib/types, references workspace dependencies, and registers in one aggregate. Packages with distinct Host and Client compiler faces use tsconfig.host.json and tsconfig.client.json leaves plus a solution-only root; ordinary two-entry Client plugins do not split (layout).
  • src/types.ts contains only types — no runtime code.
  • Tests live at package level under tests/, not src/__tests__/.
  • Update package README and JSDoc contracts in the same commit as behavior, and verify them against code with dsh-prose-standard. Group READMEs declare subsystem ownership through a canonical English page link or justified exemption.
  • Package READMEs document model, token, and KV-cache effects using the canonical Model Experience format.
  • Package READMEs put durable consumer gaps and non-obvious maintainer constraints under ## Known Limitations and Deferred Work; ordinary cleanup stays in its TODO or Agent Note. Packages with none use a justified allowlist entry.