Files
deepseek-harness/docs/cookbook/adding-a-package.md
imccyu ec601ca13d build(vendor): rescope the vendored Cordis packages into @deepseek-ai
Machine-produced by `pnpm run rescope-vendor --apply` plus the regeneration it
prints: `pnpm install` for the lockfile, `pnpm run gen-third-party-notices`,
`verify-translation-pairing --write` for the touched bilingual pairs,
`gen-doc-graphs`, and one typert snapshot whose ids embed character offsets.
`pnpm run rescope-vendor --check` verifies the result.

Renames nine vendored packages (cordis, cosmokit, schemastery and the six
@cordisjs plugins) and every reference that resolves them: manifest names and
dependency keys, module specifiers including declare-module merges, cordis.yml
plugin names, tsconfig paths, every Markdown fence, and `docs/` prose.
Directory names, upstream versions, and dependency ranges are unchanged, so
vendor/README.md still reads as an upstream snapshot; its manifest table gains
an upstream-name column so THIRD_PARTY_NOTICES keeps MIT attribution pointed
at each fork's origin.

The tutorial tier follows the rename end to end: its yaml fences named plugins
the Loader can no longer resolve, its `ts ignore-check` fences disagreed with
the compiled fences beside them, and its prose quoted both. The contracts that
told readers to keep upstream names — the root convention and the vendoring
cookbook's tree comment and manifest invariant — now say to rescope instead.

Two rules read `@deepseek-ai/` as "another workspace plugin": the client bundle
purity gate now names the vendored libraries a browser bundle inlines, and the
files where a bare `cordis` is an agent-preset id keep that product data.
2026-08-10 22:04:13 +08:00

7.8 KiB

Cookbook: adding a workspace package

English | 中文

The file-by-file checklist for a new @deepseek-ai/dsh-<name> package. This checklist is validated against the bash and adapter packages as templates; if it drifts from them, fix it here.

1. Create the package

packages/<group>/<pkg>/
  package.json     # copy from packages/core/tools, adjust name/description/deps
  tsconfig.json    # extends ../../../tsconfig.base.json, rootDir src,
                   # outDir lib/types, references: ../../../vendor/cosmokit,
                   # ../../../vendor/cordis (+ ../../../vendor/schemastery if
                   # you use Config, + ../../<group>/<dep> for each dsh dep)
  src/index.ts     # service default export or plugin (name/inject/apply/Config)
  README.md        # service API, events, extension points, design notes,
                   # + gated Model Experience context blocks or short form
                   # + the gated "Known Limitations and Deferred Work" section
                   # (or a whitelist entry in scripts/verify-package-readme-limitations.ts)

Choose an existing group when one matches the package's role (core, llm, bash, compact, subagent, todo, session-persistence, ui, util, or support). A new group is allowed, but it is a pure container: no package.json, no source files, and packages still sit exactly one level below it.

package.json invariants (enforced by pnpm run constraints / scripts/check-workspace-constraints.ts): private: true, a version matching the root package.json, type: module, main: "lib/index.js", types: "lib/types/index.d.ts", exports["."].types: "./lib/types/index.d.ts", exports["."].default: "./lib/index.js", @deepseek-ai/cordis in BOTH peerDependencies and devDependencies (same range). Mirror every dsh peer dependency in devDependencies. @deepseek-ai/schemastery goes in dependencies (it is a runtime validator), matching agent-loop. The files list contains exactly lib/index.js, lib/invariant.js, lib/types/**/*.d.ts, and package-specific runtime artifacts recognized by the gate; a package whose runtime export points into the emitted tree also includes lib/types/**/*.js. Do not publish src, declaration maps, JS maps, or stale root declaration files. CLI app packages with a package bin include lib/bin.js immediately after lib/index.js in files.

In-package relative imports use explicit .ts specifiers in source (for example, export * from './types.ts'). The compiler rewrites those to .js in emitted JS and leaves explicit .ts specifiers in declarations, which standard NodeNext/Node16 TypeScript consumers resolve to the sibling .d.ts files.

2. Register it in the root configs

File Change
tsconfig.base.json no edit for an existing group; for a new group, add a ./packages/<group>/*/src candidate to the @deepseek-ai/dsh-* wildcard
tsconfig.host.json (Host package) or tsconfig.client.json (Client package) add { "path": "./packages/<group>/<pkg>" } to references — an ordinary package belongs to exactly one aggregate, never both. api/remotes uses a repository-specific split because the Host generates a contract that the Client consumes in a later phase; new packages must not copy it (layout)
knip.json only if the package has entrypoints that repository discovery does not already cover

A packages/client/* package additionally extends tsconfig.base.client.json instead of tsconfig.base.json, and a client plugin package declares dsh.client in package.json, exports ./client, and calls the shared tsdown preset (packages/client/tsdown.client.ts) — see packages/client/AGENTS.md for the client-side contract.

Covered automatically by globs or package-manifest discovery — no edits needed: root package.json workspaces, scripts/publint-all.ts, tsdown.config.ts, .oxlintrc.json, scripts/check-workspace-constraints.ts.

3. Decide the package topology

For a swappable capability, separate Service Definition / Service provider / Consumer roles into packages when they evolve independently (see docs/architecture.md § "Capability seams" — the bash trio is the template). A single-purpose plugin stays one package.

4. Write the package README

Keep package-specific service API, config, events, extension points, and design notes first. The limitations section records durable consumer gaps and non-obvious maintainer constraints owned by this package; ordinary cleanup stays in its source TODO or Agent Note. An indirect Model Experience sentence may name the consumer that surfaces this package's contribution, but it does not restate that consumer's implementation. End a package README with this canonical sequence:

## Model Experience

### Request surface and condition

#### What the model sees

The exact data-dependent fields, an anchored generated-catalog link, or an introduction to the verbatim literal below.

##### Verbatim text for this field, when needed

```markdown
Stable system-prompt prose of any length, or another long non-generated literal, copied exactly from source.
```

#### Token effect

Fixed, conditional, retained, replaced, capped, or zero-direct token effect.

#### KV Cache effect

Append-only, prefix-stable, replacing, or independent behavior, including the exact conditions that may invalidate reuse.

## Known Limitations and Deferred Work

- **Consumer-visible gap** — exact missing operation or case, its consequence, and any maintainer constraint.

Fill Model Experience from the implementation. Use one H3 per direct, conditional, capped, lifetime, or auxiliary-model surface, with the three ordered H4 fields shown above and one prose paragraph under each. Quote stable text owned by the package: system-prompt prose goes in a titled H5 plus markdown fence under the field that introduces it—normally What the model sees—other short literals stay inline with named placeholders, and other long literals use the same nested form. Summarize only data-dependent or provider-owned text. A tool-schema surface links its anchored section in the generated tool catalog and states only deltas absent there. Keep prompt and schema surfaces separate when scoping can hide one without the other. In KV Cache effect, distinguish append-only growth, a stable repeated prefix, replacement of earlier request tokens, and an independent model request, then name the package-owned changes that can invalidate reuse. “Does not invalidate” means the package preserves an already-reusable prefix; provider cache availability and eviction remain outside the package contract. The prose standard governs completeness and ownership; the verifier enforces the required section structure.

A package with no context effect or one consumer-owned path uses the audited None, as or Indirectly, through sentence in SENTENCE_MODEL_EXPERIENCE, followed by a KV Cache effect H4 and one non-empty paragraph; a model-agnostic generic package may instead join NO_MODEL_EXPERIENCE_SECTION. Do not expand either case into a description of another package's work. The limitations allowlist is independent. The Model Experience Agent Note records the rationale.

5. Verify

pnpm install        # registers the workspace
pnpm run doc-sync
pnpm run constraints && pnpm run typecheck && pnpm run lint
pnpm run build && pnpm run hygiene

Follow the repository testing policy for the behavior-specific checks and coverage required by the new package.