Chapter 1 — The Second Seam
# Chapter 1 — The Second Seam
Book 1 taught you to hire a line cook with a work permit. This book hands you the forge. By the last page you will have added a new kind of worker to the framework itself — a paradigm, declared in the same language the shipped ones speak, proved at every test layer the framework runs, and shaped into a contribution you could merge. You will never look at an agent framework the same way again. That is not a promise about your feelings; it is a promise about what you will be able to read.
The worker you will build is a critic. The thesis it embodies is the reason this book exists at all, so we start there, because every design decision in the next twelve chapters falls out of it.
# Where you are
This book assumes you finished Cooking Agentic Thoughts with Relurpify.
You have driven relurpish, read a governed turn’s receipts, authored Euclo
thoughtrecipes in the Euclo DSL, and you know the two-directory rule —
relurpify_cfg/ is yours to edit, .relurpify_state/ is the runtime’s to
write. None of that is re-taught here. The DSL is not re-taught either; when
a recipe appears in this book, you are expected to read it fluently.
New in this book, assumed from page one: working Go. Interfaces, context,
table-driven tests, and the patience to read other people’s Go — because
from Chapter 2 on, that is most of what we do. You do not need generics
gymnastics, Go module internals, prior agent-framework experience, or a
formal CS background. If you can read cognitionzoo/reflection/ after this
chapter without flinching, you are ready for Chapter 2.
Everything in this chapter was captured on a real machine: Linux 6.18, Go
1.27.3, Ollama 0.40.8 with gemma4:e4b served, Docker with runsc
installed, Python 3.14.8, pytest 9.1.1. Where your output will differ, the
text says so.
| Requirement | Version / notes |
|---|---|
| OS | Linux or macOS (book verified on Linux) |
| Go | go directive 1.26.0, toolchain go1.27.2 — the repository’s own toolchain |
| Git | Any recent version |
| Python | 3.10+ with pytest, for the stringkit demo |
| Model | Ollama serving gemma4:e4b (your book-1 setup) |
| Sandbox | Docker, plus gVisor runsc on Linux for the default backend |
| Book 1 | Assumed fluency: relurpish, governed turns, the Euclo recipe DSL |
# Why extend the framework at all: the critic thesis
Book 1’s agent could fix a bug because you watched it work. But watch what happens when you ask an agent whether its own work is good. It grades the work with the same weights it wrote the work with. The blind spot that chose the wrong variable name is the same blind spot now asked to notice the wrong variable name. Self-review is not review. A model grading its own output shares its own blind spots — the errors are correlated with the checker.
Every serious agentic system runs into this, and the standard response is a second prompt: “now review your answer.” That is better than nothing, and it is still not review, because nothing separates the two roles. The reviewer is a costume the same actor puts on.
Relurpify already ships a paradigm for the costume: reflection, a review loop over a react delegate with bounded revisions. We will read it in Chapter 7 as our template, and it is honest about what it is — one agent loop that pauses to grade itself before revising. The critic is a different claim: a genuinely separate phase, with its own prompt, its own criteria, and its own verdict, handed to an independent drafter that must respond to it. Draft, independent critique, conditional revise. The separation is the mechanism: the drafter cannot grade the critique’s leniency, and the critic cannot reach in and edit the draft.
Here is the thing that makes this book worth your weeks: Relurpify already agrees with the thesis, mechanically. In the turn you will run in this chapter, a completed run gets flagged by the framework itself — the model asserting success is not evidence — because a verification claim needs an observation behind it. The framework refuses to take the model’s word. The critic paradigm you will build is that principle, promoted from a guard inside one node to a first-class agent shape, addressable from the recipe DSL as:
agent fixer uses criticBy the end of Part III, that line will be real, and by the end of the book it will be merge-ready. First you need to see the machine you are extending — from the builder’s seat, not the operator’s.
# The forge, from the doorway
Book 1 showed you the framework as a product. Now it is raw material. Three names, and a rule about how they relate.
cognitionzoo is where agents live. The package doc states its question
verbatim: “which agent paradigms, planning models, and execution patterns
does Relurpify use?” It ships eight paradigms, each in its own package,
each declaring what it is before any code says how it runs:
| Paradigm | Package | Execution shape | Directives it accepts |
|---|---|---|---|
| ReAct | cognitionzoo/react |
iterative | until |
| ReWOO | cognitionzoo/rewoo |
staged plan | plan (required), step, synthesize |
| Planner | cognitionzoo/planner |
plan-execute | plan, step, verify, summarize |
| HTN | cognitionzoo/htn |
decomposition | method, task |
| Blackboard | cognitionzoo/blackboard |
blackboard | source |
| Pipeline | cognitionzoo/pipeline |
linear | (none — stages are grammar) |
| Chainer | cognitionzoo/chainer |
chain | link |
| Reflection | cognitionzoo/reflection |
review loop | review, revise |
Read that middle column slowly. Execution shape is not a base class and not a strategy object. Each paradigm declares its shape as data — a label in a closed set — along with the directives a recipe may address it with, the order those directives may appear, what it composes with, what it guarantees, and executable conformance cases that prove the guarantees. All of that lives in a struct. In Chapter 7 you will fill in a struct of your own.
paradigm.Deps is what the runtime hands an agent. Every paradigm’s
constructor takes *paradigm.Deps (cognitionzoo/paradigm/deps.go), and
the composition root fills it at boot. Surveyed, the struct carries
fifteen fields — the model port, the capability registry, the permission
checker, a sandbox command runner and its policy, working memory, the AST
index, search, the stream trigger, the grounder, the prompt registry, and a
handful of runtime services you will meet properly in Chapter 8. Two fields
deserve a look right now, because they set the governance bar you are
joining:
// PermissionChecker is the capability gate shared by governed paradigms
// (ReWOO refuses to execute without one). Sourced from the same
// authorization bundle that backs the registry's permission manager.
PermissionChecker permissions.CapabilityCheckerReWOO refuses to execute without one. That sentence is the whole culture of this codebase in one field comment: fail closed, and make the failing refusal part of the type. When your critic runs, it inherits exactly this bar. No paradigm in this framework executes a tool because a model asked nicely.
execution/agentgraph is the machinery underneath. Its package doc
opens: “a deterministic state-machine workflow runtime for Relurpify
agents.” A graph is a directed structure of typed nodes — ToolNode,
ConditionalNode, HumanNode, SystemNode, ObservationNode,
TerminalNode, StreamTriggerNode, RetrievalNode — executed in order
while a typed context structure threads through each step. Graphs seal on
first execution and refuse mutation afterward. The shipped paradigms are
themselves graphs: ReAct is a think → act → observe loop you will see in
your telemetry as react_think, react_act, react_observe nodes.
The rule that relates the three names is the domain DAG — the enforced
layering you will make mechanical in Chapter 3. In one sentence:
cognitionzoo sits above execution, imports it, and may not be imported
by it. Paradigms consume the graph runtime; the graph runtime does not know
paradigms exist.
# The two seams
So you want to add an agent to this framework. There are exactly two doors, and the framework’s own docs name them as extension points:
| Want to add… | Door | Where you will live |
|---|---|---|
| A one-off agent for your workspace | Compose graphs | your recipe or your Go test, out of agentgraph nodes |
| A new kind of agent the DSL can address | Declare a paradigm | cognitionzoo/, registered like the shipped eight |
The first seam — compose graphs — is power without vocabulary. You
build a Graph by hand: NewGraph, AddNode, AddEdge, SetStart. Full
control over every node, edge, and condition. What you do not get is a
grammar. Nobody can write a recipe that says use that thing you built;
your agent is code only its author can invoke. Part II of this book lives
here, and by the end of Chapter 6 you will have a working critic pipeline
as a hand-composed graph — and you will feel, concretely, why that is not
enough.
The second seam — declare a paradigm — is vocabulary, and vocabulary has
a price: a contract. Look at the entire contract for the shipped
reflection paradigm, the specimen you will model your own on
(cognitionzoo/reflection/contract.go — this is the whole file minus the
init that registers it):
func contract() paradigm.Contract {
return paradigm.Contract{
Paradigm: "reflection",
Summary: "Review loop over a react delegate with bounded revision iterations.",
Shape: paradigm.ShapeReviewLoop,
Composes: []string{"react"},
Directives: []paradigm.DirectiveSpec{
{Name: "review", Form: paradigm.FormLine, Text: paradigm.ArgOne},
{Name: "revise", Form: paradigm.FormBlock, Text: paradigm.ArgNone,
Predicate: true,
Body: []paradigm.BodyItem{paradigm.BodyItemRun, paradigm.BodyItemDelegate},
Requires: []string{"review"}},
},
Order: ¶digm.OrderRule{Sequence: []string{"review", "revise"}},
Guarantees: []string{
"bounded revision iterations",
"authored review verdicts live in the ephemeral scratch namespace",
"composes the react delegate through the scoped-registry path",
},
Conformance: []paradigm.ConformanceCase{
{
ID: "reflection/review_writes_scratch",
Directive: "review",
Assertion: "the review verdict is written to scratch.review / scratch.review_issues and the result fields",
FixtureShape: "agent uses reflection; run: review \"…\"",
},
// … three more cases: revise_fires_on_predicate,
// revision_cap_bounded, review_pass_ends_loop
},
}
}Thirty lines, and it is a load-bearing document: the recipe loader reads it
to decide which directives are legal, the linter replays it to reject bad
recipes at lint time, and the conformance harness runs its cases to prove
the paradigm keeps its word. Notice Requires: []string{"review"} — the
grammar itself forbids a revise block with no review before it. The
contract is not documentation that drifts. It is data the loader reads, and
data that gets tested.
That is the door this book walks through. The critic will not merely run;
it will be addressable, in the same sentence as react and reflection:
agent fixer uses critic.
Which door, when? Compose graphs when the agent is yours alone and the vocabulary would be premature — prototype, ensemble experiment, one recipe’s private step. Declare a paradigm when the pattern is the contribution: when other workspaces should be able to address it, constrain it, and hold it to conformance. The book makes you walk both in order, graph first, because you cannot declare a good contract for a pattern you have not built.
# Hands-on
Four steps, one arc: build everything, run the framework’s law over it, reset the demo repo, and drive one turn with your eyes on the receipts.
# 1. Get the code, pin it, build it
git clone https://github.com/lexbity/relurpify.git
cd relurpify
git checkout BETA-RC1-FALL2026This book, like book 1, is pinned to an edition tag; every internal the
chapters show is read at that tag, and the labs re-verify on re-pin. (One
honesty note: as of this writing the tag is not yet pushed to the public
remote — the chapter transcripts were captured on the tree that became it,
whose own telemetry reports the commit it was built from. If checkout
fails, build main and expect small diffs; the labs README records the
exact tree.)
Build everything:
go build ./...
go vet ./...$ go build ./... # no output; exit 0
$ go vet ./... # no output; exit 0One Go module, one command each, nothing to configure. The build is offline-friendly; a first build takes a minute or two.
#
2. Run the law: make lint-arch
This is the baseline you will restore after every chapter of this book, so learn to read it now:
make lint-arch[PASS] lint-class-normalization: all class casts normalize
[PASS] lint-no-permissive-hitl: no permissive HITL broker
GOPROXY=off GOSUMDB=off go run ./tooling/arch/cmd/envcheck
[PASS] envcheck: no env access outside userconfig (1087 files scanned)
GOPROXY=off GOSUMDB=off go run ./tooling/arch/cmd/shimcheck
[PASS] shimcheck: no forbidden language (1087 files scanned)
GOPROXY=off GOSUMDB=off go run ./tooling/arch/cmd/symcheck
[PASS] symcheck: no removed symbols (1087 files scanned)
GOPROXY=off GOSUMDB=off go run ./tooling/arch/cmd/archcheck; EXIT_CODE=$?; \
GOPROXY=off GOSUMDB=off go run ./tooling/arch/cmd/domaincheck -mode=enforce -check=direction; \
GOPROXY=off GOSUMDB=off go run ./tooling/arch/cmd/domaincheck -mode=enforce -check=governance-orch; \
GOPROXY=off GOSUMDB=off go run ./tooling/arch/cmd/domaincheck -mode=enforce -check=context-ports; \
exit $EXIT_CODE
[PASS] forbidden: no violations
[PASS] converter: no violations
[PASS] sqlite: no violations
[PASS] glob: no violations
[PASS] stub: no violations
[PASS] cycle: no violations
[PASS] bucket: no violations
[PASS] consumer: no violations
[PASS] All architecture gates passed
[PASS] domain-direction: no violations
[PASS] All domain checks passed
[PASS] governance-no-orchestration: no violations
[PASS] All domain checks passed
[PASS] context-ports: no violations
[PASS] All domain checks passedThree seconds, and here is what just happened — because this output is Chapter 3, compressed:
envcheckparses every one of 1,087 Go files and fails if anything outside the configuration boundary reads a process environment variable. Not a grep — an AST walk, so aliasing the import does not slip it.shimcheckenforces the charter’s four bans, stated in the repository’sAGENTS.mdas four lines: no shims / no compat / no aliases / no stubs. The[PASS] forbiddenand[PASS] converterrows are its report: neither the vocabulary nor the telltale type-converter signature may appear.symcheckfails if a symbol the project removed ever reappears.archcheckanddomaincheckenforce the domain DAG: import direction, no governance→orchestration imports, no context-port violations, no bucket packages, no cycles.
Notice the shape of the deal. The layering is not a convention diagram in a
wiki; it is a program, and it runs before your PR does. When your critic
lands in cognitionzoo/, this same gate will check its imports in three
seconds — and when you get one wrong, it will tell you exactly where. You
will come to love a program that says no.
# 3. Reset stringkit
The demo repo carries over from book 1, reset: no seeded failure, tests green. Copy it from the labs and start clean:
mkdir -p ~/code/stringkit && cd ~/code/stringkit
cp ~/relurpify/devdocs/agent-construction-relurpify/labs/stringkit/*.py .
git init && git add -A && git commit -m "seed stringkit (book 2 reset)"
python3 -m pytest test_stringkit.py -q.. [100%]
2 passed in 0.02sBoth tests green. Book 1’s deliberately broken slugify is history; this
is the repaired state, and it is where the critic’s story starts. You do
not fix anything this chapter. You make the agent look at this code —
which, this book will argue, is a different job than writing it, and needs
a different agent.
# 4. One turn, receipts and all
Run doctor, boot the TUI, and drive one turn — any read-only instruction about stringkit will do:
~/relurpify/relurpish doctor --workspace ~/code/stringkit # verdict: ready
~/relurpify/relurpish chat --workspace ~/code/stringkitBook-1 readers know the doctor’s report; Result: ready with the two
informational warnings is a healthy machine. The turn is where it gets
interesting, and on the verification machine the first turn taught a
lesson worth its own section. Here is what happened, exactly.
Turn one. With the materialized profile as shipped
(tool_calling.intent: auto in
relurpify_cfg/model/profiles/default.llm.yaml), asked to explain
slugify, the panel showed the model’s raw decision as text:
│ 🤖 [10:05] Agent │
│ 🤔 Thinking [−] │
│ └─ 🔍 Analyzing request (4s) │
│ │
│ {"thought":"I need to find and read the content of 'stringkit.py' │
│ to explain the 'slugify' function. I will start by listing the │
│ files to locate the file.","action":"file_list","tool":"file_list", │
│ "arguments":{"directory":"."}}<tool_call|><|tool_response> │
│ │
│ 🧾 Result │
│ node=euclo.done | status=ok │
│ ⏱ 4s | 29 tok │No tool ran. (Panels reflowed from the captured 120-column transcript; the
full-width originals are in
labs/transcripts/ch01-baseline.md.) The model’s decision arrived as
prose — the template leak
book 1 flagged in its own first chapter — and the run closed ok having
done nothing at all. Keep this failure in your pocket: it is Chapter 2’s
door. What the runtime consumes is not “what the model said” but a
structured decision, and the shape a model’s output must have for that
parse to work is a contract like any other in this framework. Chapter 2
puts you on the implementing side of it, and your fake model will never
leak.
The fix is the book-1 drill, now with a builder’s explanation: set the intent explicitly, restart the TUI so the profile reloads.
sed -i 's/ intent: auto/ intent: prompt_based/' \
relurpify_cfg/model/profiles/default.llm.yamlTurn two. Same instruction. This time the model decided cleanly, the
runtime parsed the decision, executed the read through the governed
pipeline, and the model produced a real explanation of slugify —
lowercase, strip punctuation, collapse whitespace — with a correct account
of what a bug in it would break. The run closed, and then the framework
said this:
│ 🧾 Result │
│ node=euclo.done | status=ok │
│ ⏱ 2s | 29 tok │
╰────────────────────────────────────────────────────────────────────╯
│ ⚙ [10:08] System │
│ Agent error: task edits code but the run executed no file write or │
│ edit observation │Read it again, because this is the critic thesis living in the code today.
The task looked edit-shaped; the run executed no write; the framework
declined to certify the result. The rule is written in the observe node of
the shipped react paradigm
(cognitionzoo/react/react_observe_node.go), as a comment on the check
that produced that flag:
Loop-close honesty: an edit-shaped task that closed without an executed edit observation is unverified no matter who claimed completion — the model asserting success is not evidence.
The model asserting success is not evidence. You just watched the
framework refuse to take its own agent’s word for it — a correct,
complete-looking answer, downgraded because the claim had no observation
behind it. Every chapter of this book builds toward making that instinct
into an agent. ([NEEDS CONFIRMATION: at BETA-RC1-FALL2026, chat-routed react runs appear edit-shaped regardless of phrasing — "explain…", "analyze…", "without modifying anything", "investigate…" all flagged — so read-only chat turns close unverified. The exact chat→react task-type wiring gets pinned during Chapter 2 research.])
The receipts. You have seen them before as an operator; look once as a
builder, because your agent will write these too. The audit chain
(.relurpify_state/audit/agent-stringkit-euclo/chain-*.jsonl) recorded each
tool the run used, with the decision that let it through:
{"action": "tool:file_list", "type": "hitl", "result": "tool_allowed",
"timestamp": "2026-10-23T17:05:06.99Z"}
{"action": "tool:file_read", "type": "hitl", "result": "tool_allowed",
"timestamp": "2026-10-23T17:06:11.79Z"}And the telemetry export
(.relurpify_state/telemetry/otlp/relurpify-*.jsonl) carries the turn’s
spans — the node names are the graph you read about above, made visible:
node euclo.intake node euclo.family_select node euclo.ingest
node euclo.checkpoint node euclo.policy_gate node euclo.dispatch
node euclo.route_fork node euclo.execute_thoughtrecipe
node euclo.merge node euclo.report
node react_think node react_act node react_observe node react_doneTwelve Euclo nodes for one instruction, then four react nodes for the run it dispatched to. The Euclo root graph classifies, gates, and routes; the react paradigm is the graph it hands the work to. When your critic ships, its nodes will appear in this same list, and operators will read them in their TUI the way you just read these.
# Gotchas
- The profile edit needs a TUI restart.
relurpify_cfg/model/profiles/is read at boot; a mid-session edit does nothing to a running TUI. Quit, restart, retry — and check the transcript inlabs/transcripts/ch01-baseline.mdif your turn looks different. - The unverified-run flag is normal for read-only chat turns at this edition. If your explain-style turn closes with the edit-observation flag, you are not broken; you are watching the loop-close honesty guard. Turns that actually edit and verify close clean.
git checkout BETA-RC1-FALL2026may fail until the tag is pushed. Buildmainand note the commit; the labs README carries the tree the transcripts came from.make lint-archneeds no sandbox, no model, no workspace. It is pure source analysis — three seconds, offline, every time. If it goes red, fix the cause before anything else; never add an exemption to make it green. Exemption tables are load-bearing, and Chapter 11 explains what that costs.- stringkit ships green. Do not break it “to give the agent something to do” — chapters that need a broken state seed their own, and the labs copy is the reference.
# Summary
- The critic thesis: self-review is not review; the same model grading its own work shares its own blind spots. The buildable answer is a separate phase — own prompt, own criteria, own verdict — and the framework’s loop-close honesty rule (the model asserting success is not evidence) is that principle already enforced in miniature.
cognitionzoois the paradigm collection: eight shipped paradigms, each declaring its contract — shape, directives, order, guarantees, conformance cases — as data.paradigm.Depsis the governed surface the runtime hands every paradigm; the permission checker is mandatory, and ReWOO refuses to run without one.- Two extension seams: compose graphs (power without vocabulary) and declare paradigms (vocabulary with a price — the contract). This book walks both, in that order.
make lint-archis the baseline: three AST gates, the charter’s four bans, and the domain DAG, enforced in three seconds over 1,087 files. You will restore this baseline at the top of every chapter.- One real turn showed the book’s two themes in the wild: a model decision arriving as unparseable text (Chapter 2’s subject), and the framework downgrading an uncertified success (the critic thesis, met in person).
# Check yourself
- Why is a self-review loop not the same thing as independent critique, and what does the reflection paradigm’s contract have that the critic’s will also need?
- Your recipe needs an agent that only you will ever invoke, once, for one experiment. Which seam do you use — and what do you give up by choosing it?
- What does
envcheckenforce, why is it an AST walk rather than a grep, and what happens if your newcognitionzoo/criticpackage reads an environment variable? - In the turn you ran, the framework flagged a completed, correct-looking run. Quote the rule it enforced and say why the rule exists.
- The audit chain showed
tool:file_read … tool_allowed. Which field ofparadigm.Depsis the gate that made that decision, and which shipped paradigm refuses to run without it?
Answers. 1. Self-review is one agent grading itself with the same weights
that produced the work — errors correlate with the checker; reflection
already gives the vocabulary (review/revise, bounded revisions, conformance
cases), which is why it is Chapter 7’s template. 2. The graph seam: full
control, but no grammar — no recipe can address your agent, and nothing
holds it to conformance. 3. No code outside the configuration boundary may
read process environment variables; as an AST walk it survives import
aliasing and string tricks; your package fails the gate, in three seconds,
by exact file. 4. “An edit-shaped task that closed without an executed edit
observation is unverified no matter who claimed completion — the model
asserting success is not evidence” — because a completion claim from the
actor that produced the work is exactly the correlated-errors problem. 5.
PermissionChecker permissions.CapabilityChecker; ReWOO fails closed
without one.
# Try it yourself
- Read the neighbor contracts. Open
cognitionzoo/rewoo/contract.goandcognitionzoo/htn/contract.gonext to the reflection contract you saw here. Find, in each: the shape label, the required directive, and one guarantee you could imagine writing a conformance case for. You are practicing Chapter 7’s core skill on shipped material. - Break a gate on purpose. In a scratch copy of the repo, add
os.Getenv("HOME")to a file incognitionzoo/react/and runmake lint-arch. Read the failure. Then revert it and confirm the baseline goes green. (Do this in a throwaway clone, not your working tree — and notice how fast the gate tells you exactly where you sinned. That speed is why the dev loop in Chapter 3 starts here.)
# Where next
You have a green baseline, a clean stringkit, and one turn’s worth of
receipts — plus a leak, which is the best kind of homework. Chapter 2 goes
straight at it: the model.LanguageModel contract, read the way its authors
wrote it, and then implemented — by you, as a scripted fake model you
control. Every later chapter drives the critic through that fake, because
determinism is the only honest way to test a loop. Bring the leak; we turn
it into an interface.
The lab for this chapter is the baseline itself:
devdocs/agent-construction-relurpify/labs/ holds the reset stringkit,
verify.sh (./verify.sh gates ch01 re-runs this chapter’s baseline in
your checkout), and the captured transcripts from the verification machine.