DeepSeek Harness SDK is a plugin-based agent harness on vendored Cordis: everything is a plugin. Read docs/architecture.md before changing packages/; follow docs/AGENTS.md for documentation.
Remove this section at the first tagged release. With no external consumers, prefer the correct foundation over compatibility shims: rename or repackage freely and update every reference together. Backends reject old on-disk formats. SQLite uses monotonic SCHEMA_VERSION; dsh-session keeps SESSION_FORMAT_VERSION at 0 with no compatibility promise.
vendor/ Vendored Cordis source — manifest + sync procedure in vendor/README.md
packages/ @deepseek-ai/dsh-<pkg> workspaces at packages/<group>/<pkg>/
core/ product API spine: session, system-prompt, tools, agent, agent-loop
prompt/ workspace instructions
llm/ LLM seam + the DeepSeek adapters (hand-rolled + pi-ai design twin)
bash/ bash executor seam + local impl + model-facing bash tools
fs/ filesystem seam + local impl + policy gate + read/write/edit tools
skill/ skill provider registry + local impl + catalog/loader tool
web/ web seam + search/fetch providers + model-facing web tools
compact/ compaction seam + basic backend
context/ request-context plugins
subagent/ subagent seam + spawn/fork/ACP backends + delegation tool
workflow/ workflow seam + worker-thread engine + the workflow tool
todo/ the todo_write tool
guard/ loop-hygiene plugins
cordis/ self-referential toolset: the agent inspects/mounts plugins in its own runtime
hooks/ Claude Code / Codex hook bridges + shared wire-protocol library
session-persistence/ persistence seam + JSONL/SQLite backends
ui/ ACP/TUI/JSON-RPC bridges; boot, approval, interaction plugins
examples/ demo bundles (agent-spine + TUI/CLI/ACP/JSON-RPC bins) leaves load
support/ dev/test infrastructure packages
util/ zero-dependency utilities
python/ Python SDK and bundled runtime (see python/README.md)
native/ node-addon-landlock-run source of record (see native/README.md)
examples/ Runnable cordis.yml leaves over packages/examples bundles (see examples/AGENTS.md)
.agents/ Agent workflows and Agent Notes (`notes/`)
docs/ architecture, generated catalogs, postmortems, cookbook (see docs/AGENTS.md)
scripts/ repo gates and generators
website/ VitePress projection of selected bilingual docs/ sources
Package groups: packages/README.md.
pnpm install # pnpm workspaces, node ^22.19 || >=24
pnpm run test # vitest unit tests
pnpm run test:coverage # THE gating test run: per-file 100% coverage on packages/*/*/src
pnpm run test:e2e # real-API tests; self-skip without DEEPSEEK_API_KEY
pnpm run test:snapshot # keyless ACP/headless/TUI replay vs expected outputs; filter: -t <name>
pnpm run test:snapshot:record # re-record expected outputs (needs key)
pnpm run typecheck
pnpm run lint
pnpm run duplication # cross-file TypeScript clone detection
pnpm run build # tsc emits lib/types, tsdown bundles runtime
pnpm run hygiene # knip + publint + workspace constraints + NodeNext consumer check
pnpm run doc-sync # all documentation gates; see the doc-sync script in package.json
pnpm run website:build # VitePress build (doubles as the site's dead-link check)
pnpm run demo:headless "task" # one-shot agent (needs DEEPSEEK_API_KEY)
pnpm run demo:tui # full-screen TUI coding agent (needs DEEPSEEK_API_KEY)
pnpm run demo:cordis # self-referential demo: the agent modifies its own runtime (needs key)
pnpm run demo:acp # ACP server agent (needs DEEPSEEK_API_KEY)
When required gh, pnpm, build, test, or generator commands fail because the agent sandbox blocks credentials, network, IPC, file watching, or nested sandbox-exec, retry unchanged with the narrowest host escalation before diagnosing authentication or project failure. Require sandbox evidence; never bypass genuine test failures or the product sandbox under test.
Run narrow checks during implementation and this CI-equivalent sequence before marking a PR ready. Fresh worktrees need pnpm run build before publint and NodeNext inspect lib/:
set -euo pipefail
pnpm run typecheck
pnpm run lint
pnpm run duplication
pnpm run test:coverage
pnpm run test:snapshot
pnpm run doc-sync
pnpm run website:build
pnpm run verify-module-graph
pnpm run build
pnpm run hygiene
DSH_EXAMPLE_MODE=lib pnpm exec vitest run --config vitest.e2e.config.ts examples/headless-agent/tests/keyless-smoke.e2e.ts examples/tui-agent/tests/tui-keyless-smoke.e2e.ts packages/examples/cli-demo/tests/built-bin.e2e.ts packages/examples/acp-demo/tests/built-bin.e2e.ts packages/ui/jsonrpc/tests/built-scope-carrier.e2e.ts packages/workflow/workflow-workerthread/tests/built-worker.e2e.ts packages/code-runtime/code-runtime-worker/tests/built-lib.e2e.ts
test:coverage, not test, is the gate (why); report only commands actually run.
Real-API tests and demos read DEEPSEEK_API_KEY, optional DEEPSEEK_BASE_URL, and root .env. cordis.yml allows !!js (never !js) only under plugin config; Loader metadata is static, so conditional composition uses overlays (primer). Never commit credentials. CI e2e skips without a key; testing.md owns key policy.
@deepseek-ai/dsh-<name>; vendored packages keep upstream names and are private: true. cordis is a peerDependency (+ dev) of every harness package."type": "module"). Cross-package imports use package names; in-package relative imports include .ts. CI subprocesses that boot examples or Cordis configs run built lib/ under plain Node; only explicit source-path regressions use tsx (testing policy).ctx.effect() / ctx.on(); a registry's register() returns the disposer.@mode and payload @param; scoped keys absent from payloads need @dshScopeScan unsupported. Public service methods document parameters and non-void returns.assertNever; merge-extensible unions fall through a documented default.next() to delegate; returning without it is the veto (semantics).agent-loop requires updating docs/architecture.md.resolve(request): Spec step in the owning implementation, never a hidden ?? default inside run() (the dsh-bash request/spec split is the template).Config fields changeable from cordis.yml; a DEFAULT_* constant or test seam is not configurability. Protocol constants, external specs, and security invariants stay fixed.Branded<B> from dsh-brand), never bare string.catch names what it swallows and why nothing else can reach it; keep the try to one statement.generic/terminal/diff, locations); presentation methods are pure functions of args (cookbook).FIXME/TODO/XXX by urgency (semantics).git diff --check (pre-push) gates it.Read docs/defensive-patterns.md before lifecycle, concurrency, subprocess, or teardown work.
Everything compiles under strict: true with noImplicitAny; every remaining any explains why a narrower type is infeasible. Every module and export has concise JSDoc for its non-obvious contract; function-like exports include @param/@returns, as enforced by verify-export-jsdoc. Heritage-declared members, plugin-protocol slots, and constructors keep their docs at the declaring seam, protocol, or class.
Comments and docs preserve complete contracts and non-obvious orientation, not reasoning transcripts. Do not narrate control flow or tests, preserve review history, or restate code. Keep factual clauses affecting behavior, failure, timing, ownership, or safe use; link aggressively to owning rationale. Use dsh-prose-standard for prose decisions. Wire mechanically checkable invariants into an executed top-level gate and prove each new or changed acceptance path rejects an invalid case. Use narrow justified exceptions instead of disabling a rule globally.
Docs accompany every code change: update affected README/JSDoc contracts together; update both sides of a bilingual pair and re-record it (i18n contract). Current-state prose, one physical line per paragraph, one home per fact, and word budgets live in docs/AGENTS.md.
CLAUDE.md symlinks AGENTS.md at root, packages/, and examples/; edit the real file. Keep each rule self-contained while linking high-level docs. Condense when clarity survives; raise a verify-doc-budgets ceiling when the contract genuinely needs more space.
vendor/ packages are pinned source copies (manifest with upstream SHAs in vendor/README.md). Update via the sync procedure there; re-apply or retire the logged local modifications; rerun pnpm run test && pnpm run build.