How we use design docs to build ArchDocs with coding agents
An agent hit a bug, worked around it and kept the lesson to itself. An hour later the same bug made 102 of 127 imports fail. Here is how the design doc turned that into something the next change can use.
- Author
- The ArchDocs team
- Published
- Reading
- 17 min read
On November 1 the coding agent drafting one of our design docs hit an error. The editor refused its markdown with Invalid collection of marks for node text: bold,code, because a piece of inline code sat inside bold text. The agent rewrote the sentence to avoid the problem, wrote itself a note about it in a memory file on that machine, and carried on.
About an hour later, the same agent ran the feature it was building against 127 of our own design documents. 102 of the 127 imports failed with the same error.
This time the problem landed somewhere other people could see it. Within fifteen minutes the design doc's Work Log held the blocker, the fix, a note that the fix was outside the agreed plan, and a lesson proposed for whoever touches that editor code next. The workaround in a private note helped one agent on one machine. The entry on the design doc is where the next person or agent working on the editor can find it.
When people and agents build software together, the design doc should hold the intent, the decisions, the implementation history and the outcome of a change, and it should hand all of it to whoever works on that part of the system next. Most of the implementation on ArchDocs is done by coding agents, so we built the product to work this way and we use it on our own changes. What follows is one of them, start to finish, with screenshots of the record as it stands.
One record per change
A design doc in ArchDocs has a few parts that do different jobs. The spec says what problem we're solving and what was decided. The implementation plan says how, which parts of the system it expects to touch, and how each step will be checked. The Work Log records what actually happened while the work was underway. The evidence says what shipped, what supports that, where it differed from the plan and what was left undone.

The design doc used in this post. Read the tabs left to right as the life of the change. The header also records how it ended: a person decided it shipped, an agent relayed that decision, and no acceptance criteria were configured.
The split pays off once work starts. The spec and plan record what was agreed, and shipping freezes them; later edits need an amendment with a reason. Everything that happened after agreement goes into the Work Log and the evidence, so the original design and the actual history sit side by side instead of the second overwriting the first.
None of this is for every change. Our agents propose a design doc only when a change crosses a boundary between components, needs someone else's sign-off, will take more than one pull request or session, or adds a dependency, a data store or new personal data. For a change inside one component, a dependency bump, or a copy or config edit, they say nothing about design docs at all.
The change, and the decisions a person made
DD-0022 added a way to import design docs, RFCs and ADRs that teams already have in other tools. The spec's problem statement was specific: until then, every document arrived one at a time as a fresh draft, with no trace of its original author, date or identifier, and running an import twice made two copies. A team that adopted ArchDocs started with an empty history, so search and task context had nothing to work with until people wrote new documents. Our own repository had 110 specs and 176 implementation plans waiting.
The agent drafted the spec. Where it reached a decision it wasn't entitled to make, it raised a tracked question on the doc with options and a preferred answer instead of picking one. DD-0022 had four. Q1 asked whether an agent may create imported documents directly as Shipped, which bends our own rule that a person decides when a design doc has shipped. Aylon, who runs ArchDocs, allowed it for historical imports through one separately authorized code path. Q4 went differently.

The agent framed the trade-off and marked its preference. The answer took neither option, and because it was given on the question, it carries a name and a timestamp.
Most RFCs mix the design and the rollout plan in one page, and the agent asked whether an imported page should land whole or be split into a spec and a plan by AI. It preferred landing whole: predictable, and it works with AI turned off. The answer was to make it a choice the person importing makes. Version 3 of the spec turned that into the design: an import-level setting, "Keep each document whole" or "Split into spec and plan", with a per-row override, offered only when AI is on, and marked "(decided in Q4)". Both of the agent's original options went into the rejected alternatives, and anyone who later wonders why the import dialog has a split setting can read who decided and why.
DD-0022 had no formal approval step. Our organization doesn't require one for a change this size, and the four answered questions were the sign-off. Organizations that want a formal approval step can require one on Business.
What the agent keeps up, and what stays yours
Keeping a record like this by hand would mean narrating every commit, test run and surprise to a document while also doing the work. That's the part we hand to the agent. In our setup the agent is Claude Code with the ArchDocs plugin, connected to ArchDocs over MCP. The plugin's skills tell the agent when a change deserves a design doc and how to write one, what to record while it works, and how to close out. The MCP server gives it the tools and enforces the rules that shouldn't depend on an agent's good behavior.
Here is how the work divides at each stage of a change:
- Before the work, the agent drafts the spec and plan, raises open decisions as questions and fetches related context. ArchDocs refuses an agent's write that has no summary. You answer the questions that set policy.
- During the work, the agent logs each commit, exact test results, deviations, findings and a handoff when it stops. ArchDocs checks commit references against GitHub when it's connected. You read the log when you want to know where things stand.
- At the end, the agent writes the evidence, including what wasn't done. ArchDocs computes acceptance criteria if you configured them and records who decided the change shipped. You decide whether it shipped.
- When the next change starts, the agent asks for task context before planning. ArchDocs returns related records, each labelled with how it was found and how far to trust it. You accept or drop the constraints the agent proposed.
The skills, and the plugin's hooks, guide the agent's side of this. The hooks notice a commit, a test run or a finished subagent and remind the agent when the Work Log is behind; they never write to ArchDocs themselves. DD-0022's log predates them, so every entry in it came from the agent following the skills. The consequential decisions stay with people. An agent can't mark a doc approved or shipped without attaching a statement it quotes as a person's decision, and ArchDocs labels the result as relayed. ArchDocs can't tell whether the person really said it, so an organization that wants that check can require each decision to be confirmed by the person inside ArchDocs.
DD-0022's plan named the three parts of our system it expected to change (the API, the frontend and the API contract), broke the work into twelve tasks, and gave each task its check. Its risks section held things we'd learned the hard way, such as releasing the plugin only after the API deploys, because the skill calls a tool that doesn't exist in production until then. None of that is in the code, so a new session would otherwise find it out by breaking something.
The plan missed something
Task 6 tested the agent path against real input: our own docs/superpowers/ folder, 286 files mapped to 127 documents, imported into a local organization over the real MCP tool. 25 imports succeeded and 102 failed.

Logged as a blocker the moment it happened. The last paragraph connects it to the agent's earlier encounter with the same error while writing this design doc's own spec.
Our design doc editor is built on Tiptap, whose inline code mark excludes every other mark by default. Markdown such as **`createdAt`** failed the editor's schema check, and the whole document was rejected. Built as the plan described, the import refused four of every five real documents.
Nine minutes later the agent logged the fix.

Logged as a deviation because the fix was in a package the plan never mentioned. The entry records what the plan assumed, what was true, what changed and how the rerun went. The "Not found" reference and the correction label are explained in the evidence section below.
The fix also changed behavior outside import: the editor and the agent's own document writes now accept bold or italic code, which is ordinary GitHub-flavoured markdown. The full entry shows the constraint captured from it.
Four minutes after the fix, the agent captured the finding as a constraint attached to the files it governs: any change to the editor's mark set must keep inline code combinable with bold, italic and links, and keep the round-trip test for those cases green. A capture from the Work Log stays proposed until a person accepts it, and ArchDocs labels it "From a Work Log finding, not an approved rule" so nobody mistakes it for policy.
Two smaller surprises followed the same path. Two files contained a NUL character that Postgres refuses to store, which got its own fix, and the third run imported all 127. The Notion source tried to attach images to documents that were already shipped and frozen, so image handling moved inside the import. Both went into the evidence's list of deviations.
A log the next person can use
DD-0022's Work Log ended the build with eighteen entries. They're checkpoints: each commit, exact test counts rather than "tests pass", what a delegated run produced and what the review of it found, and each departure from the plan the agent noticed. The implementation ran through a second agent, with Codex writing code from a work order and Claude reviewing each result, running the checks and keeping the record. Claude kept the record because it was the session reviewing Codex's output.
Two entries record things a reader would otherwise dig out of the code. E-2 ends with a paragraph headed "Calls I made that the plan left open", listing four small product decisions the agent made because the plan didn't, so a person can review and reverse them instead of discovering them in the code months later. E-13 records three failing tests in an older suite that had nothing to do with this change, "so the next person does not mistake them for an import regression."
The log holds what the agent decides to record, and capture is a choice too. A second lesson that day, that our marketing site has tests pinning the docs pages and the number of MCP tools, stayed in a Work Log entry and was never captured as a constraint.
When the agent stopped, it left a handoff.

Each claim under Done cites the entry that backs it. Blocked on names the two decisions only a person could make, and Next says which scripts to run once they're made.
We used that handoff ourselves. When we came back to DD-0022 to write this post and correct its record, the first call was get_journal_handoff. It returned E-17, marked it stale because a later entry (E-18, recording the ship) had been added after it, and reported no open questions.
The evidence
The evidence is where the record says what shipped. DD-0022's has four sections: outcome, verification, deviations and not done.

The verification section separates CI from local runs and labels the dogfood import as reported. Every result here was written by the agent.
DD-0022 used recorded test and CI evidence, without configured acceptance criteria, so ArchDocs computed nothing on its own; the header says so. Because those results are the agent's report, we checked them ourselves with the GitHub CLI. Run 41310251591 on the final commit succeeded: build, unit tests, integration tests, the Docker image and both deploys. Its end-to-end job was skipped, so the "5 of 5" Playwright import suite is a local run the agent reported, not a CI result. The run before it, 41309759807, failed on two marketing tests the agent's local checks hadn't covered, which the Work Log records along with the fix. Both runs are in our private repository, so we can't link them here.
When a change needs more than a report, you can configure acceptance criteria: statements a person authorizes, satisfied by attestations or, on Business with linked pull requests, by facts ArchDocs reads from GitHub. ArchDocs computes each result, and an agent's attestation counts only where the policy allows one.
The ship itself was a person's decision. Aylon said "Ship it and then tell me how I can try out the import on a few docs." The agent marked DD-0022 shipped with that sentence attached, and the header shows it as relayed through Claude Code.
Checking the record for this post turned up one mistake. Every commit the agent logged named the repository archdocsio/archdocs; ours is archdocsio/monorepo. ArchDocs had been checking each reference against GitHub and showing "Not found" next to all of them, and the same wrong name sat on the captured constraint's file paths. Entries and captured file paths can't be edited, so we corrected the record by adding Correction entries and a corrected constraint marked as superseding the original. The original entries are untouched and now say "Corrected by", the corrected references resolve on GitHub, and the supersession takes effect only when a person accepts the new constraint. The correction entry shows both.
The next change starts with what we learned
Suppose the next change to the editor adds a strikethrough mark. It will touch packages/doc-editor/src/extensions.ts, the same file as the DD-0022 fix. That fix is a small extension that lets the code mark combine with bold, italic and links. A change that reorganizes the editor's extensions while adding a new mark could drop it and bring back the exclusion that made 102 of 127 imports fail, and it would also start rejecting the agent's own document writes again. What the next agent needs to know is short: keep the code mark combinable with other marks, keep the round-trip test for bold, italic and linked code green, and test with markdown like **`createdAt`**, because imported documents and agent-written docs often contain it.
When the agent follows the skills, nobody has to point it at DD-0022. Before planning, the skills have it ask for task context with a description of the change and the files it will edit. ArchDocs returns the decisions, constraints, open questions and design docs recorded against those files, with the same labels.
We ran that query after the correction, against the real repository and the two files a strikethrough change would touch. This is a demonstration. No such change has been made.

The constraint comes back first, matched by file path, with its source entry and its current labels.
Before the correction, the same query couldn't match the files and found the constraint third, through text search. Now it's the first result, found by path. The query used no catalog objects; the file paths recorded on the constraint were enough, and catalog objects, when you have them, give the query another way to match. The full result also lists the original capture, labelled as having a newer item that proposes to replace it.
A person reviewing that future change gets the same context and can check the proposed constraint against the implementation before accepting or rejecting it.
Try it on your next meaningful change
Pick one change in your system that crosses a boundary, needs a sign-off or will outlive one session, and run it through ArchDocs:
- Describe it to your agent and let it draft the spec and plan. Answer the questions it raises, especially the ones that set policy, and feel free to pick an answer that isn't on the list.
- While it works, open the Work Log now and then. Look for deviations, the calls it made that the plan left open, and the handoff when it stops.
- At the end, read the evidence. Check what was verified and what was only reported, read what wasn't done, and decide whether it shipped.
- When related work begins, have the agent ask for task context before it plans, and accept or drop the constraints it proposed last time.
Create a free ArchDocs account, then add the plugin in Claude Code:
/plugin marketplace add archdocsio/archdocs-plugin
/plugin install archdocs@archdocs
Run /mcp and sign in to the archdocs server with the same account. Then run /archdocs:design-doc with a sentence about the change you want to make.
Free includes one design doc with the spec, plan, questions, Work Log, evidence and up to ten acceptance criteria, which covers steps 1 to 3, and the agent can capture constraints along the way. Retrieving them with task context (step 4) needs Team, which also adds unlimited design docs and importing the ones you already have. Human approvals, linked pull requests and criteria checked against GitHub are on Business.
More in Architecture as code
Start