Design decisions
The choices that shaped zerd, each with its reason and trade-off.
The choices that shaped zerd, with the reason behind each. Several started as a mistake that showed up in a real session.
1. Enforce in code, ask in the prompt only for taste
A prompt that says "never read .env" is a request. zerd puts rules where the model cannot talk its way past them: the tool
registry is the only way to run a tool, and the guard, workspace confinement and approval checks sit in front of every call, for
the main agent, sub-agents and parallel workers alike.
Trade-off: more code to maintain than a paragraph in a prompt, but a jailbroken or confused model still can't leave the folder.
2. The author never grades its own work
The model that wrote a change is the worst judge of it. Review runs in a separate context, with read-only tools, on a different model when routing allows. Same idea for the challenger and the advisor (below). Trade-off: extra model calls. They are spent only where a mistake is expensive (a diff, a risky design question).
3. Reviewers are cheap to fool, so a second agent tries to refute them
Early reviews read like confident fiction: plausible chains of reasoning about code that did not behave that way. So a finding is a claim, not a result. Each claim goes to a verifier whose job is to disprove it; confirmed HIGHs are run in a throwaway copy of the change to see the defect happen, and one that does not reproduce is capped at MEDIUM with what was tried shown beside it. Findings citing a file that doesn't exist are dropped before anyone reads them. Trade-off: a review costs more and takes longer. The reader gets fewer, truer findings.
4. A hallucination check that is not a model
Every path and path:line in the final answer is looked up in the real tree. A made-up file or a line past the end of a file
goes back for one correction; whatever is still unverified is shown as a warning. It is a few dozen lines of code and catches a
whole class of confident wrongness for free.
5. Cheapest evidence first
Tools are ordered by cost: search (ranked files), then outline (symbols), then read_file(symbol=...), then grep. The scout,
the prompt and the tool descriptions all push the model down that ladder, because a 1,300-line file read to find one function is
tokens that every later call re-sends.
6. Never send the same thing twice
read_file remembers which lines the model has seen and returns only new ones, or a diff if the file changed. Cleared or capped
tool output isn't lost: it goes to an archive and the model gets an id (r7) to recall_result. Compaction deterministically
lists files read and modified. The goal is that the model never has to guess what it used to know.
7. Failure has a defined next step
Checks fail, so repair. Repair fails, so escalate to the strong model. A loop is detected, so escalate. Quota hits one provider, so fail over to another and block the first for the session. Budget runs low, so one last tool-free call turns the work so far into an answer. Nothing falls over silently, and nothing ends in "the model said it was fine".
8. Only remember what cannot be invented
Memory stores what you told zerd and what verified runs changed. It does not store the model's opinions about your repo,
because those are exactly what drifts and compounds. Lessons are plain text in your AGENTS.md, so you can read, edit and commit
them.
9. Pi mode is the default: fewer rails, simpler agent
zerd started with many guards: call caps, aggressive clearing of old results, a scout before every task. Measured against a simple
agent (seven plain tools, a tiny prompt, files read whole), the guards often cost more than they saved. So pi mode is on by
default, copied from how the pi coding agent works: a small tool set, no call caps, results
cleared only near the window, compaction only close to the limit. --no-pi brings back the guarded setup (scout, reference check,
parallel tasks). Safety and correctness layers stay on in both.
Lesson: every rail needs to pay rent. We measured, and removed what didn't.
10. Different brains for different jobs
One model for everything wastes money and one model for the review shares the author's blind spots. Routing is by role
(default, fast, strong, summarize, review, advisor, challenge), each a fallback chain. Adding a model needs no
code. The advisor and challenger default to a different model family than the author on purpose.
11. Plain files, outside the repo, atomic
Sessions, traces, archived results, learned lessons and review memory live in the user data dir, not in your project. Writes are temp-file + rename, so a kill mid-write never leaves a truncated session. Traces are JSONL so a bad run can be replayed line by line.
12. Say what you did not do
The answer states the review scope (working tree, last 3 commits, PR #42), lists every fallback (PR base unknown, fetch failed),
says when passing checks don't exercise the change, and labels guesses as [guess]. A harness that proves its work has to be
equally clear about where it couldn't.