A bad single action by an agent is cheap. It calls the wrong tool, you see the error, you move on.
A good plan executed by an agent is where it gets expensive. Twelve steps, each one reasonable, pointing somewhere you never wanted to go — and because every individual move looked fine, nothing in the loop had a reason to stop. The better agents get at planning, the more this is the risk that matters.
So in the fifth session of building Whale I didn’t make it smarter. I put two things in front of it: an adversary, and a human.
The layer above the loop
Up to now Whale had a working loop and, since the last session, a memory that records what it did and refines itself. What it lacked was a stage between being asked and starting work.
The new layer runs above the existing loop:
recall → plan → critique → execute
Recall pulls the relevant structure out of memory. Plan turns the request into a tree of subtasks, each node one executable unit, deliberately shallow — three levels, root included, enforced in the type itself (MAX_PLAN_DEPTH = 2), not a nested cathedral. Critique tears into that tree before anything runs. Execute is the loop we already had, now working from an approved plan instead of straight from the prompt.
Adversarial cooperation
The planning pattern I adapted comes out of Adversarial Cooperation in Code Synthesis, a December 2025 paper from Block AI Research — the people behind the Goose agent. They call it dialectical autocoding: a player proposes, a coach critiques, and the friction between two cooperating agents produces something better than either alone. It is an old idea with a new application — the point is not that the critic is right, it is that the proposer has to defend the plan before it costs anything.
Concretely: the planner produces the tree, and a critic agent goes at it branch by branch. Branches get pruned. Branches get postponed. Some survive. The critic returns a list of objections and an empty list means approval — which makes the default direction of travel through the gate, not into it. It runs in one of two modes, advisory or strict; strict is a flag away and blocks on any objection. The critique runs at essentially every iteration of the outer loop, not once at the start, because a plan that was sound three steps ago may not be sound now.
What this buys you is not correctness. It is visible disagreement. When an agent silently produces a plan, you have no signal about which parts were marginal. When a critic has pruned four branches out of nine, you are looking at a plan that has already survived an argument.
Why a human gate, and where exactly
Then the plan stops and waits for a person.
The temptation is to put approval everywhere — every node, every step, full control. That is how you build a gate nobody uses. Approval fatigue is real and it is fast: by the fifteenth dialog, people click yes without reading, and you now have the appearance of oversight, which is worse than none, because you will trust it.
So on the first iteration only the root plan is surfaced for approval. One decision, at the point where it still determines everything downstream, made by a human who has read a tree of subtasks rather than a wall of diff.
This is not a hypothetical preference for us. It is how we work at nowtec generally: agents prepare, humans send. Our own social posts are drafted by agents and never published by one — the click belongs to a person. Building the same shape into the harness was less a design decision than an admission that we already believe this.
The test run that got it wrong
And then the first real run produced a plan about itself.
I asked for one thing; the planner came back planning how to work with its own memory graph. For a moment it read like the agent had become charmingly self-absorbed. The actual cause was duller and more instructive: the recall step hands the planner what it pulled from memory, and that text arrived in the slot the planner reads as requirements. So it dutifully planned against its own context. Garbage in, diligent plan out. The cost there was on my side, not the model’s.
Which is the real lesson of the session, and it generalises well beyond this repo: context you inject is read as instruction. Anything you paste into a prompt — retrieved memory, a document, a tool result — arrives with the same authority as the user’s actual request unless you mark the boundary explicitly. Every system that feeds an agent retrieved material has this problem. Most of them have not noticed yet.
The fix is a boundary between this is what you know and this is what you were asked. That, plus some cleanup and proper progress indicators in the terminal, is where the build goes next.
What this means if you don’t build harnesses
Most organisations will never write an agent loop. They will buy one — inside a CRM, a helpdesk, a document system — and the question they will face is the same one I spent this session on: at which point does a person look at what the machine intends to do?
The answer that works is not “review everything” and it is certainly not “trust it”. It is one gate, placed where a decision is still cheap to change and a human can still understand what they are approving. If a vendor cannot show you where that gate sits in their product, they have not built one.
Watch the session
- The series so far: https://www.youtube.com/playlist?list=PLPbgiIdJb7gE
- How the memory underneath works: https://nowtec.solutions/blog/procedural-graphs-self-evolving-agent-memory/
- Code: https://github.com/nowtec/whale
This article was written with the support of AI tools and reviewed by our team before publication (EU AI Act, Art. 50).
