Last night, DeepSeek open-sourced “DeepSeek Harness” under MIT license — an agent runtime built around one radical constraint: everything is a plugin. The model adapter, the tool registry, the session log, the sandbox, even the agent loop itself. Within hours the repo passed 33,000 GitHub stars.
I spent the morning reading the source and thinking about what this means for teams like mine that have spent the last year gluing together LangGraph, custom tool registries, and homegrown session state. My take: the “everything is a plugin” idea isn’t new architecturally, but DeepSeek applied it more consistently than any agent framework I’ve seen — and there’s a concrete lesson here even if you never touch their code.
What “everything is a plugin” actually means
Most agent frameworks let you swap the model. Some let you swap tools. Very few let you swap the loop — the control logic that decides “call a tool, read the result, decide what’s next.” DeepSeek Harness treats the loop as just another plugin implementing a small interface, powered by a meta-framework they call Cordis, described as “a programming paradigm for spatiotemporal composability.”
In practice that means you can:
- Swap the model adapter without touching tool code (bring your own Claude, GPT, or local model)
- Replace the tool registry with a company-internal one that enforces your own RBAC
- Hot-swap the session/log plugin to route to your observability stack instead of stdout
- Replace the loop itself — e.g. going from a simple ReAct loop to a planner/executor split — without rewriting tools or the model adapter
Here’s a simplified version of the plugin contract, distilled from the harness’s design:
interface AgentPlugin<T = unknown> {
name: string;
kind: "model" | "tool" | "loop" | "session" | "sandbox";
init(ctx: AgentContext): Promise<T>;
}
// The loop itself is just a plugin
class ReactLoop implements AgentPlugin<LoopHandle> {
name = "react-loop";
kind = "loop" as const;
async init(ctx: AgentContext) {
return {
async run(input: string) {
let state = ctx.session.init(input);
while (!state.done) {
const action = await ctx.model.decide(state);
const result = await ctx.tools.invoke(action);
state = ctx.session.append(state, action, result);
}
return state.final;
},
};
}
}
The key insight: nothing in ReactLoop knows which model, which tools, or which session backend it’s using. It only knows the AgentContext interface. Swap ctx.model for a local model, swap ctx.tools for a scoped internal registry, and the loop code never changes.
Why this matters more than it looks
I’ve built three internal agent stacks in the last 18 months, and the recurring failure mode was always the same: the loop logic and the tool logic got tangled together. Someone adds a “if the tool result mentions PII, redact before logging” rule inside the loop, and six months later nobody can swap the logging backend without also auditing the loop for hidden business logic.
The plugin boundary forces a discipline: the loop only orchestrates, plugins own behavior. That discipline is worth adopting even if you never install DeepSeek Harness itself. If you’re maintaining a Claude Agent SDK or Model Context Protocol (MCP) based stack today, ask: could I swap my tool registry without touching my loop code? If the answer is no, you have the same coupling problem DeepSeek’s architecture is designed to prevent.
A hands-on test: swapping the model adapter
I cloned the repo and ran the quickest possible test — swap the default model adapter for a local one, keeping every tool and the loop untouched:
git clone https://github.com/deepseek-ai/deepseek-harness
cd deepseek-harness
npm install
# harness.config.ts
export default {
plugins: {
model: "./plugins/model-local-ollama.ts", // swapped
tools: ["./plugins/tool-fs.ts", "./plugins/tool-http.ts"], // untouched
loop: "./plugins/loop-react.ts", // untouched
},
};
npx deepseek-harness run --task "list files in ./src and summarize the largest one"
No changes to tool code, no changes to loop code — only the model plugin swapped. That’s the whole pitch, and in this test it held up. For teams evaluating open vs. closed models for cost reasons, that’s a genuinely useful property: you can A/B test model providers on the same tool + loop stack instead of re-plumbing your entire agent every time you want to compare.
Where I’d push back
Plugin architectures trade simplicity for flexibility, and that trade isn’t free. A junior engineer debugging “why did the agent call the wrong tool” now has to trace through three plugin boundaries instead of reading one file top to bottom. If your team is small and your agent does one job, a monolithic loop is often easier to reason about — you don’t need Cordis-level composability to build a support-ticket triager.
The pattern earns its complexity when you have multiple agents sharing infrastructure — different loops, different tool scopes, but the same model adapters and session backend. That’s exactly our situation with three internal agents sharing a common observability pipeline, and it’s where I’ll actually pilot this.
Practical takeaway
You don’t need to adopt DeepSeek Harness wholesale to get value from this release. Audit your own agent stack for one thing: can you swap your model, your tools, and your session backend independently, or are they welded together? If welded, that’s the refactor to prioritize before your next agent project, not after.
Sources: DeepSeek open sources an agent harness where everything is a plugin — The New Stack, deepseek-ai/deepseek-harness on GitHub