Once I knew what to build and with what, the next question was how to organise it. The idea of Claude, Jev and Bonsai working together is clear on paper, but how does it work in practice? What is called when and in which order, who depends on whom, and who checks whom?

The plan

The work goes from the top down, in three levels. The whole client is split into milestones, each ending in something that runs end to end: first a client that can only read, then one that can write, then accounts, threads, and so on. When a milestone starts, Claude splits it into steps, and when a step starts, Claude splits it into cards. Detail is added only one level ahead: only the milestone we are working on is split into steps, and only the current step is split into cards. This is called rolling wave planning. Every step ends with a review, and the review may change the plan for the next steps, so there is no detailed plan for work that the earlier work can still change. But there is always a more or less clear picture of what lies ahead and what is still left to do. The diagram below shows the whole cycle.

flowchart TD
    M["Milestone<br/>(e.g. a client that can write)"] -->|Claude splits the current milestone| S[Steps]
    S -->|Claude splits the current step| C["Cards: signatures,<br/>frozen tests, task"]
    C --> L[["Card loop<br/>(Bonsai writes, checks, Jev decides)"]]
    L --> R[Step review by Claude]
    R -->|next step| S
    R -.->|may change the plan| M

The unit of work is a card: one small task for the executor (normally Bonsai), usually a few functions in one file. Before a card goes anywhere, Claude has already written everything around it: the types and function signatures with empty bodies, the module’s description, and the tests. The tests are frozen. Bonsai sees the task, the files it may change and the tests, and fills in the bodies. If a test file changes by a single byte, the attempt does not count, so the model cannot pass a test by rewriting it. For a model working on its own this is the most important guard.

The cards are run by an orchestrator, a separate program that Claude wrote. For each card it asks Bonsai for code and then checks the result, cheapest checks first:

  1. Did the model touch only the files it was allowed to touch?
  2. Does it compile, and does clippy have nothing to say?
  3. Does the code break any of the project’s mechanical rules, such as which crate may depend on which?
  4. Do the tests pass?
  5. Only then Jev: questions that a machine cannot check, like “does the code do what the task describes” or “does every function belong to the module’s stated responsibility”.

The first four checks cost nothing and are exact, so Jev only sees code that already works. When a check fails, the errors go back to Bonsai for another attempt. Jev also looks at the failure and decides whether it is worth retrying (a typo, a wrong method name) or whether the card should go back to Claude (the task itself looks wrong, or the model is going in circles). After three failed attempts the card goes back to Claude anyway. The second diagram shows one card’s way through this loop.

flowchart TD
    B[Bonsai writes the code] --> G1{"Only the allowed<br/>files changed?"}
    G1 -->|yes| G2{"Compiles,<br/>clippy clean?"}
    G2 -->|yes| G3{"Project rules<br/>hold?"}
    G3 -->|yes| G4{"Tests pass?"}
    G4 -->|yes| J{"Jev: does the code<br/>do what the task says?"}
    J -->|yes| A[Accepted, merged into the step]
    J -.->|not sure| JD[Claude as judge]
    JD -.-> A
    G1 & G2 & G3 & G4 & J -->|no| F{"Jev: what kind<br/>of failure?"}
    F -->|"typo, local mistake:<br/>errors go back"| B
    F -->|"card looks wrong,<br/>model goes in circles,<br/>attempts used up"| E[Back to Claude]

There is one more participant for the start. When I searched for how Jev is used, I found the recommendation to calibrate it on your own tasks before relying on it fully. So Claude was added as a judge: every question Jev answers is also put to Claude, and while this calibration is on, Claude’s answer decides (the dashed arrows in the second diagram). On the first step Jev cost about 300 times less than Claude for the same questions, which is the reason to want it to take over.

Bonsai (Bonsai 2 27B by PrismML) was chosen for a simple reason: on my machine, with one 12 GB graphics card, it had a reasonable balance between speed and quality, about 56 tokens per second with 128K tokens of context. A better candidate could probably be found, but at that moment it was a model that definitely worked, had a good context size, and I did not want to spend time searching for another one.

An independent review of Bonsai said that it plans well and codes poorly in agentic tasks. Fixed signatures and frozen tests were meant to compensate for exactly that: the model does not have to design anything, only to fill in bodies until the tests pass.

The first run

The first step was the client’s model: pure view state, room list, timeline, dates, previews. Six cards, 75 frozen tests. One card of six passed on the first attempt, one more on the second, and four came back to Claude.

When I looked at why, only one of the four was Bonsai’s failure: it converged on the answer, but ran out of attempts on the way. The other three were not its fault:

  • The orchestrator itself had a bug. Bonsai’s code had passed every check, and the last thing left was to ask Claude, as the judge, the same questions Jev had answered. That request failed: the orchestrator named each question after the project rule it checks, with names like R:S4, and the colon is not allowed in the format Claude’s interface expects for these answers. So a correct card came back as a failure.
  • One card asked for a function that returns bool when an operation fails. The project’s own rules say that failures are typed errors. Bonsai followed the card, and Jev correctly rejected the code for breaking the rules.
  • One card asked for date calculations and said “use Hinnant’s algorithm”, without writing the algorithm down. Bonsai spent its whole token budget twice trying to derive it and did not produce a single line of code.

So in this scheme the architect’s mistakes look like the executor’s mistakes. A badly written card shows up as a failed attempt, and from the outside it is hard to tell which side is wrong.

What changed

The fixes went to where the problems were. The orchestrator got its bug fixed and a check that catches it before a run. The card with bool returns a typed error now. The date card got the formulas themselves, checked against Python’s datetime for every year from 1 to 9999. And the process for writing cards got two new rules: a known algorithm is written out, not named, and every signature is checked against the project’s rules before the card is cut.

The more general lesson is that the pipeline has to tell these failures apart. That is why Jev classifies every failure, and why “the card itself looks wrong” goes straight back to Claude instead of costing Bonsai more attempts.

What Bonsai itself does with the cards it gets is the subject of the next post.