How they build it: agent-driven development at 39 PRs/day
This chapter is the review's most novel content, because it is the part no product page shows. dsh is a live demonstration of how DeepSeek runs a large monorepo with agents doing most of the work.
Velocity
From git log:
| Metric | Value |
|---|---|
| First commit | b67e81ac97, 2026-06-10 |
| Upstream HEAD | 47f943859b, 2026-08-13 |
| Elapsed | 64 calendar days, all 64 with commits |
| Non-merge commits | 6,684 (~104/day) |
| Total incl. merges | 12,294 |
| Highest PR number | #2521 (~39 PRs/day) |
| Author concentration | one author 34%, top three 58%, ~20 total |
The branch namespaces tell the story: merges come from worktree/* (306) and
codex/* (203) prefixes — parallel git worktrees and Codex-authored PRs — plus
agent/*. A sample subject: "Merge pull request #2512 from
deepseek-harness/codex/2503-english-onboarding-copy". This is a small human
team amplified by a fleet of agents running in isolated worktrees.
The commit-type histogram shows the cost of that speed: 33.6% fix: against
10.3% feat: — 3.3 fixes per feature, a build-then-repair signature
consistent with high-throughput agent generation. The counterweight is
discipline: 94.5% of commits follow conventional-commit format, and the revert
rate is 0.40%.
The .agents/ tree: 28% of the repo, unexplained in the README
2,078 tracked files — 28% of the repository by file count, 22% by bytes — live
under .agents/ and are never mentioned in the README. They are two things:
Agent Notes (.agents/notes/, 2,057 files). A decision-record corpus.
.agents/notes/README.md:5: "An Agent Note records a decision or proposal
that affects this codebase — the why and what we gave up, the parts code and
docs can't carry." Path grammar is
{lifecycle}/{class}/yyyy-mm-dd-topic-title.md with a closed lifecycle
(proposed/implemented/rejected + frozen archived/) and a closed class
set (feature/bug-fix/simplification/architecture/process/testing).
There are 686 English source notes, roughly 714k English words, doubled by
Chinese translations. Writing one is mandatory: AGENTS.md:122 — "Non-trivial
changes MUST include an Agent Note in the same PR; only mechanical/local edits
are exempt." They deliberately declined to automate the trivial/non-trivial
judgment with a CI gate (that decision is itself recorded, in
.agents/notes/implemented/process/2026-07-19-require-agent-notes-for-non-trivial-changes.md:11).
Skills (.agents/skills/, 11 workflows). These are loaded by the harness
at runtime — .agents/skills is a first-class project skill root
(packages/skill/skill-filesystem/src/index.ts:247), so running dsh inside
this checkout auto-discovers DeepSeek's own internal workflows. They are the
most revealing artifact in the repo:
dsh-trim-cot-leakagefights their own model's reasoning leaking into committed prose. Its acceptance test (SKILL.md:12): "could a reader at HEAD, with no access to any session transcript, PR thread, or uncommitted draft, resolve every reference and verify every claim?" It ships tuned regex "recall batteries" from an actual 2026-08 purge, including a Chinese one, and a note that ripgrep skips dot-directories so.agents/was the purge's biggest miss risk (references/recall-batteries.md:7).record-browser-gifmakes a demonstration GIF a merge gate for GUI changes (SKILL.md:14) and forbids fixture fakery: "use a real server ... a real API key, and real model rounds. Never substitute fixture queries, mock transports, synthetic event injection" (:16).dsh-code-reviewrequires that assertions "verify external state, logs, events, or disposal rather than restating the implementation or trusting an agent's report" (SKILL.md:41).
The skills target two vendor harnesses at once — Claude Code and Codex — with
optional agents/openai.yaml sidecars kept aligned by
scripts/verify-skill-invocation-metadata.ts. This is dogfooding taken to its
limit: their internal agent-authoring rules ship in the exact format their
product consumes.
The .agents/ warts
- 22% of repo bytes never ship and no external consumer can use them. The
root package is
private: trueand publishable packages use explicit file allowlists, so.agents/is confirmed repo-only weight — but every clone pays for ~714k words plus their Chinese twins, and the README explains none of it. - The frozen archive is a 428-file link graveyard — 318 of 873 outbound
links in
archived/are dead (36%), by policy: documentation gates skip archived sources (.agents/notes/README.md:42). - Internal infrastructure is annotated as such. An internal telemetry
collector hostname (
.agents/notes/implemented/feature/2026-07-31-web-telemetry-default-mount.md:19), an internal npm registry, and eight Figma design URLs are present and labeled internal — converting hostnames into reconnaissance hints. (No credentials leak: a targeted scan found zero.) - A phantom citation inside the skill that defines the dead-citation test.
dsh-find-simplifications/SKILL.md:12tells the reader to consult "the tests-are-not-golden-truth and Agent Notes-are-not-golden-truth doctrines" inAGENTS.md. Grep for "golden" acrossAGENTS.mdanddocs/returns only that line — there is no such doctrine. It is exactly the class-1 dead citation the neighboringdsh-trim-cot-leakageskill exists to catch, and it is prose, so no link checker can see it.
The documentation machine
The doc system is genuinely more elaborate than most production repos:
- A versioned tier taxonomy with word budgets, machine-enforced by
verify-doc-budgets(docs/AGENTS.md:19-57), and a self-applied anti-slop checklist (:59-71) that forbids status annotations and emphasis inflation — which is whydocs/is nearly free of aspirational language. - Generated catalogs with freshness verifiers: a 3,151-line config catalog that cross-checks the runtime schema against the documented type, a 56-event producer/consumer matrix, a persistence catalog, a graph atlas.
- 220 of 268 package READMEs carry a gate-enforced
## Known Limitations and Deferred Worksection (scripts/verify-package-readme-limitations.ts:15). - A bilingual pipeline: every doc, non-vendor README, and active Agent Note is
a triple (English
.md, Chinese.zh.md, hash-record.i18n.yaml) — 1,078 pairs repo-wide — kept in sync by a custom git merge driver. docs/postmortem/— four incident write-ups whose stated purpose is "why our process let it through" (README.md:5). These are the best warts source in the repo: PM 0001 (an ACP crash that 178 green tests and 100% coverage never caught, because no test used the real load path), PM 0002 (filesystem tools silently disabled by a!!jsexpression in a non-interpolated field), PM 0003 (their own web agent validating a replacement server instead of its own GUI, three mistakes deep), PM 0004 (a Landlock notice misclassifying child exit codes).
The doc machine's blind spot
For all that machinery, the drift we found clusters in the generated and gated docs, not the hand-written ones — the theme developed in weaknesses.html. Additionally:
BENCHMARK.mdis a 3-line pointer with no data, and it is an orphan governed by none of the ~30 doc gates (no.zh.md, absent from every manifest). No benchmark result exists anywhere in the repo.- A
FIXMEships in reference docs (docs/subsystems/llm-streaming.md:597) even thoughdocs/development.md:157defines an openFIXMEas a release-blocker. - Two
TODOs ride inside the generated config catalog (docs/config-catalog.md:672,:709) — source TODOs laundered into published reference docs, invisible to the freshness gate. - The postmortem corpus is invisible on their own website — 85 of 110 English docs reach the published site; the best self-knowledge artifact is among the 25 that do not.
Testing
The test story is strong. 216 of 219 packages have a tests/ directory (the
three without are defensible: a type-only utility, a tiny service seam, a demo).
762 spec files, plus the build scripts test themselves (45 spec files under
scripts/). The seven vitest configs are not redundancy — they are disjoint
lanes separated by cost, credentials, and artifact dependency (.spec.ts unit,
.e2e.ts token-spending real-API, .snapshot.ts replay, three web lanes),
each with an explanatory header. Skipped tests are almost nonexistent: 8 across
the whole repo, 6 of them conditional-on-platform-or-key, and zero .only,
.todo, or .fails. The test-support packages provide a scriptable
OpenAI-compatible mock server and a session-replay harness, and the policy is
sound (docs/testing.md:23: "Mock only the expensive or non-deterministic
boundary ... keep everything downstream real").
The headline coverage gate is 100% per-file — "100% or it doesn't merge"
(vitest.config.ts:269). But it is substantially hollowed out for the
client half: of 69 exclusion paths, 51 are packages/client/*, self-labeled
as debt with four TODO(gui) blocks. One exclusion is a negated glob
(everything except one file). The gate is true for the host/core half and
materially untrue for Client, extensions, self-modification, and the Typert
generator. There are also 631 v8 ignore comments repo-wide (each must carry a
reason, but 631 is a large number against a "100%" claim) and two silent
describe.skip blocks in the least-gated file in the repo, the Typert catalog
generator.
CI and release
CI security hygiene is above average: an explicit, reasoned ban on
pull_request_target (.github/workflows/e2e.yml:20-24), an always()
verdict job so a skipped required check cannot read as passing, and
trusted-branch policy checkout. But the current CI has real gaps:
- Master pushes get almost no hosted validation. Every blocking job is
PR-gated, and the three hosted post-merge reference jobs are switched off
(
serial-linuxandserial-macosareif: false), acknowledged by# TODO(hosted-serial-ci): Re-enable ... before release. There is currently zero hosted macOS signal anywhere. - The blocking Windows signal is Wine-on-Ubuntu, not Windows
(
ci.yml:338-342). The real-Windows job is deliberately non-blocking, so a real-Windows-only regression can merge — for a product that ships a Windows CLI with ACL-based sandboxing.
Release discipline, by contrast, is a highlight. Three independent publish
families (dsh, vendored Cordis, native landlock-run). Publication is decided
per package against the registry by tarball integrity — missing gets published,
identical gets skipped, differing fails the run
(scripts/release/publish.ts:5-8) — and every tarball is installed into a
throwaway consumer outside the repo with the bin driven before release
(scripts/release/verify-packed-install.ts:14-17). There is exactly one
dependency patch in the entire 221-package tree
(pnpm-workspace.yaml:71-72, an additive node-pty env override, not a bug
fix) — remarkable restraint.
The developer-preview churn is visible in the version line: eight
release(dsh) commits landed on 2026-08-13 alone, the base version jumped
0.0.1-rc.5 → 0.1.0-rc.1 the same day (so the rc counter restarted, and
0.1.0-rc.4 never existed), and the "publish publicly" flip
(8c1e8d9890) landed mid-sequence — anyone who installed an early rc got a
different package-visibility contract than later ones.
Process cost
The machinery is not free. There are 158 files under scripts/ (35 verify-*,
17 gen-*, 12 translation-*), a 787-line knip config, an issue-management
system of 1,119 lines for a repo that accepts no external contributions, and a
whole CI workflow whose only job is to reject filenames containing "golden".
Much of it is well-organized (a single run-gates.ts DAG orchestrates the
verify scripts into 14 named modes, with a cycle detector). But the marginal
cost of a non-trivial change is real: source edit, plus an Agent Note, plus its
Chinese translation, plus hash records — three extra files and a translation
review, every time.