Part 1
Part 1 · Name the disease correctly
1.1 The six diagrams share one structure. That fact itself is a signal
Abstract the six Mermaid diagrams and they are all the same shape:
subgraph 层1 { A }
subgraph 层2 { B }
subgraph 层3 { C, D }
subgraph 层4 { E }
A --> B --> C --> E
Six projects whose stacks, languages, process models, and deliverables are completely different produce diagrams that could be swapped for one another—which means the diagrams carry no project-specific information.
A reliable self-check: cover every label, leave only boxes and lines. If the six diagrams still look the same, none of them is drawn correctly.
Real architectural difference lives in topology: OpenCode is a star—“one server + N clients.” Open Design is a trust split—“three processes + one privileged center.” grok-build is a message topology—“one process + Actor mailboxes.” OpenManus is a type topology—“one inheritance chain + one tool pool.” Those four topologies must not collapse into the same vertical stack.
1.3 The diagrams contain nothing that would start an argument
The value of an architecture diagram is that it carries a judgment someone can challenge. Every sentence on the current diagrams is unfalsifiable description: “tool registry,” “agent main loop,” “model adapter layer”—nobody disagrees, and nobody learns anything.
A good architecture diagram should provoke at least one of these reactions:
- “Wait—why is this synchronous?”
- “This edge crosses a process. What’s the serialization cost?”
- “This state lives on this side. What happens if the other side dies?”
- “There is no line between these two boxes. Do they really not communicate?”
If a diagram cannot provoke any of those sentences, it is decoration.
Part 2
Part 2 · Three questions you must answer before you draw
Do not start drawing. First answer these three questions in prose in a draft. If you cannot write the answers, do not pick up the pen.
Question 1: What question does this diagram answer? (Question)
One diagram answers one question. If you cannot write that question in a single sentence, you have not thought it through.
| ❌ Unqualified question |
✅ Qualified question |
| “Claude Code’s architecture” |
“After the user presses Enter, until the first token appears on screen, which components hold control, in what order?” |
| “OpenCode’s system design” |
“Why can OpenCode let a TUI, a desktop app, and Zed share the same session state?” |
| “What modules does Open Design have” |
“Open Design does not write its own main loop. How does it still keep output quality consistent across 25 third-party CLIs?” |
| “grok-build’s layering” |
“In Goal Mode, how does a goal survive hours and many model calls without being lost?” |
Question 2: Who is the reader, and what decision will they make with this diagram? (Audience & Decision)
| Reader |
Decision they must make |
What the diagram must give them |
| An architect choosing a base for a fork |
Which project to build on |
Where the extension points are, what is hard-coded, blast radius of a change |
| An engineer about to read source |
Which file to open first |
Entry + trunk path + exact filenames; side paths may be omitted |
| A TL assessing risk |
Whether it can go to production |
Trust boundaries, failure paths, state persistence points |
| A product engineer looking to steal a design |
Which pattern is worth copying |
The causal story of that pattern, not a panorama |
The current six diagrams default to serving reader type 4, but their content only half-satisfies type 2.
Question 3: What is this diagram’s load-bearing wall? (Load-bearing claim)
Every diagram must have one core claim. Every other element exists to support it. If you cannot find the load-bearing wall, you are listing.
Verified load-bearing-wall examples (from this repository’s analyses):
| Project |
Load-bearing wall |
Evidence |
| Open Design |
The daemon is the only privileged process—it binds loopback and exclusively owns SQLite / credentials / project files / spawn rights; the web UI is a shell |
项目分析/open-design-源码分析.md:159 |
| Open Design |
Adapters are data, not classes—26 definitions describe only “how to talk to this CLI,” never “what to say” or “how to schedule” |
same document :453 |
| OpenCode |
The server is the product—even an in-process TUI still walks the full HTTP/RPC path, so multi-client is free |
项目分析/opencode-源码分析.md |
| OpenWorker |
Out-of-band approval—permission requests do not block the session; they land in an inbox and a human handles them when free |
项目分析/openworker-源码分析.md |
| grok-build |
A Goal is not a prompt; it is a state machine—plan / execute / verify / strategist-recovery persist as four states |
项目分析/grok-build-源码分析.md |
| OpenManus |
The inheritance chain is a partial order of capability—BaseAgent(loop + stuck detection) → ReActAgent(think/act) → ToolCallAgent(tool parse) → concrete agents |
项目分析/OpenManus-源码分析.md:91 |
Part 3
Part 3 · Six diagram types for agent systems (the core method)
“Architecture diagram” is not one kind of diagram. It is six. Draw them on one canvas and they collapse into a directory tree. This is the most important section of this guide.
Type A · Process and trust topology (Deployment / Trust Topology)
Answers: How many address spaces does the code run in? Who may touch what? How are boundaries crossed?
Must draw:
- Every independent process / address space distinguished with a heavy border (not a casual subgraph ring)
- Every cross-process edge labeled with: transport (HTTP loopback / stdio / Unix socket / IPC file) + synchrony (blocking / streaming / polling)
- Privilege asymmetry: who can read credentials, who can write the filesystem, who can spawn processes
- Network egress: the only component that can reach the public internet (this is the data-exfiltration surface)
Why this diagram should be drawn first: it sets the physical constraints for every later discussion. None of the current six diagrams draws a process boundary at all—OpenWorker’s Rust shell and Python engine are two processes, yet they appear as two boxes side by side, with no hint that a serialization hop sits between them.
Example (Open Design, based on verified facts):
flowchart LR
subgraph BROWSER["① 浏览器 · 无特权"]
UI["Next.js 16 App Router + React 18"]
end
subgraph SIDECAR["② Next.js server 侧车 · 低特权"]
SSR["SSR / 静态资源"]
end
subgraph DAEMON["③ Daemon 进程 · 唯一特权方"]
API["/api/* · 绑 loopback"]
DB[("SQLite
projects · conversations · runs")]
CRED["凭证库"]
SPAWN["子进程 spawn 权"]
end
subgraph CHILD["④ 被 spawn 的第三方 CLI · 独立进程 ×N"]
CLI["claude / codex / cursor-agent …"]
end
UI -->|HTTP| SSR
UI -->|"HTTP · loopback only"| API
API --- DB
API --- CRED
API --> SPAWN
SPAWN -->|"stdio · SSE/JSON-RPC"| CLI
CLI -->|"写文件(不回传内容)"| FS[("项目 cwd 文件系统")]
API -.读取产物.-> FS
Interrogations this diagram immediately invites (that is the value):
- “The third-party CLI is an independent process. Are credentials forwarded by the daemon, or does the CLI hold its own?”
- “The CLI writes the filesystem directly, bypassing the daemon. So lint and review are after-the-fact?”—yes. That is Open Design’s design, and the diagram exposes it.
Type B · Sequence of one turn (Turn Sequence)
Answers: In one interaction, how do control and data flow along the time axis?
The essence of an agent system is a loop, and a loop cannot be expressed by a flowchart—a flowchart can only draw a single pass. You must use sequenceDiagram.
Must draw:
- Loop boundary (loop block)—visually separate “one turn” from “one session”
- What re-runs every turn (context reassembly, tool-set recomputation) vs what is one-shot (session init)
- Back-edge: how tool results enter the next turn’s input
- Early-exit points: which conditions break the loop
Example (Claude Code main-loop skeleton; paths verified to exist):
sequenceDiagram
autonumber
participant U as 用户
participant R as REPL.tsx
participant H as handlePromptSubmit.ts
participant Q as query.ts::queryLoop
participant C as 上下文组装
participant A as services/api/claude.ts
participant T as tools/(43 个)
participant P as utils/permissions/
U->>R: 回车
R->>H: 原始输入
H->>H: 分流:/命令 · !shell · 普通 prompt
H->>Q: 进入循环
loop 每一轮(不是每次会话)
Q->>C: 重新组装上下文
Note over C: 系统提示 + CLAUDE.md + git 状态
每轮都重跑,不是启动时一次
C-->>Q: messages[]
Q->>A: SSE 流式请求
A-->>Q: token 流 + tool_use 块
alt 模型要调工具
Q->>P: 该工具此次调用允许吗
P-->>Q: 允许 / 拒绝 / 需询问用户
opt 需询问
P->>U: 权限弹窗
U-->>P: 决定
end
Q->>T: 执行
T-->>Q: 结果
Note over Q: 结果回流进 messages,进入下一轮
else 只有文本
Q-->>R: 收敛,退出循环
end
end
This diagram makes three things a flowchart cannot: ① context is reassembled every turn; ② permission checks happen before tool execution and may interrupt out to the user; ③ the loop’s exit condition is “the model returned text only.”
Type C · Control plane vs data plane (Control / Data Plane Split)
Answers: Which components decide what to do, and which move content?
This is the classic split from telecom and cloud infrastructure. It holds in agent systems and is extremely useful, and none of the six current diagrams uses it.
- Control plane: main loop, permission adjudication, goal state machine, scheduler, compaction decisions
- Data plane: token stream, tool I/O, file reads/writes, context buffers
How to draw: left/right columns, not top/bottom layers. Control-plane edges as solid lines; data-plane edges as thick / a different color.
Why it is worth money: you see at a glance where this project put decision rights.
- Claude Code: the control plane is entirely in the local process; the model only proposes
- Open Design: the control plane is outsourced to third-party CLIs; it keeps only the entry prompt and the exit quality gate—its most counterintuitive fact, and the one that most needs to be drawn
- grok-build: GoalTracker is a control-plane state machine independent of the model; if the model drifts, it is still there
Type D · State ownership and lifecycle (State Ownership)
Answers: Where does state live, who owns it, how long does it live, and what is lost on crash?
Every state container must be labeled with three attributes:
| Attribute |
Values |
| Medium |
memory / SQLite / JSONL file / remote service |
| Lifecycle |
single turn / single session / cross-session persistent / cross-machine |
| Crash semantics |
lost / reconstructable / already persisted |
Example fragment:
flowchart TB
subgraph EPH["回合级 · 崩溃即丢"]
S1["step_context 工具可见集快照"]
S2["本轮 token 缓冲"]
end
subgraph SESS["会话级 · 内存"]
S3["messages[] 对话历史"]
S4["审批缓存 approval store"]
end
subgraph PERSIST["持久 · 落盘"]
S5[("rollout / JSONL 会话资产")]
S6[("SQLite: projects · runs")]
S7["项目 cwd 的真实文件"]
end
S3 -.压缩时截断.-> S3
S3 -->|每轮追加| S5
A fact you cannot see unless you draw it: most agents’ “memory” is three different media glued together, and the pit engineers fall into most often is getting one segment’s lifecycle wrong.
Type E · Extension surface and blast radius (Extension Surface)
Answers: If I add a new capability, what do I change? Who is affected?
How to draw: put the extension point at the center; radiate outward “files you must touch to add this thing.”
You must distinguish three kinds of extension point:
1. Data extension (add a definition / a JSON)—zero code; blast radius = 1 file
2. Interface extension (implement a trait / interface)—blast radius = a new file + one registration site
3. Core rewrite (change the main loop)—blast radius uncontrollable
This diagram is the highest-value artifact for a “selection” reader, and the current six diagrams have none of it.
Open Design’s example is decisive: adding the 26th CLI = append one RuntimeAgentDef datum to registry.ts, with no new logic. That is the verifiable consequence of “adapters are data,” a hundred times stronger than writing “26 CLI adapters” inside a box.
Type F · Failure and degradation paths (Failure Modes)
Answers: What happens when something goes wrong?
The shared trait of almost every amateur architecture diagram: it draws only the happy path.
You must draw at least three kinds:
- Retry edges (with backoff policy)
- Degradation edges (capability drops but the system does not halt, e.g. semantic retrieval fails → fall back to keyword match)
- Circuit-break / terminate edges (stuck detection, step cap, cancellation-token propagation)
Distinguish them from the main path with dashed lines + red.
Part 4
Part 4 · Discipline of visual channels
Iron law: one visual channel encodes one variable. In the current diagrams, color and stroke are pure decoration—the two strongest channels are wasted.
| Channel |
Suggested encoding |
Forbidden |
| Stroke weight |
process / address-space boundary |
arbitrary emphasis |
| Fill color |
plane membership (control / data / storage / external) |
coloring because it “looks good” |
| Line style |
solid = sync call; dashed = async / event; dotted = optional / degradation |
mixing them |
| Arrows |
one-way = call; two-way = request–response (use sparingly; most of the time split into two edges) |
using a two-way arrow to hide unclarity |
| Edge labels |
transport + synchrony (HTTP/SSE, stdio, poll 500ms) |
leaving them blank |
| Shape |
rectangle = component; cylinder = persistence; diamond = decision; parallelogram = external system |
all rectangles |
You must include a legend. Custom encoding without a legend = no encoding.
On two-way arrows
A <--> B appears 5 times in the current six diagrams, almost always covering a place that has not been thought through.
What does LOOP <--> PERM actually mean? The main loop calls permissions and permissions answer (that is one synchronous call: draw one-way + annotate the return value)? Or does the permission system actively interrupt the main loop (that is two different edges, with completely different semantics)?
Rule: use a two-way arrow only for true bidirectional peer communication (e.g. full-duplex WebSocket). For request–response, draw one-way and write the return in the label.
Part 6
Part 6 · Concrete prescriptions for the six projects
For each of the existing six diagrams, a replacement (not a supplement—the current diagram should be replaced).
| Project |
What is drawn now |
What should be drawn |
Primary types |
| Claude Code |
5-layer vertical stack |
Full sequence of one turn: split → reassemble context every turn → SSE → permission adjudication → tool → result back-flow → converge |
B + ② |
| Open Design |
4 function boxes |
Three-process trust topology: the daemon is the only privileged party; third-party CLIs are independent processes and write the filesystem directly; the quality gate intervenes after the fact |
A + E |
| OpenCode |
client / server / model three segments |
Star topology + the counterintuitive edge “even the local TUI walks full HTTP”—that edge is why multi-client is free |
A + C |
| OpenWorker |
three boxes side by side |
Cross-language process boundary (Rust shell ↔ Python engine) + unified event stream + out-of-band approval inbox: approval does not block the main loop |
A + D |
| grok-build |
4-layer crate inventory |
Goal Mode state machine: plan / execute / verify / strategist-recovery four states + multi-hour persistence + decoupling from model output |
② + D |
| OpenManus |
inheritance chain + toolbox |
Inheritance chain as a partial order of capability (what each layer adds) + dual termination of stuck detection and max_steps |
② + E |
On misuse of “Kimi K3 style”
Using diagrams in the Sebastian Raschka vein is a good idea, but you have to understand why they work:
Their information density comes from a two-level structure of “main structure + local zoom”—the main diagram gives the global skeleton; callout boxes give internal detail of a critical local (tensor shapes, dimension transforms, concrete operators).
The current implementation copied the layout, not the information structure: the right-hand callouts hold “module blurbs,” which are the same abstraction level as the main diagram, not a drill-down.
Correct use: the main diagram draws process topology; the callout holds the internal implementation of that one load-bearing mechanism—e.g. Open Design’s main diagram draws three processes, the callout holds the real field list of RuntimeAgentDef, so the reader sees “an adapter is this 20-field data structure, with not one line of behavior code.”
Part 9
Part 9 · Fact-check protocol (prompted by errors found this round)
This review found 4 hard errors + several precision problems in the six diagrams, all of a type that could have been avoided. The following process is mandatory.
9.1 Errors found this round
| # |
Location |
Error |
Fact |
Evidence |
| 1 |
Title §4 |
“OpenWorker (OpenClaw)” treats OpenClaw as an alias |
OpenClaw is an acknowledged external project, not an alias. Original: Design (from OpenClaw): secrets **never enter the model's context, prompts, or traces** |
参考项目/openworker/coworker/secrets.py:3 |
| 2 |
§2 |
Open Design daemon written as “Fastify + SQLite” |
It is Express + better-sqlite3. The repo’s own apps/daemon/AGENTS.md:96 says: "Do not move daemon-only Node, SQLite, Express, filesystem, or process types into contracts." |
项目分析/open-design-源码分析.md:126,1787 |
| 3 |
§3 |
acp/ drawn as a top-level client package peer to packages/tui |
ACP lives in packages/opencode/src/acp/, i.e. inside the server package. The diagram took “a subdirectory of the server” and drew it as “a peer client of the server,” inverting the real boundary |
参考项目/opencode/packages/opencode/src/acp |
| 4 |
§4 |
scheduler.py path |
Actually coworker/automation/scheduler.py |
参考项目/openworker/ |
Precision problems (not false, but below a “professional” bar):
- Claude Code’s main loop is labeled only
src/query.ts : queryLoop(), omitting src/QueryEngine.ts (1 295 lines) and the src/query/ subdirectory (config.ts / deps.ts / stopHooks.ts / tokenBudget.ts). The heart is distributed. Pointing at one file misleads someone reading the source.
- “40+ tools”:
claude-code/src/tools/ actually has 43 entries. If you can count, write the exact number.
- OpenManus agent inventory omitted
DataAnalysis (data_analysis.py) and SandboxManus (sandbox_agent.py).
- “26 CLI runtime adapter layer” and “25 CLIs” coexist on the same diagram with no explanation. Correct statement: 26 runtime definitions correspond to 25 distinct executables—
byok-opencode reuses OpenCode’s binary, so there is one more definition than binary. That extra definition is itself a design detail worth drawing.
9.2 Mandatory process
Rule 1 · Every proper noun must have a source.
Every name you put on a diagram (project alias, framework name, file path, class name) must be attachable to a file:line or to command output. If you cannot, do not write it.
Rule 2 · The naming triple must be resolved.
Repo name / package name / command name often differ. OpenWorker is all three different (repo openworker / Python package coworker / CLI openworker). Which one you write on the diagram depends on who the diagram is for—a source reader wants the package name; a selection reader wants the product name.
Rule 3 · Every path must have been ls’d in the checkout.
for f in src/query.ts src/tools/ ...; do
[ -e "$f" ] && echo "✅ $f" || echo "❌ $f"
done
Rule 4 · Every number must be computed now.
ls | wc -l, wc -l, grep -c. Ban “about,” “40+,” and other estimates from memory—unless that is how upstream documents it, and you cite the source.
Rule 5 · Hierarchy must be verified.
Before drawing X as a child of Y, confirm that X’s real path is under Y. Error #3 is exactly skipping this step.
Rule 6 · Cross-check against existing analyses.
The twelve documents under 项目分析/ have already been line-verified. On conflict, the analysis document wins, or go back to source for a three-way confrontation—do not silently trust your impression.
Part 11
Appendix · A complete “good diagram” specimen
Question: Open Design does not write its own main loop. How does it still keep output quality consistent across 25 third-party CLIs?
Load-bearing wall: It cedes control to third parties and keeps only the entry prompt and the exit quality gate—an architecture of “close both ends, let go of the middle.”
flowchart LR
IN["① 入口收口
prompts/system.ts · 2 075 行
20 层上下文 · 按变化频率分带"]
ASSETS["skills 164 · design-systems 153
design-templates 115 · craft 11"]
DEF["RuntimeAgentDef ×26
只描述「怎么说话」
不描述「说什么」「怎么调度」"]
CLI["② 第三方 CLI · 独立进程 ×25
claude / codex / cursor-agent
opencode / devin / qwen …"]
FS[("项目 cwd 文件系统
HTML · PDF · PPTX · MP4")]
OUT["③ 出口收口
lint-artifact 程序化反 AI 味
Design Jury 五陪审评审"]
ASSETS --> IN
IN -->|"拼进 spawn 参数"| DEF
DEF -->|"spawn · stdio"| CLI
CLI -->|"直接写盘
产物不回传 daemon"| FS
FS -->|"事后读取"| OUT
OUT -.->|"不合格则重跑"| IN
classDef own fill:#eef4ff,stroke:#4a6fa5,stroke-width:2.5px
classDef third fill:#fff4ec,stroke:#c96442,stroke-width:2px,stroke-dasharray:5 3
classDef store fill:#f4fff0,stroke:#4a8f3c
class IN,ASSETS,OUT own
class DEF,CLI third
class FS store
Legend: ■ solid blue box = Open Design’s own code · ■ dashed orange box = third-party process, behavior uncontrollable · ■ green box = persistence · dotted = feedback / degradation edge.
⚠️ A layout lesson you must remember: an earlier draft grouped “entry” and “exit” in one subgraph OWN to express “close both ends.”
Mermaid’s LR layout then shoved that group to the right as a whole, destroying left-to-right flow semantics—the reader saw the third party first, then the entry. Logic inverted.
Rule: when “grouping” and “flow” conflict, let position express flow and color express ownership.
The diagram above dropped the subgraph and used classDef coloring instead: blue nodes appear at both ends, orange in the middle. “Close both ends, let go of the middle” emerges from the spatial distribution of color, and left→right flow is not destroyed.
That is more accurate than forcing a box, and it looks better.
figcaption: Close both ends, let go of the middle. Open Design does not control third-party CLI loops, so quality assurance can only sit on the entry prompt and exit programmatic checks—note that artifacts are written to disk directly by the CLI and not returned to the daemon, so lint and review are architecturally after the fact. That constraint is not implementation laziness; it is the necessary cost of ceding control.
Why this diagram passes:
1. It answers a concrete question, not “exhibit the architecture”
2. It has a load-bearing wall, and the diagram’s topology itself (narrow at both ends, wide in the middle, dashed enclosure) expresses it
3. It exposes a fact that can be interrogated (artifacts are not returned → the gate can only be after the fact)
4. It has a degradation edge (fail → re-run)
5. Color and line style have semantics and a legend
6. Numbers serve the claim (26 definitions vs 25 binaries is labeled explicitly)
7. With text covered, its shape is completely different from the other five projects’ diagrams
This guide is written from the twelve file-by-file analyses under this repository’s 项目分析/ and the source trees under 参考项目/. Every error listed in Part 9 was re-checked with grep -n / ls / the source text itself.