Codex vs DeepSeek Harness: I Read Both Source Codes and Ran 150 Benchmarks So You Don’t Have To
Two things happened in August 2026. OpenAI open-sourced the harness that powers Codex under Apache-2.0. DeepSeek released dsh v0.1 under MIT.
Then the comparison articles started rolling in. The consensus was nearly identical across the board: Codex has a mature ecosystem, DeepSeek Harness is more flexible with its plugin architecture.
That statement isn’t wrong. But it doesn’t help you make a decision.
So I did the tedious thing. I pulled both codebases locally and read them line by line. Codex locked to tag rust-v0.150.1. DeepSeek Harness—I read the TypeScript source directly from the installation directory, version 0.1.1-rc.2.
Then I ran five mechanism scenarios through a test environment, 150 real agent runs total, with separate probes for sandbox denial and mid-run steering.
Here’s what the source code revealed, followed by what the benchmarks actually measured.
The 10-Dimension Scorecard
Let’s start with the summary. Tool scheduling: dsh is stronger. Tool inventory: Codex is leaner and sharper, dsh is more comprehensive—depends on which philosophy you subscribe to. Multi-agent: Codex is significantly stronger. Context management: roughly even, with a slight edge to dsh. Sandboxing: Codex is stronger. Observability and replay: dsh is stronger. Model interoperability: dsh wins outright. Prompting and work discipline: Codex is stronger. Extensibility (custom development): dsh is stronger. Failure recovery: dsh has a slight edge.
It’s roughly 5-5. But the decision usually comes down to just one or two of these dimensions.
Multi-Agent: dsh’s Claimed Strength Falls Short
The outside impression is that dsh, being a “recomposable Agent runtime,” should excel at multi-agent scenarios. The source code says otherwise.
Codex has nine production-ready agent control tools defined in a single file: spawn_agent, send_input, send_message, followup_task, resume_agent, wait_agent, list_agents, close_agent, interrupt_agent. Spawning, messaging, appending tasks, waiting, listing, resuming, closing, interrupting—a complete lifecycle management suite. Running codex features list locally shows multi_agent is stable and enabled by default; goals is also stable and default-enabled. Under prompts/templates/goals/, there are three templates: budget_limit.md, continuation.md, objective_updated.md. “Long-running goals + budget caps + continuation” has been productized.
dsh’s control plane has four tools: send_message, interrupt_agent, list_agents, plus report on the sub-agent side.
But dsh has its own elegant touches. Sub-agents come in two semantics: fork and spawn. Fork inherits the prefix of completed turns from the parent session; spawn starts with a fresh context. The distinction is a single boolean on the provider—inheritsParentContext—true on one side, false on the other. There’s also recursive depth budgeting with an assertion cap. The ralph tool does loop orchestration—”spin up a structured-output sub-agent per round with max rounds and handoff word limits”—and workflow handles multi-stage orchestration.
The accurate framing: Codex leads in maturity; dsh leads in semantic clarity and orchestration flexibility.
Codex Has No read_file Tool
I searched for all tool name literals in Codex. No read_file. No grep. No list_dir. Reading files and searching code both go through a single tool: exec_command. The distribution bundle includes a ripgrep binary.
dsh does the opposite: read, write, edit, glob, grep, read_image are all separate tools, plus str_replace_editor.
This isn’t about one approach being crude and the other refined. Codex believes “one shell to rule them all”—narrow tool surface, less selection burden on the model, at the cost of correctness being pinned on command-line string composition. dsh believes “fine-grained tools are more controllable”—each tool’s parameters, errors, and UI presentation can be independently designed, at the cost of the model choosing from more tools.
File editing primitives reflect the same divide. Codex uses an apply_patch envelope (*** Begin Patch / *** Update File: / *** Move to:)—one call can handle multi-file additions, deletions, edits, and moves with high throughput. dsh uses old_str unique matching—zero or multiple hits both error out immediately and feed back to the model. Precise, with straightforward failure messaging.
The Decision Might Come Down to a Single Enum
This is the hardest difference in the source code.
Codex’s WireApi enum has exactly one variant: Responses. wire_api = "chat" errors out at deserialization with a message explicitly saying “no longer supported”—even ollama-chat was removed.
dsh: the DeepSeek adapter POSTs directly to ${baseURL}/chat/completions, plus a pi-ai adapter provides multi-provider routing. The config can directly specify openai, anthropic, or any compatible service with api: openai-completions.
If your model service speaks the OpenAI-compatible chat completions interface, dsh plugs in with zero effort. Codex requires a Responses translation proxy layer.
That conclusion gets a qualification after the benchmarks. More on that below.
Tool Parallelism Implementation
When multiple tool calls appear in the same model response, how are they dispatched?
Codex uses a read-write lock. Tools declare whether they support parallelism—parallel-capable ones grab a read lock and run concurrently; non-parallel ones take a write lock for exclusive execution. Missing declaration defaults to non-parallel. Simple and reliable, at the cost that a single “unsafe” tool degrades the entire batch to serial execution.
dsh is more nuanced. Exclusive calls form barriers; parallel calls enter a bounded rolling pool. Subsequent calls are reclassified before launch—exclusive reclassification waits for the current pool to drain. Dispatching can overlap, but policy evaluation, results, and result context commit strictly in the order the model provided.
One detail reveals the design thinking: on interruption, dsh writes synthetic error results for calls that haven’t been dispatched yet—so the event log remains legal for replay. It fabricates a failure record rather than leaving a “call with no result” gap in the log.
Two Compression Strategies, Two Failure Modes
Both sides have context compression, but with different objectives.
Codex cares about not exceeding the window. The compression threshold counts tokens with a buffer, and the scope can be configured as “entire context” or “only new additions after the compression window prefix.” compaction_image_budget is enabled by default—images count toward the compression budget and old ones are pruned as needed. Engineering built directly around real API billing.
dsh cares about not corrupting history after compression. It maintains a “tool call/result balance” and only allows cutting history at positions where the balance is zero. If a tool/result can’t find a matching call, it throws an error. Overflowing text goes to spill: stored to disk, with only head/tail previews plus a retrieval locator left inline.
Codex prevents out-of-window errors. dsh prevents compression from splitting tool_call/tool_result pairs and making subsequent requests invalid. Both correct; they’re fixing different bugs.
The same logic extends to the session layer. dsh’s append-only event log with pure-function projection isn’t an add-on—it’s an architectural constraint that even interruption and compression must accommodate for replayability. Codex also has JSONL rollout, resume, and fork, but they read more as operational capabilities than architectural non-negotiables.
Sandboxing: Codex Goes Deeper
Codex’s SandboxType has four variants: no sandbox, macOS Seatbelt, Linux seccomp, Windows restricted token. All three platforms have independent implementation files. macOS policies are four separate .sbpl files. The privilege escalation path lives in its own crate.
dsh’s approach shares the same lineage—even the permission vocabulary is identical (read-only / workspace-write / danger-full-access). Implementation uses a platform chain: Linux goes through bwrap then falls back to landlock, macOS uses seatbelt, Windows uses ACL restricted tokens. With multiple candidates, feature probes arbitrate in order. If the platform lacks the chain or all probes fail, execution is denied outright—the command doesn’t run.
One necessary trade-off: dsh makes the sandbox pluggable. You can swap it out. That’s flexibility and simultaneously a risk surface—your sandbox is only as strong as the plugin you’ve installed.
Where Work Discipline Lives
This directly determines “which one works better with the same model.”
Codex has six model-versioned base prompt files: gpt_5_2_prompt.md, gpt-5.2-codex_prompt.md, gpt-5.1-codex-max_prompt.md, and others. They start by declaring identity and capability boundaries, followed by lengthy “How you work” sections that lock down planning, sandbox approval, and output style.
dsh’s built-in identity declaration is a single sentence: You are an AI agent powered by DeepSeek Harness.
This isn’t incomplete. The prompts use an ordered section registry. The order 0 slot is intentionally left for the deployer’s persona—the official design explicitly leaves “who you are and how you work” blank. Real behavioral constraints are pushed down into each tool’s own text—for example, the jobs tool tells the model: keep track of background job IDs, don’t busy-wait, collect outputs with job_output before finishing, kill irrelevant jobs with job_kill.
Codex comes with tuned work discipline out of the box. dsh has a cleaner structure for customizing discipline without fighting built-in prompts.
dsh also has something Codex doesn’t: cordis_define / cordis_run / cordis_stop / cordis_undefine plus three introspection tools—letting the model define, start, and stop plugins within the session. The agent can modify its own runtime. No equivalent in Codex.
Same-Model Comparison Finally Worked
After reading the source, I thought a performance benchmark wouldn’t be feasible. The reason was that enum above: Codex speaks Responses, dsh speaks chat completions. Different protocols mean different models on each side. The measurement would be about which model is smarter, not which harness is stronger.
For this test, I used gpt-5.6-sol, DeepSeek-V4-Pro, Opus 4.8, and GLM-5.3. The actual API endpoint supported both /v1/chat/completions and /v1/responses. So Codex went through Responses, dsh through chat completions, both pointing to the same model ID.
So the conclusion needs a word change. It’s not “Codex can’t talk to your model.” It’s “your model service must provide a Responses-compatible endpoint.” For services with only chat completions, the original conclusion holds. When both protocols are available, Codex can connect directly.
Two integration pitfalls worth documenting.
dsh’s zero-parameter tools get rejected. Tools like job_list and get_goal—no required params in JSON Schema—map to null at the API layer and get rejected by validators: Invalid schema for function 'job_list': null is not of type "array", returning a 400. OpenAI models tolerate it; DeepSeek routing doesn’t. I ended up writing a 40-line local proxy that patches required: [] at the wire layer. Not turning off the tools—that would change the object under test.
Responses routing isn’t available for all models. DeepSeek and Anthropic routing returned high demand errors after five retries. Codex ended up running only two models, compressing eight combinations down to six.
The 150-Run Benchmark
Design principle: test mechanisms, not IQ. Pass/fail had to be deterministic—no subjective scoring.
Five scenarios, 5 runs each, six harness × model combinations = 150 total runs.
Large output: hide a marker inside a 5MB file, verify retrieval after truncation/spill.
Parallel throughput: read 10 independent small files in one go.
Survival after compression: 60 files each containing one integer, sum them, answer is unique.
Infinite loop self-healing: ask it to verify a non-existent token, watch for repeated searches.
Sequential dependency: write a.txt first, then derive b.txt from its content.
Pass/fail checked file contents, the last output line, and wall-clock time. No subjective decisions.
Result: 149/150 passed.
Across all five formal scenarios, neither side showed a persistent “can’t complete” failure. Differences landed on cost and variance.
Median wall-clock times (same model):
The 5× gap in the compression row is the most interesting data point. It validates the “Codex has no read_file” observation. Codex used a single exec_command to aggregate all 60 files—one call, done. dsh used read to fetch them one by one, resulting in a much longer tool-call sequence.
Same philosophical divide, projected onto the timeline. One shell to rule them all is genuinely faster, at the cost of correctness being pinned on command-line string composition and intermediate steps being un-auditable. Fine-grained tools are slower, but every step leaves a trace in the event log. Whether you care more about wall-clock or replayability isn’t answered in the source—it depends on what you’re building.
The one actual failure was dsh + GLM-5.3 + parallel, hitting 121 seconds without retrieving all 10 tokens. 1/100 jitter—not enough to support any conclusion. But dsh’s standard deviation in parallel and large-output scenarios (23.7s, 16.4s) was significantly higher than Codex’s (3.3s, 7.9s). A single run win doesn’t mean much—this is why.
Two Supplemental Probes
Sandbox denial and mid-run steering weren’t included in the 150-run statistics. Reporting them separately.
Sandbox denial: denial path measured; recovery path not measured. Running Codex in true read-only mode without bypass parameters, asking it to write a file—the system rejected the write. Logs explicitly say patch rejected: writing is blocked by read-only sandbox. Final response was BLOCKED; target file confirmed not created. Denial path works. Whether it can recover through approval or privilege escalation remains unverified.
dsh supplemental probe never reached model execution, returning dsh: TRANSPORT: Connection error. dsh’s denial behavior, file state, and recovery capability can’t be concluded from this run. Source shows read-only / workspace-write / danger-full-access permission layers—but source capability isn’t runtime evidence.
Mid-run steering: no actual run result. Source and existing tests confirm both sides have real-time entry points: Codex via app-server’s turn/steer; dsh via Agent Inbox / Web Host API with mode: "steer". But I didn’t complete the actual API-driven re-test for the same active turn on both sides. So “interface exists” can’t be written as “steer succeeded.”
These two probes don’t join the 149/150 pass rate. Particularly for mid-run steering—implementation entry points confirmed, actual tests not yet completed.
Which One to Choose
Choose by your use case, not by name recognition.
Choose Codex if you: just want to get repository work done; need to run untrusted code on macOS/Linux with kernel-level sandbox boundaries; require productized features like long-running goals, budget caps, multi-agent collaboration; don’t want to write your own work discipline; care about wall-clock time—under the same model it runs 5× faster on compression-heavy long-context tasks.
Choose DeepSeek Harness if you: need to connect models that don’t speak Responses (unless your service provides a Responses-compatible endpoint); are building your own agent product and need to swap models, tools, sandboxes, even the agent loop; require full-trace replay for observability; can accept longer tool-call sequences in exchange for every step being auditable.
Install both—they don’t conflict. Config files don’t interfere. Use Codex for daily delivery, wrap dsh around web and headless flows. Reports already indicate dsh can call Codex as a sub-agent—the boundaries between harnesses are blurring anyway.
Quick Operations Checklist
-
Read source to identify decision points: Codex locked to tag rust-v0.150.1; dsh source at~/.dsh/profiles/node_modules/@deepseek-ai/—each package has src/ and Chinese READMEs. -
Check your model service’s API protocol: chat completions only → dsh plugs in directly. Responses only or both → Codex can connect. Responses routing isn’t available for all model backends. -
Watch for dsh zero-parameter requiredfield: missingrequired: []on parameterless tools gets rejected by some model services—add a proxy patch or fix the tool definition. -
Performance depends on scenario: compression-heavy long-context tasks: Codex is ~5× faster. Fine-grained tool scenarios: dsh offers stronger auditability. Variance data shows dsh single-run volatility is higher. -
Sandbox capability verification: Codex read-only denial path confirmed via probe. dsh sandbox is plugin-based; actual strength depends on chosen plugin and platform probe chain. -
Multi-agent maturity: Codex productized; dsh’s fork/spawn semantics clearer but fewer tools. -
Work discipline: Codex has pre-tuned built-in prompts; dsh’s persona slot is intentionally blank, with behavior constraints pushed down to tool-level descriptions.
FAQ
Q: Can I install both Codex and dsh side-by-side?
Yes. Config files don’t interfere. Use Codex for daily delivery, wrap dsh for web and headless flows. Reports already exist showing dsh calling Codex as a sub-agent.
Q: My model service only supports chat completions. Which one do I choose?
dsh. Codex’s WireApi enum has only the Responses variant. Setting wire_api = "chat" errors out at deserialization.
Q: dsh zero-parameter tools error out. How do I fix it?
Patch required: [] at the wire layer. The original used a 40-line local proxy. Don’t turn off the tools—that changes the object under test.
Q: Which one is faster?
Depends on the scenario. Compression-heavy long-context tasks: Codex runs ~5× faster. Large output, self-heal, sequential dependency: the gap is smaller. But dsh’s variance is significantly higher in parallel and large-output scenarios.
Q: How do I choose between sandbox implementations?
Codex has platform-specific independent implementations—macOS with separate .sbpl policy files, privilege escalation in its own crate. dsh sandbox is a plugin with a platform chain that arbitrates in order. Choosing dsh means your sandbox strength depends on which plugin you’ve installed.
Q: Should I read the source first or run benchmarks first?
Read the source first. It tells you whether mechanisms exist and how they’re designed, so you know what to measure. Then run benchmarks to see how much the difference actually is. The 5× wall-clock gap wasn’t visible from source alone—source only said “leaner vs more granular.”
Q: Codex doesn’t read files, it uses exec_command. Is that safe?
It’s a philosophical choice. Codex believes “one shell to rule them all,” bundles ripgrep. Correctness rides on command-line string composition. dsh uses separate tools—every operation is auditable with straightforward error messages—but call sequences are longer.

