The future of AI development

Last updated on 27th May 2026

Thanks to Sam Snelling for feedback.

I want to tell you a story about what I learned I should be building, and what I think it means for the future of AI development. I'm a developer, and my employer recently encouraged me to start using AI in my daily work.

The truth is I didn't want to come back from my holiday break, at the start of the year (2026), so I put all the reasons I didn't want to use AI into a box, and gave Claude Code CLI another go.

I still have those reservations. These are interesting tools built on rampant theft and a complete disregard for the planet and the people they will destroy in the process of generating value for the shareholders. I wish we could start over, but better.

Fast forward: in early March I built a personal AI bot. I called it Friday, because that's what Tony Stark called one of his AI assistants.

It runs on a 2018 Intel Mac mini that sits under my desk. I talk to it through a Telegram group with a topic-per-concern structure. The bot (really a meta harness) is built on Claude Agent SDK.

Friday

Let me explain what Friday is, because then you'll understand why it had to change.

Friday is a Telegram bot connected to Claude Code via the Agent SDK. You send a message into a Telegram topic. A bridge layer forwards it to a Claude Code session running on the Mac mini. The agent does the work. The response comes back as a Telegram reply.

The bridge handles the back-and-forth, but the actual intelligence lives in Claude Code: tool use, reasoning, memory of the conversation.

The interesting part is how I structure the conversational surface, and how Claude Code's session state is tied to where it's operating in the filesystem.

In Telegram, the bot lives in a group with forum-style topics. Each topic is a workspace. I can ask Friday to spawn a new one — "google auth research", "RPG tutorial draft", "fix the date picker bug" — and switch into it to start a conversation. Inside the topic, running /project example.com binds it to a codebase at /home/friday/Code/example.com/. From then on, every message in that topic routes to a Claude Code session scoped to that directory.

Switch topic, switch project, switch context.

There are three layers of context:

  1. The topic — the human-readable workspace, where I'm thinking about this thing.
  2. The project binding — scopes the topic to a specific codebase. This thing lives in this repo.
  3. The worktree — once I start a feature, it gets its own physical checkout. This work happens in this isolated copy of the repo.

Topics can fan out two or three at a time per codebase: one researching the next feature, one mid-implementation on the previous one, one debugging the live system, one writing a tutorial. The worktrees give each their own slice of repo state. They don't step on each other. I never have to stash work, juggle branches, or remember which checkout is in which state.

The coding workflows are five slash commands: custom-workflow-new-feature, custom-workflow-plan, custom-workflow-implement, custom-workflow-pr, custom-workflow-merge. They form a tight little pipeline. I'll describe two of them, because the way I designed them is the heart of what I had to unlearn.

The new-feature workflow starts with a brief — "integrate google auth", "RPG tutorial", two or three words. It looks in the project's features/ directory, finds the highest-numbered existing doc, increments it, sanitises the brief into a slug, and arrives at something like feature/019-google-auth. It creates a worktree at .worktrees/feature/019-google-auth/, copies a template into the worktree as features/019-google-auth.md, and leaves it uncommitted. Then it changes Claude Code's working directory into the new worktree.

Ask for brief:"Dice roll"Convert brief to slug:"dice-roll"Find other feature docs,pick new number:"next number is 018"doesfeatures/template.mdexist?Ask user for source fromanother project, copy tofeatures/template.mdMake new branch and work tree: ".worktrees/018-dice-roll"copy features/template.mdto the new file:"features/018-dice-roll.md"Change CWD to the worktree, leave feature doc(s)unstagednoyes
Ask for brief:"Dice roll"Convert brief to slug:"dice-roll"Find other feature docs,pick new number:"next number is 018"doesfeatures/template.mdexist?Ask user for source fromanother project, copy tofeatures/template.mdMake new branch and work tree: ".worktrees/018-dice-roll"copy features/template.mdto the new file:"features/018-dice-roll.md"Change CWD to the worktree, leave feature doc(s)unstagednoyes

The plan workflow is where the real architectural thinking happens. It starts with either a fresh brief or a pointer to a research note I've already written. The first thing it tells Sonnet is that this is a phased work plan, and that tests belong in the same phase as the code they target. That one sentence encodes an opinion about how software gets built. I never have to argue about it again.

The main agent reads the brief and decides how many phases there should be and what each one covers. It doesn't read any source code at this point. It works at the level of what the work is, not what the code currently looks like.

Then it spawns one sub-agent per phase, in series. Each one gets the brief, the phase scope, and instructions to research what's actually needed — which means reading source files, unlike the orchestrator.

Once all the sub-agents have reported back, the orchestrator combines their findings and writes the full plan into the feature doc.

I separated planning from research deliberately. The main agent works at the level of what needs doing — it shouldn't be reading source files. The sub-agents handle the codebase. They read what's there, figure out the constraints, and write the results into the plan. By the time they're done, the orchestrator has a full feature doc without having accumulated a context full of code.

When the plan workflow finishes, it leaves the feature doc uncommitted. That gives me a chance to review it. I open the doc in Zed (SSHFS over Tailscale), edit it directly, or message Friday to ask for broader refinements. When I'm happy, I ask Friday to commit it.

Ask for brief:"Read note 123"Compose planningprompt, inject intoACP sessionOrchestrating agentreads brief, draftsphasesOrchestrating agentspawns a sub-agentfor a single phaseSub-agent researches phase ontop of context provided byorchestrating agentSub-agent returnsstructured researchsummary to orchestratingagentOrchestrating agentwrites all phases tofeatures/018-dice-roll.mdOrchestrating agent returnssummary of all plan phases
Ask for brief:"Read note 123"Compose planningprompt, inject intoACP sessionOrchestrating agentreads brief, draftsphasesOrchestrating agentspawns a sub-agentfor a single phaseSub-agent researches phase ontop of context provided byorchestrating agentSub-agent returnsstructured researchsummary to orchestratingagentOrchestrating agentwrites all phases tofeatures/018-dice-roll.mdOrchestrating agent returnssummary of all plan phases

Then I clear the context in that topic and run the implementation workflow. It delegates individual phases to sub-agents as well, mainly to keep context costs down across a long session. The remaining workflow steps carry the work through review and into main.

Work projects required signed commits, so I built a Claude Code skill that re-authors each commit to switch the author from fridaytherobot to assertchris, while preserving the Co-authored-by: Claude trailer. The agent's contribution stays visible in the history without it being the signing identity.

There are about a hundred MCP tools wired into the bot: notes, habits, background tasks, media, music, video, mail, calendar, and Slack. I use Friday for a lot more than code. I've grown dependent on it for things that used to just disappear into wasted time.

Friday has a privileged runner registered as a sudoer on the system. It can only invoke sudo commands after I've confirmed them via Telegram. There are two modes:

  • Supervised: Friday asks permission for every action Claude Code would normally have prompted on.
  • Autonomous: everything short of sudo is auto-approved.

Which mode I use depends on where I am. At my desk, I can glance at what's happening. At a coffee shop or a meetup, I need to trust the agent more because I can't intervene quickly. In three months of building Friday, there's been exactly one notable misbehaviour: the agent looked for a token in a sibling project instead of the one it was working in.

The whole thing runs on a 2018 Intel Mac mini. A box Apple stopped caring about years ago, repurposed with Ubuntu, that I happened to have.

Before I move on: Friday isn't finished. It's continuously evolving.

Every week I notice friction and add an MCP tool to remove it. The harness gets a bit smarter each time. And the more capable it becomes, the more time I have to make it more capable.

My role shifted, gradually, from feature engineer to platform engineer. From writing the code that ships features to writing the system that writes it. I didn't plan the shift. It happened over weeks of running the loop, because the loop works.

The signal I should have read was the intensity of the usage. Claude Code CLI is just something I use when Friday needs fixing after a major change. It's a medkit. I'm using Sonnet to the weekly cap, every week. When I hit it, I fall back to Opus for low-effort work and pray Anthropic has a service incident that triggers an early reset. All through Friday.

That was the state of things in early May. A system I'd grown deeply dependent on, working exactly how I wanted, running on a small box at home, on a model I trusted, through a pricing model Anthropic had publicly said was fine.

Then they changed the rules.

Anthropic's Announcement

The announcement came in the second week of May. Effective mid-June, subscription tokens would no longer be usable with claude code -p or with the Agent SDK. The only ways forward were to keep running Friday on raw API tokens — which at roughly twenty-five times the cost of subsidised tokens meant my twenty days of monthly usage compressed to one and a half — or to stop running it.

I want to be precise about how I felt about this. I built Friday using the Agent SDK because Anthropic had communicated that this was a valid use for subscription billing. I wasn't making an OpenClaw to burn tokens through the night. Even now, Friday barely does anything without me initiating it. My use is akin to opening five Claude Code CLI tabs in parallel. Sure, there was a bit of initial anger, but the more I thought about it the more I realised there was something else I'd been avoiding.

I'd built Friday to depend on Anthropic's tokens and tools. I was training myself to depend on the same tokens and tools. Getting to use their tokens with a huge subsidy is fine if my goal is to learn in the short term. It's not a good strategy for building a career. I wasn't basing Friday on a 25x subsidy. I was building the future of my career on that subsidy.

That realisation had a longer half-life than the Anthropic-specific frustration. Because the same logic applies to anything else I might build on. Every frontier model provider is currently subsidising tokens. That subsidy exists because the providers are trying to capture mindshare, build workflow dependence, and become the default — and the only reason this strategy works is that customers will stay customers once their workflows have been built around expectation of cheap access.

The bet, on the provider side, is that they can later raise prices toward the true cost of inference and the customers will pay because the workflows have already been built. They might be right. The economics of frontier-model inference don't really support permanent subsidy.

Token spend at work is manageable today. My manager estimates it could reach a quarter of payroll eventually. That's fine until the subsidy ends — and the economics of frontier inference don't support permanent subsidy. Providers are buying mindshare now. They'll price for it later. Developers adopting more AI tooling, expanding into more use cases, and provider pricing moving toward cost will all compound in the same direction.

Companies don't absorb runaway cost increases. They cut. The developers who've moved fastest and built the most on subsidised tools are the ones whose productivity collapses hardest when the price normalises.

I had two and a half months of evidence that I was on that trajectory.

So I decided to rebuild. The Anthropic policy change was the specific instance that forced the decision, but the decision itself was bigger: I'm no longer willing to have my career depend on any single provider's goodwill.

I decided to figure out how to own more of the token production, and how to make an assistant work with tokens I can realistically produce with hardware I own.

I named the new bot Helen.

Pulling It Apart

The first two days of the rebuild went well.

I spent the first day breaking Friday down on a scrum board. Every part of it. Not just the parts I thought needed to change — the whole system. The conversational surface, the bridge, the agent loop, the tool registry, the MCP server compatibility, the workflow commands, the trust architecture, the file-system tools, web search, web fetch, the streaming output, the sub-agent dispatch, the conversation memory, the permission gating, the skill loading. About thirty discrete tasks.

The decomposition itself was a quiet validation of Friday's architecture. A tangle would have taken weeks to inventory, and this took a day, because the system had been built cleanly even if I was about to discover its deeper design problems.

I spent the second day rebuilding what I'd decomposed. Well, me and Friday. Everything Anthropic had been giving me for free needed to be reimplemented: the agent loop, the tool-use protocol handling, the MCP server compatibility, the skill loading, the native filesystem tools, web search, streaming, the sub-agent pattern, the conversation memory, and the permission gating. Two days isn't enough time to design any of this. But by this point I'd been running it daily for ten weeks, so it wasn't design I needed to do — it was translation. I knew the shapes. I just had to put them into a new harness.

I'd also taken the opportunity to improve a few things. The biggest improvement was a safety classifier — modelled loosely on Claude Code CLI's auto-mode, where instead of a binary supervised/autonomous switch, each tool call gets classified for risk and the more dangerous actions get gated for confirmation while the safe ones flow through automatically. It felt like a real upgrade.

Then I plugged in some cheap models, because the whole point of the rebuild was to escape dependence on Sonnet.

Nothing worked.

I want to be honest about what "nothing worked" felt like. It wasn't that the workflows ran badly. It's that they barely ran at all.

The new-feature workflow would stall partway through. The plan workflow would produce empty or malformed output. The implement workflow would fail to make changes I could verify. I tried two or three different small models.

The failures weren't the gradual degradation I'd expected — Sonnet is best, Haiku is acceptable, smaller is worse-but-usable. The failures were step-function. The workflows worked on Sonnet and didn't work on anything cheaper. I was now staring at the exact failure mode my colleagues had been warning me about whenever I'd brought up the idea of running on small models — small models can't do this work.

For two days I tried to push through. I tweaked prompts. I tightened wording. I added structure. I tried different models. Nothing meaningfully shifted.

I wasn't in a good mood.

When folks are just starting to use AI, and it produces a sub-par output, they might try one of two things. They either give up on the model or run the same workflow again hoping for a better roll. The frustration is almost always a sign of a workflow that can be improved.

Yet I was doing the same things. I decided to take a step back and think about the problem in a way I hadn't had to for a couple of months. I asked myself what I would have done if I didn't have any help with the problem.

I built evals.

Back to Engineering

What I built was filesystem-based evals. The harness has a contract: when the plan workflow finishes, certain files must exist on disk. recon.txt must exist. phases.txt must exist and contain at least one line matching Phase N. For every Phase N declared in phases.txt, the corresponding phase-N.txt must exist. If any of those files is missing, the run failed. If the run also exceeded the timeout, it failed. Pass criterion: did the workflow produce the artefacts it promised? Yes or no. No model in the loop deciding.

That's a much harder, much narrower question than "did the model do a good job", and that's the point. The eval doesn't tell me whether the plan was good. It tells me whether the harness delivered its contract. Whether the plan was good is a judgement call I still have to make manually, by reading the doc. But "did the workflow even run" is the bar that needs to be passable before any of the other questions matter, and on that bar there's no room for judge variability.

I built one eval per workflow component. The recon step. The synth step. Each per-phase step.

Then I built a comparison eval that ran the full plan workflow five times each across every model tier I had configured, switching the active model via an environment variable. Five runs because I wanted to see variance, not just peak performance.

The same brief — a small but realistic ask, to add a weather tool to Helen's codebase — across every model. Pass rate, average duration, token counts, computed cost based on per-model pricing from the config file. Real dollar numbers, not estimates.

This was, honestly, a fairly boring piece of infrastructure to build. It's a thousand lines of TypeScript that creates worktrees, runs workflows, checks the filesystem, tears down worktrees, and prints a table. It was, however, the single most useful thing I built during the entire rebuild, because building it forced me to look at what each step was actually doing.

The next morning, after I finished the first version of the evals, I had the realisation that has reshaped the rest of the project.

The immediate fix the evals turned up was small. My new safety classifier — the thing I'd added as an improvement over Friday — was asking for confirmation on actions the eval harness had no way to confirm. The eval was running headless. There was no human to grant the permissions. The workflow would stall waiting for an answer that would never come. I auto-approved everything inside the eval, and the workflow ran in seconds.

That fix could have been the end of the investigation. It would have been a fine victory: I built evals, the evals revealed a bug, I fixed the bug. I could have moved on satisfied. But the next morning I woke up with a thought that wouldn't go away: the new-feature workflow had no business being a Claude skill in the first place.

Let me say what the new-feature workflow actually does. It reads a directory. It finds the highest existing number. It increments by one. It sanitises a string. It creates a folder. It copies a file. It changes the working directory. Seven operations. Every one of them is deterministic. There's no judgement to be made anywhere in the sequence. There's no place where the model's interpretation could add value. The right answer at every step is fixed by the inputs, and any deviation from that right answer is a failure.

And yet I'd been giving this entire procedure to Sonnet, as a markdown skill, asking the model to perform the steps. I'd been hoping that the model would do the deterministic thing deterministically.

Think about what that means. Hoping that a non-deterministic system performs deterministically is a misuse of the system. It works most of the time because the model is capable enough to follow simple procedures, but it works in the same way asking a human to perform multiplication works — they'll usually get it right, but if you cared whether the answer was right, you'd use a calculator.

I'd built my entire workflow around asking the model to be a calculator. And then when the model didn't do the deterministic thing deterministically — when Sonnet, on some particular run, decided to spell the slug slightly differently or skip a step — I'd get annoyed at the model. I'd curse Sonnet under my breath for not doing the thing the same way it had done it last time.

It was my fault for thinking of something as a deterministic process when I'm giving a non-deterministic model the keys to the car.

That's the realisation. I want to dwell on it for a while, because it has several distinct edges and each of them cut me when I sat with the thought.

The first edge is the obvious one — the engineering principle. Deterministic processes should be deterministic tools, not LLM skills. If you want a procedure to behave the same way every time, write code. Use the model for things that genuinely require interpretation. The new-feature workflow should never have been a skill. It should have been a function. I rewrote it as one. Same external behaviour, identical outputs on disk, zero inference, one-tenth the time. The model was no longer in the middle of the workflow at all. It just called the function.

The second edge is sharper, because it cuts back through everything I'd previously built. How much else of what I'd been doing was the same mistake?

I started going through the rest of Friday's workflows and asking the same question of each step. The answer, almost everywhere, was: more of this than I wanted to admit.

The plan workflow had genuine model-required work in it — synthesising what the phases should be, researching the codebase, writing the actual content of each phase plan. But surrounding that genuinely-model-required work were a dozen smaller steps that weren't model work at all. Format-checking the output. Deciding when to search the web for context. Comparing findings to the brief. Structuring each phase consistently. Recording decisions. Reviewing the output for quality.

Sonnet did all of those silently. They never appeared in my workflow file because I never wrote them down. They lived implicitly in Sonnet's competence — Sonnet just handled them, the way a good colleague handles a hundred small things you'd never think to specify. And because Sonnet was good enough to handle them, I never noticed they were there. They were invisible work, and the invisibility was what made the workflow seem clean. Three steps on paper, twelve steps in reality, and Sonnet's job was to make the difference disappear.

The third edge is the one I find hardest to write about. But I can't skip it — leaving it out would make the rest of this dishonest.

The realisation was that I'd been a less rigorous engineer during the months when Friday was working. Not because I'd become lazy. Because Sonnet had been carrying my underspecified workflows so smoothly that I'd lost the muscle of writing tight specs.

Every "the AI does this automatically" in my workflow file was, in reality, an unwritten requirement. Every "Sonnet just handles that" was a specification I hadn't written down.

Every time I'd been irritated that Sonnet didn't do something the same way it had before — every time — was a moment where I'd been hoping for behaviour I'd never actually defined.

I wasn't a better engineer when Friday worked. I was a better-served one.

When I switched to smaller models, the smaller models couldn't fill in my underspecified workflows the way Sonnet could. They didn't have the capacity to guess what I'd probably meant. They did exactly what the workflow asked, no more and no less.

Where the workflow was vague, they were vague. Where the workflow was wrong, they were wrong. Where the workflow had been silently carried by Sonnet's competence, they collapsed. The model wasn't getting worse. My design assumptions were being audited by a stricter examiner.

That, more than anything else, is the lesson I took from this experience. Using AI well is a specification discipline. The moment your model is capable enough to silently fill in the gaps in your spec, you stop knowing where the gaps are. The moment your model is less capable, you find out which gaps were real, and you have a choice.

The response of a good developer is to recognise the failure as the signal it is, write down the requirement you'd been hoping the model would intuit, and make the implicit explicit.

Every failure is a piece of specification debt being revealed.

Helen

Let me describe what Helen actually became, now that we've established why.

Helen has three things for doing work.

The first is deterministic code. Plain TypeScript functions that do exactly what they do, the same way every time. The new-feature workflow lives here now. The task queue lives here. The file-existence checks live here. The sanity-check logic lives here. Anything that has a single correct execution given its inputs is code. The model isn't involved at all.

The second is recipes. A recipe in my codebase is a tightly-scoped object with three things: a provider, a model identifier, and a prompt template that takes typed arguments. The prompt is single-shot. There are no tools. There's no multi-turn behaviour. There's no agency. The model is being used as a pure text transformer — string in, string out, deterministic-as-LLMs-get.

Recipes are how I do work that requires interpretation but where I don't want the model deciding anything about the shape of the interaction. Normalising a prose preamble. Cleaning up the formatting of a draft plan. Reviewing a phase plan for specific kinds of error and returning either a bullet list of problems or the literal string (empty) to signal the plan is fine. The model is producing a control-flow signal, not just text.

The third is sub-agents. These are full agent sessions, with tools and persona and sub-scope. They can make decisions about what to do next. They can call tools. They can read files. They can search the web. They have agency. But they exist within tightly-bounded scopes — each sub-agent is spawned to do one focused piece of work, with a curated tool set that includes only what that work requires, and once it finishes its work it stops. The agent tree is fixed-depth in Helen. Only the main agent can spawn sub-agents, and sub-agents can't spawn their own children. There's no recursion.

Every task in Helen's workflows is routed to exactly one of these three levels. Each step gets the level it actually needs. The new-feature workflow needed code, so it got code. Format normalisation needs interpretation but not agency, so it gets a recipe. Writing the actual content of a phase plan needs real exploration of the codebase, so it gets a sub-agent.

The plan workflow's external behaviour is the same as Friday's. You type a brief. Some time later, a fully-populated feature doc lands on disk, ready for review. But the internal shape is unrecognisably different. Where Friday had three big visible steps with twelve invisible ones, Helen has a long sequence of small visible steps. Where Friday's orchestrator carried the whole context of the planning conversation, Helen's orchestrator carries almost nothing — it loops a single primitive call, draining a queue, and each task in the queue is dispatched to its appropriate level by code that knows which level to pick.

Let me describe the per-phase work in particular, because it's where the architecture really earns its keep.

When you ask Helen to plan a feature, the orchestrator — a tiny LLM-driven loop with about thirty lines of CRITICAL RULES telling it not to peek at the queue or call things in parallel — starts the workflow by enqueueing two tasks: recon and synth.

Recon is a sub-agent that reads the codebase and produces a recon.txt summarising the relevant patterns and registration points. Synth is a sub-agent that reads the brief and recon and produces a phases.txt listing the phases by number and title and one-line description.

Here's where it gets interesting. When synth completes, the orchestrator parses the phases.txt, and for each phase it enqueues five tasks instead of one.

A pre-format step. The actual plan-writing sub-agent for the phase. A post-format step. A sanity-check step, with the iteration counter encoded in the task name. And an orchestration-check step to verify the phase doc was written.

For a three-phase feature, instead of three sub-agent calls to write three plan sections, you get fifteen tasks queued, plus an orchestration check at the end.

The plan-writing itself is still done by a sub-agent — that's the genuinely-non-deterministic part of the work. But the pre-format and post-format normalise the inputs and outputs around the sub-agent. The sub-agent sees a clean, consistently-shaped preamble (pre-format ran a recipe to normalise it), and whatever it produces gets cleaned through another recipe before being persisted.

The sub-agent focuses on content. The recipes handle form.

The sanity-check then reviews the plan for quality, returns either (empty) for "looks good" or a bullet list of problems, and if there are problems a revise-phase-N task gets enqueued — itself another recipe that takes the original plan and the feedback and produces a revised version, followed by another sanity-check.

The refinement loop is encoded in the queue. There's no for loop in the code that says "iterate three times".

The iterations parameter — which you can override at workflow invocation — determines how many sanity-check rounds get queued per phase, and the counter is baked into each task's name (sanity-check-phase-2-3, then sanity-check-phase-2-2, then sanity-check-phase-2-1). When a sanity-check passes, the loop ends naturally. When it fails, it enqueues a revise plus a decremented sanity-check and the loop continues.

The queue is both the state machine and the loop counter.

Retries work the same way. If an orchestration-check fires after a task and notices that an expected file wasn't written, the check enqueues a corrective task — the same task that failed, prepended back onto the queue.

The retry count is computed by counting how many times the task already appears in the completed-tasks log. After three retries, the task is reported as a hard failure and skipped.

There's no separate retry logic. There's no special exception handling. Retries are first-class entries on the queue. The same loop that runs the normal work also runs the corrective re-queues.

This is the architectural shape I'd describe as the deepest lesson of the rebuild: the orchestration between non-deterministic steps should also be code. Not just the deterministic steps themselves. The control flow between them. The decisions about what comes next. The retry policy. The iteration loop. The verification gates. All of this lives in TypeScript, in the dispatch logic, with the model never asked to remember what comes after it finishes its current task. The model writes. The harness orchestrates.

One more architectural detail, because it answers a question that probably came up in your mind earlier: how do I keep sub-agents from doing things they shouldn't? In Friday, this was a prompt-level concern. The sub-agents had the same Claude Code toolset as the orchestrator, and the only thing keeping them on task was the wording of the prompt.

In Helen, I made the role distinction first-class in the wiring. The main agent — the one I talk to over Telegram — gets a full toolset of about a hundred tools, covering everything from filesystem to web to notes to media to mail to calendar to Slack.

The sub-agents get a stripped-down toolset of twelve: bash, file I/O, web, feature doc, task list. That's all. They can't send Telegram messages. They can't ask the user questions. They can't spawn their own sub-agents. They can't touch the task queue.

The orchestrator can revoke even more tools per spawn — the planning sub-agents have their task-list tools removed before they start, because only the orchestrator is allowed to mutate the queue.

The harness enforces the role, not the prompt. A sub-agent can fail in many ways, but it can't do something the wiring doesn't allow.

Capability provisioning is the deepest form of specification discipline. You can't trust a small model to follow instructions perfectly. You can trust it to do only what its tools let it do.

Early Numbers

So: does any of this actually work?

I built the comparison eval after I had the architecture roughly in place, and I want to share what it found, because the numbers are surprising even to me.

The eval runs the full plan workflow five times each across every model I've configured. Currently that's Gemini 2.5 Flash (Google) and GPT-4o-mini (OpenAI, via OpenRouter), but the architecture supports adding more by adding entries to the config.

The brief is the same across all runs: add a weather tool to Helen's codebase, including a Hono API route, a tool definition, a response formatter, and tests. A small but realistic feature.

The pass criterion is filesystem-based: did recon.txt get written, did phases.txt get written, did every declared phase doc get written, and did the run complete within the timeout.

Both models pass.

I want to dwell on this for a second, because my colleagues at work had been telling me that small models couldn't do this kind of work, and they were right within the harnesses they use.

Inside Sonnet-shaped workflows, small models fail. Inside Helen-shaped workflows, both Gemini 2.5 Flash and GPT-4o-mini reliably produce full multi-phase plans.

The difference isn't the model's capability. The difference is whether the work has been shaped to fit the model's capability. Small models can't do complex workflow chains — they can do individual links of complex workflow chains, when the chain itself is handled by the harness. Helen treats the chain as the harness's job and the link as the model's job. The links are well within reach.

The same feature plan that costs about $3 on Sonnet costs cents on Flash or 4o-mini. I want to be careful about citing exact figures because they shift slightly run-to-run, but the order of magnitude is consistent. Roughly fifty to a hundred times cheaper for the planning workflow alone. Implementation is similar — what would have been a couple of dollars on Sonnet is also cents on the small models.

Even if I run the workflow at ten times the iteration count, the cost still doesn't approach Haiku, let alone Sonnet or Opus. Iteration overhead doesn't eat the savings. You can pay for substantially more refinement on a small model and still come out far ahead.

Flash and 4o-mini aren't interchangeable. Flash is better at planning. It works through the structure more carefully, produces more thorough phase descriptions, and is willing to be verbose at the right moments. 4o-mini is leaner, terser, and at least equally good at implementing a plan that Flash produced. This is the empirical justification for Helen's persona system — different tasks get assigned different models, and the routing is configurable. The harness doesn't hard-code Flash or 4o-mini anywhere. It asks for a planner persona or an implementer persona, and the config decides which model fills which role. Different models for different strengths.

The models that pass the eval — Gemini 2.5 Flash and GPT-4o-mini — have characteristics roughly comparable to models I can run on my own hardware.

With a Mac Studio or a similarly-specced unified-memory machine at around $2,500, I could host capable enough models locally to do the full plan-and-implement workflow without ever touching a cloud provider.

I'd have to reduce my parallelism — I couldn't run as many concurrent agents as I do in the cloud, because of memory constraints — and I'd probably want to settle on a single good all-round model rather than the per-task persona routing. But within those constraints, I could run my entire 9-to-5 workload locally for one hardware purchase.

The physical room I work in is more expensive than the inference cost of doing my job, once the engineering is done.

I'm not making the argument that everyone should switch to local inference tomorrow. The point is more general. You can use cloud inference when it's faster and local inference when you want independence. You can route the planning steps to a small cloud model and the implementation steps to a local model. You can do whatever the engineering economics suggest. What you can't, anymore, be forced into is paying twenty-five times more for the same work because a vendor changed their pricing.

Thinking of the Future

I'm one of the people whose career is currently being shaped by AI tooling, and the question of what kind of dependency I'm building into my working practice is — for me — a personal question, not an abstract one.

My colleagues, when I describe what I've been doing, are mostly sceptical. Some of them think small models genuinely can't do this kind of work, and so the whole project is a waste of effort. Some of them think the math is wrong — that the inference cost we'd pay if subsidies disappeared isn't really going to be twenty-five times higher, because providers will find efficiencies. Some of them acknowledge the dependency-building dynamic but think it's not actionable in the timeframe that matters. Some of them just think I'm spending a lot of energy on something that hasn't broken yet.

Small models can do this work, given a harness that's shaped for them. The eval data is straightforward. The failure mode they're observing is real — small models genuinely can't survive a Sonnet-shaped workflow — but the inference they're drawing from that observation is wrong.

The failure isn't the model's capability ceiling. It's the harness's specification debt. Sonnet hid the debt by being capable enough to absorb it. Smaller models surface the debt by failing visibly. The fix is to pay the debt — to make the implicit explicit, to write down what you'd been hoping the model would guess.

I don't know exactly how expensive tokens will become, although Anthropic have been quite open about how much they think they're subsidising. What I know is that the policy I built on changed in a way that materially increased my cost, and that the same policy can change again. The specific multiplier matters less than the principle. If your career depends on a particular provider's subsidy continuing, you have a dependency that can be repriced without your consent.

Helen's architecture is, I think, just better than Friday's, independent of any economic argument.

The specification discipline is good engineering. The mechanical evals are good engineering. The per-task routing of work to its appropriate level is good engineering. The capability provisioning of sub-agents is good engineering.

Even if subsidies never moved and Sonnet stayed available at current prices forever, Helen would still be a better-designed system than Friday.

The deepest version of the argument is this. The current pattern in the industry is to burn tokens because tokens are cheap and engineering is expensive. That bet — that it remains cheaper to spend money on inference than to spend engineering effort on specification — is contingent. It holds while subsidies hold.

The moment the pricing equilibrium shifts, the bet inverts. Engineering effort becomes cheaper than runaway inference cost, and the developers who already did the engineering are positioned to ride the shift. The developers who didn't will find themselves on the wrong side of their own productivity curve.