Rebuild of the region machinery (PR3) on the post-#904 Typert projection: renderPageRegion/renderInheritedPage live in dsh-typert-generator beside the projection; scripts/gen-cordis-catalog.ts owns the curated SERVICE_PAGE / EVENT_SCOPE_PAGE / SERVICE_WALK_EXEMPTIONS / LINK_MAP partition (fail-loud in both directions, with the independent Context-merge scan backstopping the projection's blind spot), spliceRegion, and the guarded pair auto-record. docs/cordis-catalog/ is deleted: the flat events/services catalogs dissolve into per-page regions and docs/cordis-catalog/core moves to docs/cordis-api/ with the inherited tier as its own generated page. The partition absorbs the post-regrouping surface: ctx.typert → invariants.md, ctx.directoryPicker → workspace.md, skills/* events → skills.md, and the four launcher-provided tui accessor values join the named exemptions.
4.0 KiB
Cordis tutorial
English | 中文
Cordis is the plugin framework underneath the DeepSeek Harness SDK: a small runtime where every capability — tools, LLM adapters, file access, the agent loop itself — is a plugin mounted into a shared context. This tutorial teaches Cordis hands-on: each chapter is a runnable example you build in a scratch directory inside this repository, ending with a plugin wired into real harness services.
The audience is agent developers. You do not need deep TypeScript experience; the TypeScript notes below explain the syntax that may be unfamiliar, and every chapter shows the exact commands and expected output.
If you want the condensed concept reference instead of a walkthrough, read the Cordis primer. The exhaustive API reference lives in the generated cordis-surface regions on the subsystem pages and the Cordis core API pages.
Setup
You need a clone of this repository with dependencies installed — the quick start covers prerequisites. No API key is needed for this tutorial; every example runs keylessly.
git clone https://github.com/deepseek-ai/deepseek-harness-sdk.git
cd deepseek-harness
pnpm install
Create the scratch directory the chapters work in. tmp/ is gitignored, so nothing you write there touches version control:
mkdir -p tmp/cordis-tutorial
cd tmp/cordis-tutorial
Every chapter runs the same command from this directory:
node --import tsx ../../vendor/cordis/bin.js
That one-file launcher (see vendor/cordis/bin.js) creates a root Context, mounts the Loader plugin, and tells it to load ./cordis.yml from the current directory. Everything else — which plugins exist, how they are configured — comes from that YAML file, which you will write in a moment. The --import tsx flag lets Node run the TypeScript files the config points at without a build step.
Chapters
- Your first plugin — a plugin is a function; the loader mounts it.
- Lifecycle and effects — Cordis-managed registrations are undone when their plugin unloads.
- Services — expose a capability on
ctxand depend on it withinject. - Events — typed events, broadcast dispatch, and the waterfall short-circuit.
- Configuration — validated config from
cordis.yml, failing loud on bad input. - Composition and HMR — the config file as a plugin tree, hot reload, and diagnosing a plugin that never loads.
- Into the harness — register a model-callable tool against real harness services.
TypeScript notes
The examples use three TypeScript features beyond ordinary modern JavaScript:
- Type annotations describe values without changing runtime behavior:
ctx: Contextsays thatctxhas the Cordis context API,who: stringaccepts text, andstring[]means an array of strings. import type { Context } from 'cordis'imports only type information. It vanishes at runtime, so a plugin file that needsContextsolely for annotations adds no runtime dependency.- Declaration merging (
declare module 'cordis' { ... }) adds your entries to interfaces that Cordis already declares — for example the type of a newctx.greeterproperty or event name. It generates no runtime wiring; the plugin separately provides the service or emits the event. Chapter 3 shows the pattern in full.
Chapter 5 also uses an interface to describe a configuration object's fields and a generic type such as Schema<Config> to say which object shape a schema validates. You can copy those declarations as shown; the surrounding text explains what each one connects.