Skip to content

Cordis tutorial

You need a clone of this repository with dependencies installed; the development guide lists the prerequisites. No API key is needed for this tutorial; every example runs keylessly.

Terminal window
git clone https://github.com/deepseek-ai/deepseek-harness.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:

Terminal window
mkdir -p tmp/cordis-tutorial
cd tmp/cordis-tutorial

Every chapter runs the same command from this directory:

Terminal window
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.

  1. Your first plugin — a plugin is a function; the loader mounts it.
  2. Lifecycle and effects — Cordis-managed registrations are undone when their plugin unloads.
  3. Services — expose a capability on ctx and depend on it with inject.
  4. Events — typed events, broadcast dispatch, and the waterfall short-circuit.
  5. Configuration — validated config from cordis.yml, failing loud on bad input.
  6. Composition and HMR — the config file as a plugin tree, hot reload, and diagnosing a plugin that never loads.
  7. Into the harness — register a model-callable tool against real harness services.

The examples use three TypeScript features beyond ordinary modern JavaScript:

  • Type annotations describe values without changing runtime behavior: ctx: Context says that ctx has the Cordis context API, who: string accepts text, and string[] means an array of strings.
  • import type { Context } from '@deepseek-ai/cordis' imports only type information. It vanishes at runtime, so a plugin file that needs Context solely for annotations adds no runtime dependency.
  • Declaration merging (declare module '@deepseek-ai/cordis' { ... }) adds your entries to interfaces that Cordis already declares — for example the type of a new ctx.greeter property 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 fields a schema validates. You can copy those declarations as shown; the surrounding text explains what each one connects.