dsh.so

Architecture

How DeepSeek Harness is put together — Cordis, profiles, bundles, events, the turn flow, and capability seams. This is a guided tour of the official architecture.md; read the original before changing anything under packages/.

The big picture

Model
Harness (Cordis)
Agent Loop
Plugins [Tools, Skills, Storage…]

A running dsh is a plugin tree composed at boot from ordered layers. There is no privileged core: the model adapter, tool registry, session log, and agent loop itself are all plugins that register services, typed events, and reversible effects on a shared Cordis context — so every part is replaceable from configuration.

Cordis

Cordis is the framework under dsh. Plugins contribute to a shared context, and registrations are effects that unwind when a plugin unloads — this is what makes “everything is a plugin” more than a slogan. You extend dsh by mounting a plugin beside the others, never by patching a core.

Profiles and bundles

  • Profile — a named composition stored in the Harness home. It lists the bundles it stacks, holds any out-of-tree plugins it installs, and keeps the user's own cordis.patch.yml. web and headless ship as templates.
  • Bundle — a distribution format for Cordis config rows and the code they mount. Whatever a bundle inserts stays patchable by the layers above it.

Each declares itself in its own package.json under a dsh field: dsh.profile lists a profile's bundles, and dsh.bundle points at a bundle's patch file.

dsh-base is the first layer of every profile: model adapters, tools, persistence, sandbox and approval policy, settings, credentials, telemetry. dsh-web-app adds the browser application; dsh-headless adds a one-shot runner with no server at all.

Layers apply to an empty entry list in this order: each bundle in the profile's listed order → the profile's cordis.patch.yml → the home-level patch → any --patch overlay. A patch targets a row by id and replaces its whole config, or inserts new rows. See Plugin Development for the full packaging walkthrough.

Core packages

PackageOwnsctx key
core/sessionThe append-only SessionEvent log and in-memory storectx.sessions
core/system-promptPrompt-section and tool-schema assemblyctx.systemPrompt
core/toolsThe scoped tool registry and guarded execution pipelinectx.tools
core/agentThe Agent interface, live registry, and agent/* eventsctx.agents
core/agent-loopThe default driver implementing that interfacectx.agentLoop
core/scopeThe per-agent scoped-registration primitivelibrary, no key
llm/llmMessage and stream vocabulary plus the adapter seamctx.llm

Events are the extension points

Events are how plugins hook in — and picking the right domain is the first decision in most changes:

  • Session events — durable facts appended to the log and broadcast through session/event. Use one when the fact must survive a reload.
  • Agent events (agent/*) — carry a live Agent: inbox, step, status, request, validation, continuation. Use them to observe or intercept work in flight.
  • Capability events — attach policy and adapters to a seam (fs/*, tools/*, telemetry/*) without importing the loop.

The turn flow

A step is one model request plus the tools it calls. A turn is zero or more steps: it opens before its first input is claimed and closes once nothing is owed.

turn flow (simplified)
turn/start
claim next-step input + one queued message
assemble prompt sections + tool schemas
step/start
agent/request -> llm/stream -> assistant/chunk* -> assistant/message
tool/call* -> tools/execute -> tool/result*
step/end
turn/end

turn/*, step/*, user/message, assistant/*, and tool/* are durable session events; the rest are live extension points. Waterfalls (agent/pre-step, agent/request, llm/stream, the tools/* events) must call next() to delegate; agent/turn-stopping is serial and has no next().

Session log & the model-visible rule

The session log is the source of the context the model sees. deriveMessages() projects model history from it, and raw assistant/chunk events preserve replay and UI fidelity. Fork, resume, transcripts, telemetry, and persistence all derive from this stream. The invariant: model-visible means logged — anything that reaches a model request must be reconstructable from the log.

Capability seams

A seam is a swappable capability with three roles: a Service Definition declaring the interface, a Service Provider implementing it, and a Consumer using it — commonly a model-facing tool. One provider swap changes the whole product: filesystem and subprocess providers share one execution world, so pointing them at a remote sandbox moves Bash, PTY, and LSP with them.

Where new behavior goes

GoalMechanism
Add a model providerregister its adapter on ctx.llm
Add a model-facing capabilityregister on ctx.tools; its schema joins prompt assembly
Add shell executionregister a ctx.shell backend
Add a human commandregister on ctx.commands; dispatches without a model turn
Add background workregister on ctx.jobs; job_* tools collect or stop it
Add filesystem access or policyregister a ctx.fs provider or listen to fs/* events

See your own tree

zsh — dsh
$ dsh --profile web --dump-config
# every row it prints can be replaced by a patch of your own
$

This is the fastest way to understand the composition and prototype a plugin.

Join the community

Questions or feedback? Official Discussions is the project’s canonical support channel; Discord has an active community. dsh.so itself improves via plugin submissions and your feedback.