SnackOnAI Engineering | Senior AI Systems Researcher | Technical Deep Dive | September 15, 2026
The Promise
The composability story is real and formally grounded, and the architecture doc tells you exactly where it is switched off. Reading those two things together changes which profile you should deploy.
What this covers: the Cordis substrate, the profile and bundle layering, the turn flow and its waterfall contract, the session log invariant, and the plugin supply chain. What this excludes: Agent Teams, the Electron desktop build, and the Python SDK internals.
What It Actually Does
DeepSeek Harness, dsh, is an MIT-licensed agent harness from DeepSeek AI. Model-agnostic, plugin-based, runs with npx @deepseek-ai/dsh web. It is explicitly a developer preview, and the README says so in capitals: there will be compatibility-breaking changes.
The claim is "everything is a plugin," and it is meant literally. The model adapter is a plugin. So is the tool registry, the session log, and the agent loop itself. The architecture doc puts it plainly: there is no privileged core to patch.
Underneath sits Cordis, a TypeScript meta-framework formalized in A Programming Paradigm for Spatiotemporal Composability by Yifan Shi of Peking University and DeepSeek-AI, Wei Zhang of Peking University, and Tianyi Cui of DeepSeek-AI. It is a cs.PL paper, not a model paper, and it gives the system two properties with names:
Revertible effects. Every context transformation carries an inverse the runtime holds. Unload a plugin and every registration it made unwinds. That is temporal composability.
Reactive coeffects. Every context change is classified against a component's declared requirements, which drives whether it activates or deactivates. That is spatial composability.
Both are mediated through a single unified context type, which the paper calls the context paradigm, and the payoff is an observational equivalence: effects from distinct components interleave without disturbing one another.
That is a stronger guarantee than any other agent framework currently offers, and it is worth taking seriously. Then read the profile section.
The Architecture, Unpacked

Caption: Focus on the profile table in the second box and the invariant in the last. The first tells you where composability is switched off, the second is the only structural control on what a plugin can show the model.
Three decisions carry this design.
One, reversibility is the primitive. Most plugin systems let you register things and hope teardown is correct. Cordis makes every registration an effect with a held inverse, so unloading is total by construction rather than by discipline. That is what makes runtime swapping safe enough to build a product on.
Two, composition is data, not code. A profile is a list of bundles plus patch files. dsh --profile web --dump-config prints the entire tree, and any printed row can be replaced by a patch of your own. There is no plugin registration API to learn because there is no code path to intercept.
Three, the log is the context. deriveMessages() projects model history from the session log, and every assistant/message embeds the exact compact timed stream that produced it. Fork, resume, transcripts, telemetry and persistence all derive from the same durable settlements rather than from parallel bookkeeping.
The Code, Annotated
The layering that decides what you can change
# A running dsh is composed at boot from ordered layers. See yours:
dsh --profile web --dump-config
# Layers apply to an empty entry list in this order:
# 1. each bundle in the profile's listed order
# 2. the profile's cordis.patch.yml
# 3. the home-level cordis.patch.yml
# 4. any --patch overlay
# A patch targets a row by id and REPLACES its whole config, or inserts rows.
# ← THIS is why there is no plugin API: extension is config reconciliation,
# not a registration call you have to find the right hook for.
dsh web # deliberate alias for --profile web
dsh --profile headless # one-shot runner, no server
dsh --profile sdk # JSON-RPC server
dsh --profile acp # automation-only ACP server
# Custom profiles default to LIVE patch reload. Of the five shipped
# profiles, only `web` is live. The other four apply all layers once at
# startup, because replacing a one-shot or stdio application's dependencies
# after it owns work would invalidate that lifecycle. ← see Insight One
Caption: The composability the Cordis paper formalizes is fully available in exactly one shipped profile, and the doc is honest about why. Check which profile your deployment uses before believing the hot-reload story applies to you.
The waterfall contract, and the way plugins break it
// Six events in the turn flow are waterfalls. A listener that wants the
// chain to continue MUST call next(). One event, agent/turn-stopping,
// is serial and has no next() at all.
ctx.on('agent/pre-step', async (agent, next) => {
const decision = await next() // ← forget this and the chain
// stops here, silently
if (!decision || decision.type === 'reject') return decision
// Wrapping listeners must PRESERVE the original decision's fields.
// startsRequestSeries in particular: drop it and the loop will not log
// a fresh request/header, and the prompt consolidation path changes.
return { ...decision, messages: rewrite(decision.messages) }
// ^^^^^^^^^^^ ← THIS is the trick the docs call out explicitly
})
// The six waterfalls: agent/pre-step, agent/request, llm/stream,
// tools/pre-execute, tools/execute, tools/post-execute
// The one serial: agent/turn-stopping
//
// A rejected or empty first claim closes a DURABLE turn with no step.
// Cancellation during agent/request or prepareCall commits neither the
// system prompt nor the accepted user messages. Retries do not repeat
// assembly or agent/pre-step.
Caption: Reconstructed from the documented turn flow. Six places where a missing next() produces no error and no step, and a spread operator is the difference between a correct wrapper and a subtly broken one.
The invariant that constrains every plugin
// From the architecture doc, verbatim in spirit:
// "Model-visible means logged. Anything that reaches a model request
// must be reconstructable from the log, and a runtime invariant
// asserts it."
//
// Practical consequence: you cannot add context to a model request by
// writing to some scratch buffer. A new model-visible input REQUIRES
// extending SessionEventMap and rendering from the log.
declare module '@dsh/session' {
interface SessionEventMap {
'my-plugin/injected-context': { text: string; origin: string }
}
}
// ← THIS is the security property nobody is discussing. See the Takeaway.
// A plugin with ctx can do a great deal. What it cannot do is put text
// in front of the model without that text becoming a durable, exportable
// session event that fork, transcripts and telemetry all read.
Caption: Most agent frameworks let any component append to the prompt. This one asserts at runtime that it cannot happen off the record, which turns an architectural rule into an audit guarantee.
It In Action
Input: you want tool calls to a particular MCP server to be denied during a specific agent's turns, without forking the agent loop.
Step one, find the row. dsh --profile web --dump-config prints the composed tree. The tool registry appears as a row with an id, contributed by dsh-base.
Step two, write a patch, not a fork. A cordis.patch.yml at the profile or home level targets that row by id and replaces its config, or inserts a new row beside it mounting your plugin. No core file is edited, which is the entire point of having no privileged core.
Step three, register on the right seam. A model-facing capability registers on ctx.tools, and its schema automatically joins prompt assembly. You do not separately tell the prompt about it.
Step four, intercept at the documented point. Guarding execution means listening on tools/pre-execute, one of the six waterfalls, and either returning a denial or calling next() to delegate.
Step five, the effect unwinds. Because registrations are Cordis effects, unloading your plugin removes the tool, the guard and the prompt schema entry together. There is no teardown function to write and no partial state to clean up.
The numbers that matter here are structural rather than temporal. Seven documented ctx service keys. Three event domains. Six waterfall events plus one serial. Five shipped profiles, of which one reloads live. Three roles required before something counts as a seam, since the doc is explicit that a Service Definition, a Service Provider and a Consumer are all needed and one role alone is not a seam.
That last rule is the most useful thing to take from the doc. It rules out the most common agent-framework mistake, which is shipping an interface with exactly one implementation and calling it pluggable.
Why This Design Works, And What It Trades Away
It works because reversibility was solved before extensibility was offered. Cordis holds an inverse for every effect, so plugin unload is complete rather than best-effort, and that is what makes it defensible to declare the agent loop itself a plugin. A framework without that property cannot honestly make the same offer.
It also works because Cordis is not new. It already powers the Koishi chatbot framework, so the substrate arrived with production mileage that the harness did not have to earn.
What it trades away:
Hot reload, in four of five profiles. Insight One.
Comprehensibility. The architecture doc opens by recommending you use an agent to explore the codebase. That is a remarkable sentence in a human-facing document, and the doc's density backs it up: a single paragraph on the turn flow covers request series, prompt consolidation, attempt reconciliation and freeze provenance. AGENTS.md exists specifically for agent readers. The extensibility surface has outgrown the documentation format.
Stability, explicitly. Developer preview, with compatibility-breaking changes promised in capitals. Building a product on this today means accepting rewrites.
Silent failure in the waterfalls. Six events where a missing next() produces no error, just no step.
The plugin supply chain. Insight Two.
Technical Moats
The moat is not the plugin architecture. Plugin architectures are old, and anyone can write a registration system.
The moat is the reversibility metatheory and its implementation. The paper's contribution is a calculus of dynamic composition whose metatheory carries composability from a single component to a whole system of interleaved components. Building that correctly means holding an inverse for every effect, tracking dependencies for activation and deactivation, and proving the interleaving does not interfere. Cordis does the tracking and reversal automatically, and getting that right is years of work that the harness inherited rather than funded.
The second moat is the session format discipline. Committed generation paths are never renamed, replaced or deleted. A read open migrates in memory and publishes nothing. A write open encodes, verifies, and exclusively publishes a version-named successor beside the unchanged source. Each migration package owns exactly one vN to vN+1 step. That is storage-engine engineering applied to agent transcripts, and it is the part nobody copies because nobody notices it until their sessions become unreadable two releases later.
The third is enforcement tooling. A script named verify-application-entrypoints classifies every package bin, executable source and root demo, and rejects any Node application path that bypasses dsh. Architectural rules that are only written down decay. Rules with a failing check do not.
What is deliberately not a moat: the harness is MIT, and DeepSeek published the theory rather than keeping it.
Insights
Insight One: the headline composability property ships in one profile of five, and it is the one you do not run in production.
The Cordis abstract lists hot module replacement as a capability of the declarative component loader. The harness architecture doc then states which profiles get it:
Profile | Layer behavior | Typical use |
|---|---|---|
| live patch reload | interactive |
| applied once at startup | automation |
| applied once at startup | automation |
| applied once at startup | automation |
| applied once at startup | automation |
One of five. Twenty percent. And the four without it are precisely the automation, one-shot and stdio profiles that real deployments use.
The stated reason is good engineering: replacing a one-shot or stdio application's dependencies after it owns work would invalidate that lifecycle. Correct, and the honesty is worth crediting.
But it reframes what you are buying. Reversible effects and reactive coeffects remain true everywhere, because they govern composition. What changes is whether composition happens once or continuously. In four of five profiles, dsh is a very well-founded static composition system, and the runtime swapping story is a development affordance rather than a production one.
There is a second carve-out in the same section. sdk-minimal is described as the deliberate exception that owns its complete explicit tree and does not apply dsh-base. So the uniform layering has one documented hole too. Neither fact is hidden. Both are absent from every summary of this project I can find.
Insight Two: everything is a plugin, plugin discovery is a GitHub topic, and the adjacent literature already has a body count.
Read these three facts consecutively.
The harness has no privileged core. A plugin receives ctx and registers effects on the same footing as the model adapter and the agent loop. It is not sandboxed from the harness, it is the harness.
Discovery, per the README, is: add the dsh-plugin topic to your repository. Installation runs through dsh plugin, backed by pnpm and a private store. There is no curation layer, no signing, no review queue, because there is no marketplace yet.
And SoK: Agentic Skills, a cs.CR systematization from February, documents the ClawHavoc campaign in which roughly 1,200 malicious skills infiltrated a major agent marketplace, exfiltrating API keys, cryptocurrency wallets and browser credentials at scale.
The harness ships a SAFETY.md and the README tells you to read it before running the project, which is more than most projects do. But a safety notice is documentation, and the failure mode above is distribution. The property that makes this architecture elegant, that a plugin is indistinguishable from core, is the same property that makes a hostile plugin indistinguishable from core.
This is not a prediction of doom. It is an observation about sequencing. The plugin ecosystem is being seeded now, with a GitHub topic as its index, while the security literature for exactly this pattern was published six months ago. Whoever builds the curation layer for dsh-plugin is doing more for this project than most feature contributors will.
Takeaway
A hostile plugin in this architecture can do a great deal. What it cannot do is put text in front of the model without that text becoming a durable session event.
The architecture doc states the rule in three words and one sentence: model-visible means logged. Anything that reaches a model request must be reconstructable from the log, and a runtime invariant asserts it. Adding a new model-visible input therefore requires extending SessionEventMap and rendering from the log.
Read that next to Insight Two and something unexpected falls out. The invariant was written for a different purpose, which is making fork, resume, transcripts, telemetry and persistence all derive from one source rather than from parallel bookkeeping that drifts. It was an engineering-consistency rule.
It is also an audit control, and a stronger one than the safety notice.
In most agent frameworks a compromised component can append to the prompt and leave nothing behind, because the prompt is assembled in memory and the transcript is written separately. Contamination and record are different code paths, so one can lie about the other. Here they are the same path by assertion. A plugin that poisons a prompt produces evidence in the session log, and that log is what fork, transcripts and telemetry already read.
The general lesson is worth more than the specific case. A system where the record is derived from the same structure the behavior is derived from cannot misreport itself, and that property is usually a side effect of caring about consistency rather than a security feature anyone set out to build. If you are designing an agent system, deriving the transcript from the request rather than writing it alongside costs you almost nothing and buys you an audit trail that survives a compromised component.
Most teams write the log next to the prompt. Write it underneath instead.
TL;DR For Engineers
Everything is a plugin, including
ctx.agentLoop. Cordis holds an inverse for every effect, so unloading unwinds every registration rather than relying on teardown discipline.Live patch reload ships in
webonly. The other four profiles,headless,sdk,sdk-minimalandacp, apply all layers once at startup.Six turn-flow events are waterfalls requiring
next(), and wrapping listeners must spread the original decision or silently dropstartsRequestSeries.Model-visible means logged, asserted at runtime. A new model-visible input requires a new session event type, which makes off-the-record prompt contamination structurally impossible.
Plugin discovery is a GitHub topic. The cs.CR literature already documents roughly 1,200 malicious skills in one agent marketplace, so the curation layer is the missing piece.
Explain It Like I'm New
Software that uses AI to get work done needs moving parts around the model. Something to talk to it, something to run the tools it asks for, something to remember the conversation, something to decide when the work is done.
Most systems build those parts into a core and let you add extras around the edges. The core is privileged. You can extend it, but you cannot replace it.
DeepSeek Harness takes the opposite position. Every part is the same kind of thing, a plugin, including the piece that decides what the model does next. There is nothing in the middle to protect.
That is easy to state and hard to make safe. Pieces that can be added at any moment can also be removed at any moment, and removal leaves debris. A plugin registers something, gets unloaded, and the registration lingers.
The underlying framework requires every change to come with its own undo, which the system keeps. Removing a plugin genuinely removes everything it did. A paper published alongside the code works out why that composes correctly when many pieces do it at once.
The wider significance is about what counts as infrastructure. As these systems do real work, the interesting questions stop being about the model and start being about whether components swap without breaking each other, and whether you can prove what the system showed the model. Both are ordinary engineering problems, which is a sign the field is maturing.
See It In Action
The architecture document (docs/architecture.md) is the primary source for everything in this issue, including the turn flow, the profile table and the logging invariant. Dense to the point of difficulty, and it opens by recommending you use an agent to read the codebase.
The Cordis primer (docs/cordis-primer.md) is the prerequisite. A plugin is any object implementing
Service, in three interchangeable shapes, and understandingctx.effectbefore anything else will save you an afternoon.dsh --profile web --dump-configis the fastest way to understand the system. It prints the composed plugin tree, and every row it prints is something you can replace with a patch file.The Cordis paper (arXiv 2608.25512) is a cs.PL paper with a real metatheory, not a system description. Read section one for the two dimensions of composability even if you skip the calculus.
Koishi (repo) is the chatbot framework Cordis already powers. The best evidence that the substrate works, because it has been carrying a different product for years.
Community Conversation
The code shipped before the theory. DeepSeek Harness was open-sourced on 13 August 2026. The Cordis paper reached arXiv on 26 August, thirteen days later, having lived in a plain GitHub repository under the Cordiverse organization in between. The lineage is Koishi, then Cordis, then Harness, then the formalization, which is the opposite of how the paper reads.
A cs.PL paper from a frontier lab is itself the signal. DeepSeek published a programming-languages contribution alongside a product release, with academic co-authors from Peking University. That is a different kind of output from the model papers the lab is known for, and worth noticing as a statement about where they think the hard problems are.
The developer-preview warning is unusually direct, in capitals in the README, with a safety notice you are told to read first. Compare against the usual practice of shipping an agent framework with a quickstart and no caveats.
The plugin ecosystem is being seeded through a GitHub topic,
dsh-plugin, plus a Discord. That is the entire discovery mechanism today, which means the window for someone to build curation before the ecosystem is large is open right now.The open question worth pressing on: whether the
agent/*waterfall contract will survive the compatibility-breaking changes. Six events requiringnext()is a lot of surface to keep stable, and every third-party plugin depends on it.
References
A Programming Paradigm for Spatiotemporal Composability, Shi, Zhang and Cui, 2026, cs.PL. Revertible effects, reactive coeffects, and the calculus of dynamic composition behind Cordis
SoK: Agentic Skills, Beyond Tool Use in LLM Agents, Jiang et al., 2026, cs.CR. Seven design patterns for the skill layer, and the ClawHavoc supply-chain case study
From Question Answering to Task Completion: A Survey on Agent System and Harness Design, 2026. The comparative frame for where this harness sits among its peers
SWE-agent: Agent-Computer Interfaces Enable Automated Software Engineering, Yang et al., NeurIPS 2024. The argument that the interface around the model matters as much as the model
Toolformer: Language Models Can Teach Themselves to Use Tools, Schick et al., NeurIPS 2023. Where the tool-registry seam ultimately comes from
ReAct: Synergizing Reasoning and Acting in Language Models, Yao et al., ICLR 2023. The loop shape the turn flow generalizes
MemGPT: Towards LLMs as Operating Systems, Packer et al., 2023. A useful counterpoint on treating the session log as managed memory
DeepSeek Harness is an MIT agent runtime where the model adapter, tool registry, session log and agent loop are all plugins on Cordis, a TypeScript meta-framework whose revertible effects and reactive coeffects are formalized in a cs.PL paper published thirteen days after the code shipped. Its live patch reload ships in one of five profiles, the four without it being the automation ones, and its plugin discovery is currently a GitHub topic search against a threat model the security literature documented six months ago. It matters because its logging invariant, that model-visible means logged and a runtime assertion enforces it, turns a consistency rule into an audit control that survives a compromised plugin.
Keep Going
The habit from this issue: when a project formalizes a property in a paper, check which shipped configuration actually enables it. Twenty percent here, and the architecture doc says so plainly in a table most readers skip.
SnackOnAI runs this teardown weekly on the systems engineers actually deploy, agent runtimes, plugin kernels, serving stacks, and the architecture docs that quietly qualify the abstract. No announcements, no press release summaries. Subscribe at snackonai.com and join 10,000+ engineers reading it.
Forward this to whoever on your team is choosing an agent framework to build on.
Sponsored Ad If you enjoy practical AI insights, check out SnackOnAI and support the newsletter by subscribing, sharing, and exploring our sponsored ad, it helps us keep building and delivering value 🚀
Some teams never seem to stop moving. They're on Attio, the agentic CRM.
Every customer signal is captured in one shared context layer, always current and compounding. Agents and workflows build pipeline, chase every buying signal, and move deals forward, an always-on revenue engine running alongside your team.
With Attio, you’ll get:
Leads automatically prioritised and routed to the right rep
Expansion and risk signals caught the moment they land
Follow-ups written in your voice, already there when you arrive
Teams like Parallel, Turbopuffer, and Wordsmith build on Attio. Are you one of them?


