DeepSeek Harness Doesn't Bet on AI Understanding Your Code — It Writes the Rules Down
After DeepSeek Harness was open-sourced, I pulled the repository.
The most eye-catching line in the README is, of course, everything is a plugin. Looking further, there are models, tools, Sessions, sub-Agents, terminals, sandboxes — quite a lot of stuff. Under packages/, you can count a total of 219 two-level workspace packages.
But what really made me stop was this unassuming folder in the root directory:
.agents/
notes/
skills/
I originally thought it just contained a few prompt files for Claude Code or Codex. After counting: 11 Skills, 684 English Agent Notes (including archived records), and each Note usually has a Chinese version and paired files.
This is not just "casually writing a few prompts."
I dug deeper and found that DeepSeek Harness is doing something quite rare: it doesn't bet on the Coding Agent understanding the project every time. Instead, it breaks down "how AI should modify this repository" into rules, operational procedures, historical decisions, and automated checks.
To clarify, the repository does not claim that all code is AI-generated. This article discusses how it involves a Coding Agent in development, not assigning an unfounded "AI content percentage" to the project.
What exactly is inside .agents/?
Don't get tangled up by the directory name first.
The main entry point for development standards is actually the root AGENTS.md, not inside .agents/. .agents/ is more like its supporting material: skills/ holds work procedures, and notes/ holds design decisions.
The whole relationship can be compressed into these lines:
AGENTS.md Long-term, always-valid repository rules
*/AGENTS.md Additional rules specific to a certain directory
.agents/skills/ How to do a certain type of task
.agents/notes/ Why it was done that way in the first place
scripts + hooks + CI Checks whether it was done
Separating these things is very necessary.
For example, "New model-visible content must be written to the Session Log" is suitable for AGENTS.md, because it's an architectural requirement that is always valid.
"Which tests to run before pushing" is not suitable for stuffing into every conversation's context; it should be made into an on-demand loaded Skill.
"Why the Session saves the raw assistant/chunk" should also not be written as a long comment next to the code; it belongs in an Agent Note. The code is responsible for telling you how it runs now; the Note is responsible for recording the original trade-offs.
Many teams mix these three types of content into a single super-long prompt. The file gets longer and longer, and when it's time to actually work, no one is willing to read it from the beginning.
AGENTS.md doesn't write "Please write good code for me"
The AGENTS.md in the root of DeepSeek Harness is very long, but it rarely contains unverifiable phrases like "code should be elegant" or "pay attention to best practices."
It writes very concretely. For example:
Registrations are effects.
Model-visible <=> logged.
Plugins, not loop changes.
Non-trivial changes MUST include an Agent Note.
Translating these lines:
- Plugin registrations must be revocable following the lifecycle;
- What the model can see must be reconstructable from the Session Log;
- New behavior should preferably connect to existing extension points, not directly modify the Agent Loop;
- Any change involving behavior, architecture, or cross-package conventions requires a decision record.
My favorite is Model-visible <=> logged.
Agent projects fear one problem most: the model makes a strange decision, you go check the logs, and find that the piece of content temporarily spliced into the Prompt at that time was never saved. Thus, the code, chat history, and the context the model actually saw don't match up, and troubleshooting relies on guesswork.
DeepSeek Harness directly blocks this. As long as content enters the model request, there must be a corresponding Session Event, which can be reconstructed from the log later.
This is a rule that can guide code reviews. If someone adds a new context injection but doesn't design an event, a reviewer can directly point out it's non-compliant, without needing to discuss "whether the log could be improved a bit more."
It doesn't let one file manage the entire repository
Outside the root directory, locations like packages/, docs/, scripts/, examples/, vendor/, etc., have their own AGENTS.md.
AGENTS.md
packages/AGENTS.md
packages/client/AGENTS.md
docs/AGENTS.md
scripts/AGENTS.md
.agents/notes/AGENTS.md
.agents/notes/implemented/AGENTS.md
When modifying a regular package, you don't need to stuff all the rules for the documentation site and archived Notes into the context. Just enter the corresponding directory and read the additional rules there.
This seems ordinary, but it's actually very suitable for large repositories. More AI context is not always better. With too many irrelevant rules, the model will still miss the truly important one.
The repository also links CLAUDE.md to the corresponding AGENTS.md. Claude Code and Codex don't need to maintain two sets of similar specifications that will inevitably become inconsistent after a few months. Rules should ideally have a single source, and tool differences are handled in the invocation metadata.
Skills solve "what to do now"
Opening .agents/skills/dsh-pre-push-checks/SKILL.md, the top looks like this:
---
name: dsh-pre-push-checks
description: Use before pushing, force-pushing, marking ready for review...
---
The description is not introductory text; it tells the Coding Agent when to load this procedure.
What this Skill does is also very practical: first look at the current branch and the full diff, then decide what evidence is needed. If you changed the local behavior of one package, run the corresponding tests; if you changed output visible to the model or user, run snapshots; if you touched exports, bin, worker, or build configuration, add build, hygiene, and built smoke tests.
It also explicitly states not to mechanically re-run the entire repository's tests just because you're preparing to push. CI is responsible for full coverage and platform matrix; local verification should target this specific change.
This is much more useful than a sentence like "Please ensure all tests pass before submitting."
Other Skills are similarly narrow tasks: how to do code reviews, how to maintain documentation, how to archive old Agent Notes, how to record browser GIFs, how to check the repository for over-engineering.
There's another interesting detail. The document translation Skill is set to be explicitly invoked only by the user; the model cannot trigger it itself. The reason is easy to understand: batch translation has a large impact scope and might also invoke models; it shouldn't run just because the AI thinks "let's update it along the way."
To avoid inconsistencies in invocation permissions for the same Skill between Claude Code and Codex, the repository even has a verify-skill-invocation-metadata.ts specifically checking the configurations on both sides.
684 Agent Notes, not 684 development logs
.agents/notes/ is even more worth looking at.
It is categorized by status into four types:
proposed/ Still under discussion, not yet fully implemented
implemented/ Already implemented, and must stay consistent with the current code
rejected/ Seriously considered, but not adopted
archived/ Frozen historical records
Underneath, they are further categorized by feature, bug-fix, architecture, simplification, process, testing.
The basic structure of a Note is not complicated:
# Agent Note: <Title>
Status: implemented
## Problem
## Decision
## Alternatives considered
## Consequences
I think the most valuable part here is not Decision, but the mandatory Alternatives considered.
Anyone maintaining old projects has encountered this: a newcomer proposes an "obviously simpler" modification, the team discusses it for a long time, and finally someone remembers that it was actually tried two years ago and got stuck on a specific edge condition. The code only leaves the final solution; it won't proactively tell later people why that path was a dead end.
For a Coding Agent, this problem is even more severe. It is very good at re-deriving a seemingly reasonable solution based on the current code, but it doesn't know if this solution was just rejected three months ago.
Writing down the failed options and abandoned capabilities is what counts as leaving usable project memory for the AI.
These Notes are not just an ever-growing log that only gets additions. implemented must describe the currently implemented mechanism; if paths, names, or defaults change, it must be updated. Records that have lost maintenance value can be moved into archived, but after archiving they are frozen and can no longer be used as current documentation.
This set of rules has a maintenance cost; 684 is definitely not light. Later I will talk about why I don't recommend ordinary projects copy it exactly. But for an Agent monorepo with 219 packages, it at least solves the problem of design rationale being scattered across PRs, chat histories, and someone's memory.
If AI were to add a new tool, what would it go through?
According to this repository's rules, the Coding Agent should not search for agent-loop and then directly stuff a branch into it.
It first reads the root rules and packages/AGENTS.md, then looks at the architecture documentation and the adding-a-tool cookbook. Next, it searches existing Agent Notes to confirm whether this capability has already been discussed and which extension point it should connect to.
The tool itself needs to consider more than just an execution function. The capability seam here usually needs to distinguish between Service Definition, Provider, and Consumer. New Schemas or contexts visible to the model need to enter the Session Log; parameters come from model JSON and must be validated at this untrusted boundary; tool results affect the user interface, and it must be determined whether they render as generic, terminal, or diff.
After implementation, local logic is covered by unit tests. As long as model output, tool display, or user flow changes, a keyless snapshot of a real runnable example must also be added. Non-trivial changes simultaneously add or update an Agent Note, clearly writing down why it was connected this way and what was abandoned.
When nearing a push, the pre-push Skill is invoked again, selecting tests based on the diff. On commit, hooks check staged lint, whitespace, translation pairing, and archived files; on push, typecheck runs; CI then takes over coverage, snapshots, build, hygiene, and platform matrix.
Throughout this entire process, the AI will certainly still write wrong code. But it will find it very hard to quietly bypass the architecture, forget design records, or declare completion after only running one convenient unit test.
This is what I understand as AI development standards: not demanding the model behave like a senior engineer who never makes mistakes, but placing it within normal software engineering constraints.
I picked one Agent Note to dissect: ACP Snapshot Testing
The most suitable case study among them is the document .agents/notes/implemented/testing/2026-06-19-acp-snapshot-tests.zh.md.
Its title is "ACP Snapshot Tests, Record Once, Deterministic Replay." I chose it not because the name sounds nice, but because this Note explains a testing design from start to finish: the problem, the solution, the unadopted solutions, and the costs ultimately borne.
It first admits there's a hole in the middle of existing tests
Unit tests can test tool registration, event handling, and branches of a function, but they won't necessarily start the complete Loader, Agent subprocess, and ACP protocol.
On the other side, real API tests, while closer to the product, have two troubles: model output is unstable, and CI might not have an API Key.
So a very typical false green occurs: all unit tests pass, real model tests are skipped due to no key, and as a result, the Loader wiring, protocol output, or built entry point is broken, with no test to tell you.
This is not unfounded worry. The Note directly links to an incident postmortem: a default export caused the Loader to lose a needed inject; local tests didn't catch it, and it was only exposed during real assembly.
It didn't choose "write another smarter Mock"
The solution is to record one real run, then replay the model stream.
During recording, a real API runs the ACP example, saving a normal session.jsonl. This log contains not just model text, but also assistant/chunk, tool calls, tool results, turns, and step boundaries. During replay, cordis.snapshot.yml uses llm-replay to replace the real LLM adapter, but the Loader, Agent Loop, tools, and persistence still use the official composition.
In other words, the test replaces only the most unstable layer. Everything else runs as usual.
The tool-call-turn scenario in the repository is a good way to see this process. The input asks the Agent to execute echo SNAPSHOT_OK; the model first produces a bash tool-call, the real tool returns SNAPSHOT_OK, and then the model outputs DONE. Replay doesn't just write DONE into the expected file; it lets this entire flow run again.
What llm-replay actually does
deriveReplayScript() reads the assistant/chunk from the log, groups them by (turn, step), and ends one model call upon encountering finish. What's obtained in memory is not a vague string, but a script with chunking order:
{ kind: 'chunks', chunks: [...] }
{ kind: 'throw', chunks: [...], message, code }
{ kind: 'hang' }
Normal model streams can be derived from the log. Situations where the model throws an exception before outputting any chunks, the stream hangs, or needs cancellation at a specific time — information that cannot be fully inferred from ordinary chunks — are separately placed into replay.override.json.
After replay starts, each llm/stream call consumes one script entry in order. If the script runs out early, it means the code called the model too many times; if entries remain after the test ends, it means the code called the model too few times. Both cases report errors and won't let the scenario pass silently.
It compares not one snapshot, but two surfaces
The first is the stdout transcript seen by the ACP client, such as initialization responses, DONE in session/update, and the final end_turn.
The second is the re-persisted Session JSONL after replay. It can see tool calls, event order, and turn structures omitted from the protocol output.
Things that change every time, like timestamps, Session IDs, temporary paths, and process IDs, are normalized, but consecutive seq and event relationships are preserved. This way, it won't cause false positives due to different temporary directories, nor will it erase genuine sequence changes.
The Note also seriously wrote "Why other solutions weren't used"
The earliest idea was to hand-write an llm.json containing model chunks. This was later abandoned because real Session logs already contain this data; hand-crafted fixtures would instead drift from product behavior.
HTTP recording tools like Polly, nock, and MSW were also considered but ultimately not adopted. They record adapters and SSE bytes, not the Agent composition Harness wants to verify; if the Provider changes, the recording files and their testing value would change along with it.
There was also a tempting shortcut: inferring whether the model threw an error or was cancelled from turn/end { error }. The Note also rejected this approach because the reason for a turn ending is lossy; a 401, a mid-stream failure, and a cancellation could result in similar outcomes and cannot be guessed.
These "why nots" are more useful than "what library we used." If someone later wants to change the replay to HTTP recording, reading the Note first tells them this debate has already happened.
What this solution bought, and what it cost
The cost is obvious: each scenario needs input, Session log, stdout expected output, and sometimes workspace and override files; recording and refreshing also require someone to seriously review the fixtures.
What it bought is keyless, repeatable assembly testing. CI doesn't need to call a real model to check if the Loader is wired correctly, if tools actually executed, if the Session was persisted as expected, and if the ACP output changed.
It also doesn't pretend to solve all problems. Replay cannot prove that today's real model would give the same answer, so real API e2e tests are still retained; the script binding for concurrent sub-Agents also has clear limitations. Writing out the boundaries is more reliable than claiming "full determinism."
This is where I find the value of Agent Notes: they don't just tell the AI a conclusion, they also tell the AI the scope of that conclusion's applicability.
What I would copy, and what I wouldn't
If I were to add a similar mechanism to my own project, I wouldn't start by creating 684 Notes, nor would I immediately implement bilingual documentation, 100% coverage per file, and dozens of gates.
That's the product of DeepSeek Harness's current scale and risk surface. If a small project copies it exactly, it will just end up with a pile of unmaintained Markdown.
I would copy four things first.
First, separate long-term rules, task procedures, and design reasons. AGENTS.md is not responsible for teaching all work, Skills are not responsible for explaining the entire architecture, and Notes are not written as operation manuals.
Second, narrow rules by directory. The root directory only keeps global requirements; frontend, backend, docs, and scripts each supplement their own constraints.
Third, leave a short decision record for non-trivial changes, especially clearly writing down what was not adopted. Notes don't need to be numerous; preventing the team from stepping into the same pit twice already has value.
Fourth, connect at least one type of rule into CI. Specifications without automated checks quickly become a polite file sitting in the repository.
The minimal directory can actually be very small:
your-repo/
AGENTS.md
docs/architecture.md
.agents/
skills/
pre-push/SKILL.md
code-review/SKILL.md
notes/
proposed/
implemented/
rejected/
scripts/
verify-agent-notes.*
At the start, you might only need two hard rules: which extension point new capabilities enter from, and what tests must prove user- or model-visible changes. Add Skills and Notes as real problems emerge.
In the end, this is the only thing I want to copy
After looking through .agents/, I didn't get a set of "DeepSeek AI coding prompts" that I could directly copy and paste. This is actually a good thing.
What's worth copying from DeepSeek Harness is not a specific Prompt, but its arrangement of different content into different locations: rules go into AGENTS.md, procedures are made into Skills, rationale goes into Agent Notes, and what can be automatically judged is handed to hooks and CI.
No matter how strong the model's capability, it can't inherently know what trade-offs a project has made in the past, nor will it automatically choose the most suitable test. The repository needs to organize this information.
For most teams, there's no need to start with 684 Notes. First write one page of truly enforceable AGENTS.md, create two commonly used Skills, leave one decision template, and let CI reject one clearly non-compliant type of change. That's already much more effective than continuing to pile up prompts.