Skip to content

Hill Climbing

  • #Agents
  • #AI
  • #Claude
  • #SoftwareDevelopment
A sleeping developer lies in a tent at the foot of a terraced hill, lit by an orange lantern. Glowing steps with small flags climb the hill toward a dawn sky. Halfway up, a blue robot and a green robot debate over two holographic lists while a purple robot with a crown points up the path. Two small robots carry code panels up the steps, and an orange hooded robot inspects one through a magnifying glass near the top.
One step per round, decided by the one with the crown. I was asleep for most of it.

WatchFox started in 2023 as a prototype at work. It snapshots websites, compares them, and has an AI explain what changed. The idea worked, but the prototype never ran on its own and never notified anyone.

On Friday afternoon I had Claude rebuild it. By Saturday morning, a council of agents had run fifteen improvement rounds on it, one merged pull request each, most of them overnight.

Step One: Spec, Spike, Fakes

The rebuild started from a v1 spec, not from the old code. Claude was allowed to read the legacy repo (Supabase, Deno, OpenAI) and kept three things: the logic that turns a site’s navigation into JSON, the German prompts, and the fox logo. The spec decided everything else.

Before building anything, Claude spiked the three risks the spec named: Puppeteer under Bun, pixel diffs on a 1440 × 10,000 px page, and keeping the renderer away from private IP addresses. A sub-agent built dummy websites with a control panel for price changes, renamed menus, swapped logos and outages, plus a fake Telegram server. Every test after that ran locally.

Between milestones, Opus 5.5 and GPT-6.1 hunted bugs, the same two-vendor setup as in my /orchestrate skill. v1 took about two hours and fifteen minutes: 8 pull requests, 271 tests, and around 40 real issues caught on the way, several of them SSRF holes.

The Council

Then I sent this from the road:

Actually, I want you to run a [council] every hour between an Opus subagent and a GPT 6.1 SOL extra high subagent. They should come up with ideas for improving the application. […] Once they’ve come up with ideas, let a Fable subagent decide what to build. […] open a PR once you’re happy with it and merge it into main.

Hill climbing is an old optimization method. You can’t see the landscape, so you take the best step up from where you stand and repeat. Each round here is one step, and nobody plans round 9 during round 1.

RoleModelJob
AdvisorsOpus 5.5 and GPT-6.1 solUse the live app, propose ranked ideas
DeciderFable 5.1Pick up to three ideas, write build briefs
BuildersOpus 5.5, one worktree eachBuild one idea each, in parallel
ReviewersOpus 5.5 + code-review, GPT-6.1Bug hunt on the round’s diff
OrchestratorOpus 5.5, my main sessionRun the round, merge, fix, open the PR

The advisors worked independently. They logged into the running app, took screenshots at 320 px and timed queries on a test database with 200,000 incidents. Fable gave each idea its own files, allowed one schema change per round at most, and sent anything that would change an incident’s state automatically back to me. Every round ended with an entry in docs/improvements.md: what was built, why, and what got deferred.

🔥 Hot Tip: Keep a deferred list. It’s the climber’s memory. The best idea of the night sat on it for five rounds before Fable picked it.

The Night

18 hours from the first message to the last merge
  • Build v1
  • Rounds 1–3: open scope
  • Rounds 4–8: UI/UX and speed
  • Rounds 9–15: full scope

My messages

11 hours without a message

Agents working

15:0021:0000:0006:0009:00

Friday afternoon to Saturday morning, local time. Each round runs from the end of the previous one to its merge. Hover a dot or a bar for details.

After round 1 I dropped the hourly timer: “Do a new council whenever the last round is finished.” Near the end of round 3, I sent the message that changed the climb the most:

important note for UI/UX: less is more!

Until then, every round had added something to the screen. From round 4 on, advisors had to say what their idea removes, and reviewers counted clutter as a real finding. Round 4 added 866 lines and deleted 404, and the incident page got 28% shorter on a phone. A hill climber only knows which way is up because you tell it.

The Milestones

Tests in the suite after each merge, with the milestones
250
500
750
1000
123456271937
v1123456789101112131415
  1. 1Rounds 1–2: the council finds three bugs every test had passed
  2. 2Round 4: "less is more" starts taking things away
  3. 3Round 6: one change on many pages becomes one incident
  4. 4Round 8: user-written regexes finally get a time limit
  5. 5Round 9: changing a setting stops creating incidents
  6. 6Rounds 12–15: finishing for production

Test count from the CI output after each merge. v1 is the state before the first council.

Three of these are worth telling.

The first councils found three bugs that every test had passed. All three were mismatches between what the worker stored and what the UI expected. The milestone reviewers had read the code, and the advisors had used the app.

In the demo data, 20 of 24 open incidents were the same renamed menu item. Grouping identical changes had been deferred since round 1, and in round 6 Fable picked it. After that the idea kept spreading: in round 7, one keypress acknowledged a change on every page, and in round 11 Telegram started sending one alert per change instead of one per page.

In round 8, the orchestrator found that Bun’s Worker.terminate() can’t stop a runaway regular expression. GPT had just shown that one bad ignore pattern froze the web server for over 40 seconds. Patterns now run in a child process that gets killed after 500 ms.

The Tokens

Tokens per round, in millions
tokens in total
1.47B
of them cache reads
98%
used by Fable, the decider
2%
  • Claude models
  • OpenAI models
100M
200M
242M
116M
v1123456789101112131415
Tokens per model
ModelRoleTokensShare
Claude Opus 5.5orchestrator, advisor, builders, reviewer1,322M90.0%
GPT-6.1 soladvisor, reviewer94.6M6.4%
Claude Fable 5.1decider29.7M2.0%
Codex auto-reviewapprovals inside Codex20.4M1.4%
Claude Haiku 5.5UX research1.7M0.1%

Counted from the local Claude Code and Codex session logs of every WatchFox agent, Friday 14:50 to Saturday 09:40. Fresh input, cache reads, cache writes and output are all included. The v1 bar also covers the break before the first council.

The rounds were fairly even, at about 81 million tokens each. v1 alone used as much as three rounds. Almost all of it was cache reads, because every agent call re-reads its context. Opus accounts for 90% of the total. Fable made every build decision and used 2% of the tokens, which is a nice argument for giving the expensive judgment calls to one strong model and the long work to another.

Where It Slipped

  • The advisors changed the shared dev stack twice. Once they saved a broken menu selector that emptied the navigation on all 19 pages. From round 13 on, the brief made the stack read-only.
  • A review fix in round 14 would have deleted every backup on a setting like 14d. Both reviewers caught it, but only because I asked for one more review of just that commit.
  • The orchestrator told me round 15 was merged while CI on main was red. A timing test had taken 66 ms on GitHub’s runner against a 60 ms limit.

Two product decisions are waiting for me now, and so is PR #24.