Back

AI Coding Workflows: From Cloud to Local


Most arguments about AI-assisted development are arguments about which model is best. That question has a short shelf life and, more importantly, it is the wrong unit of analysis. A coding agent is an arrangement of parts: a harness that calls tools, an inference provider, a model doing the planning, possibly another doing the typing, and a physical location where the computation happens. Fix the arrangement badly and the best model in the world will still burn tokens re-reading files it already understood.

The useful skill is not choosing the best coding model. It is designing a workflow in which the model, provider, execution location, and worker roles can change without changing the engineering contract.

I first encountered this framing in DeepLearning.AI's AI Coding Workflows: From Cloud to Local, built with JetBrains. Its experiment rebuilds one small Python web app across eight configurations and records what each change does to context, tool calls, time and cost. That data is genuinely useful and I have summarised it in the case study at the end — but the argument below is about what it implies for any repository with explicit constraints and executable validation, which for me usually means a C++ codebase with a build system, a test suite, and interfaces whose misuse is expensive.

Two results are worth stating up front, because both contradict what I expected:

  • Splitting work across subagents made the first runs more expensive, not less. Delegation is an investment that only pays once the worker role changes model.
  • Moving work off the expensive model did not remove context pressure. It relocated it onto the orchestrator, which then became the largest consumer in the run.

1. A Coding Workflow Is More Than a Model

Separating the harness from the model is the move that makes everything else visible. The harness reads instructions, calls tools, runs commands and manages the loop; the model only decides what to do next. Once those are distinct, three more parts separate out, and each is a decision rather than a given.

Part What it decides What you inherit by default
Harness Which tools exist, what is permitted, how work is delegated Whatever you installed, plus its model ecosystem
Inference provider Whose hardware runs the model, and the price per token The vendor bundled with the harness
Planner model Decomposition, delegation, review, accept/reject The largest available, for everything
Worker model The mechanical production of code Also the largest available
Execution location What leaves the machine, and what a run costs at the margin Someone else's data centre

These are dials, not a ladder with a best setting at the top. A concurrency-sensitive refactor and the mechanical addition of a serialization function are not the same job, and there is no reason they should run on the same model in the same place.

What makes the dials turnable is the engineering contract: the written constraints, the executable validation, and the delegation boundary between planning and implementation. If those three live in the repository, swapping a model is a configuration change. If they live in a chat transcript, they leave with the session, and every swap is a rewrite.

2. Build a Repeatable Evaluation Harness

You cannot compare configurations unless each one receives the same task, the same constraints, the same starting revision, and the same judgement. Four artifacts, under version control:

  • Intent — what the software does and who it serves.
  • Constraints — the decisions already made, which are not the agent's to revisit.
  • Roadmap — the work split into phases that can be implemented and judged one at a time.
  • Acceptance tests — owned by whoever specified the phase, and off-limits to the worker.

The constraints document does the heaviest lifting, because it closes the decisions an agent would otherwise make silently and differently on every run. For a C++ repository that means being explicit about the things a plausible-looking diff can quietly violate:

  • Language standard and the compilers that must keep working.
  • Warning policy, and whether warnings are errors.
  • Sanitizer configuration the tests run under.
  • Dependency manifest and whether adding to it requires approval.
  • API and ABI stability boundaries — which headers are contracts and which are internal.
  • Performance budgets, where a correct-but-slower implementation is a defect.

Without that, one run adds a dependency, another redesigns an interface, a third picks a different concurrency model, and you are comparing engineering decisions rather than configurations.

Beyond the contents, three properties do the real work.

One command decides the outcome. Every run must end in the same invocation returning the same kind of exit status — cmake --workflow --preset ci, which configures, builds and tests in one invocation, or whatever equivalent wrapper your project uses. That command is the scoreboard: it converts an impression into a result you can record beside a token count. Make sure it actually rebuilds — a bare ctest will happily test stale binaries after a source or build-system change, which is exactly the failure a worker will not notice and you will not see in a green result.

The scoreboard is not writable by what it scores. Acceptance tests belong to whoever specified the phase. If a worker can edit them, a run can pass by weakening the check instead of meeting it. Workers may add unit tests next to their code; those are output, not scoreboard.

Every run starts clean and ends reverted. A fresh context per run, and a return to the same commit afterwards, so the next configuration is not inheriting its predecessor's half-finished state or conversational memory. This discipline is worth keeping outside the experiment too — carrying a long context into a new task is the cheapest way to degrade quality without noticing.

3. The Real Economics of Delegation

The standard advice is to split work across subagents so that each gets a small, focused context. The stated reason is sound: as a context window fills, output quality degrades even when everything still technically fits, because attention spreads across more material and details in the middle lose weight. A large model on a small task barely notices. A small model does not have the window to begin with.

The implied conclusion — that splitting the work therefore saves tokens — is wrong, and the measurements say so clearly. Delegating each phase to a fresh subagent on the same model made the orchestrator leaner and the total bill larger: roughly 50% more context and turns, 20% more tool calls, and a higher cost than the single-context baseline.

The mechanism is obvious in retrospect. A single long session reads a file once and keeps it. Every handoff re-establishes context the previous session already had: the worker reads the same headers, rediscovers the same conventions, and returns a summary the orchestrator must then absorb. With one model in both roles you are paying premium rates for that duplication and receiving nothing in exchange.

Delegation is a precondition, not a result

You cannot put a cheaper or local model on implementation until implementation is a separable, well-scoped job with an explicit interface. The cost increase from splitting the work is the price of building that interface. Judge it as an investment and check the return at the next step — not at this one.

The second correction is subtler and outlasts any particular pricing. When the work moved to eight small workers instead of two large ones, the average worker session dropped by roughly a factor of six — and the orchestrator's context grew almost eightfold, from 90K to 712K. Total context barely moved. Someone has to compose eight briefs and review eight results, and that someone is the expensive model.

So context pressure relocates rather than disappearing. Two practical consequences: measure the planner and the worker separately or you will congratulate yourself on a saving that moved next door; and treat orchestration itself as a workload to be designed, because past a certain granularity you are paying more to describe the work than to do it.

4. Strong Planner, Cheaper Implementer

Once implementation sits behind an interface, the model behind that interface becomes a variable — and this is where the cost curve actually bends. Keeping planning and review on a capable model while routing implementation to a small fast one produced a clear cost drop in the measured runs, even though turns and tool calls both rose.

The split that matters is between judgement and transcription. In a C++ codebase the line is usually easy to draw:

Keep on the strong model Delegate to a cheap or local worker
A concurrency-sensitive refactor: what the locking discipline is, which invariants hold across threads Applying an agreed signature change across call sites
Ownership and lifetime decisions at an interface boundary Implementing serialization against a fixed schema
Whether a change breaks ABI or leaks an internal header into a public one Adding a bounded CMake target with stated sources, includes and link dependencies
Template and overload design that downstream code will depend on Writing table-driven tests for behaviour that is already specified
Reviewing the diff for the above, and rejecting it Mechanical adaptation of build files, fixtures and boilerplate

The economics only work if the brief is tight. Cheap models are cheap for a reason: given a vague or oversized task they produce mistakes, mistakes produce more turns, and enough extra turns cost more in time and money than using the capable model would have. The mitigation is a smaller, more explicit unit of work — not a better worker.

The same split, in three harnesses

This division is not a workaround; the tooling now assumes it. Both vendor-tied harnesses ship a tiered family designed for exactly this, and the open one lets you assemble your own. The names differ, the shape does not:

Role Claude Code Codex OpenCode
Architect / reviewer
Ambiguous, difficult, or expensive to get wrong: the concurrency design, the ABI question, the review that can reject a diff
Opus Sol whichever frontier model you point it at
Planner / orchestrator
Normal feature work, debugging, refactors — decomposing a phase and writing the handoff packet
Sonnet Terra a mid-tier hosted model via a router
Implementer
Clear, repeatable work with objective checks — which is exactly what a good packet plus an immutable test suite produces
Haiku Luna a cheap hosted model, or a local one

That last row is worth dwelling on, because "clear, repeatable, with objective checks" is not a property of the task you are handed — it is a property you manufacture. A bounded CMake target with named sources and a pass/fail preset qualifies. "Make this module thread-safe" does not. The specification work in sections 2 and 5 is what moves a job from the top row to the bottom one, and the price spread between tiers is the return on doing it.

Mechanically, the assignment belongs in configuration rather than in a prompt. All three harnesses put a delegated agent in its own file under the project, so the worker's tier becomes a committed, reviewable artifact instead of a sentence someone has to remember to type. Claude Code uses Markdown with YAML front matter, where the body is the agent's system prompt:

<!-- .claude/agents/implementer.md -->
---
name: implementer
description: Implements one delegated packet against named paths.
model: haiku
maxTurns: 12
disallowedTools: WebFetch, WebSearch
permissionMode: acceptEdits
---

Implement only the delegated packet, touching only the paths it names.
Write each file's complete final content; never patch by anchor.
Build and run targeted tests as often as you need while working.
Finish by running the scoreboard command exactly once, then stop and
report its result whether it passes or fails. Do not repair after it.

Codex splits the same information between the planner's config.toml and one TOML file per delegated agent, with the system prompt as a developer_instructions string:

# ~/.codex/config.toml — the planner
model = "gpt-5.6-terra"
model_reasoning_effort = "medium"
# .codex/agents/implementer.toml — the worker
name = "implementer"
description = "Implements one delegated packet against named paths."
model = "gpt-5.6-luna"
model_reasoning_effort = "low"
sandbox_mode = "workspace-write"
developer_instructions = """
Implement only the delegated packet, touching only the paths it names.
Write each file's complete final content; never patch by anchor.
Build and run targeted tests as often as you need while working.
Finish by running the scoreboard command exactly once, then stop and
report its result whether it passes or fails. Do not repair after it.
"""

OpenCode uses Markdown with front matter like Claude Code, but qualifies the model with its provider — which is where the open harness earns its keep:

<!-- .opencode/agents/implementer.md -->
---
description: Implements one delegated packet against named paths.
mode: subagent
model: openrouter/deepseek/deepseek-v4-flash
steps: 12
---

Implement only the delegated packet, touching only the paths it names.
Write each file's complete final content; never patch by anchor.
Build and run targeted tests as often as you need while working.
Finish by running the scoreboard command exactly once, then stop and
report its result whether it passes or fails. Do not repair after it.

Change that one string to lmstudio/<model-id> and the same worker, with the same brief and the same guardrails, runs on your own hardware instead of someone else's. Nothing else in the file moves. That is the thesis of this article reduced to a single line of configuration — and the reason the open harness is worth the setup cost even if you never leave the cloud.

One thing these three files do not do is confine the worker to the paths its packet names. permissionMode: acceptEdits and sandbox_mode = "workspace-write" are coarse boundaries: they decide whether the agent may write in the working directory at all, not which files it may touch. The named-path restriction lives in the body, which makes it advisory — a distinction section 6 takes seriously, because path-level enforcement is available in some harnesses and has to be replaced by review in the others.

The vocabularies differ; the levers are largely the same. Every one of these files carries a model choice and some way to restrict what the worker can reach — though, as the table shows, they do not all give you the same control:

Lever Claude Code Codex OpenCode
Worker tier model: model model:, provider-qualified
Loop ceiling maxTurns: none per agent — see below steps:
Reachable tools tools: / disallowedTools: sandbox_mode, mcp_servers permission: keys
Write scope coarse (working directory) coarse (workspace) fine (per-path allow/deny)
Behaviour brief Markdown body developer_instructions Markdown body
Scope of model choice one vendor's family one vendor's family any provider, cloud or local

The distinction that matters is between the behaviour brief and everything above it. The brief is persuasion; every other row is enforced by the harness. That is the argument of section 6 — and it is why a reviewer agent should be defined with disallowedTools: Write, Edit, sandbox_mode = "read-only", or a deny-by-default permission block, rather than merely told not to change anything.

Two gaps are worth naming rather than papering over. Codex has no documented per-agent turn or step cap — the session-wide token controls are not the same thing — so termination has to come from the parent workflow: delegate one phase, require a single scoreboard run, and check that the child returned instead of trusting it to stop itself. And only OpenCode offers path-level write rules; in the other two, "these files and no others" is a review obligation, not a setting.

The last row is the one that decides how many of these dials you actually have. A vendor-tied harness gives you a tier ladder inside one family, which covers the cost argument but not the location one. An open harness treats the provider as part of the model identifier, so the cheap-worker move and the go-local move become the same edit.

One caution on comparisons: reasoning effort is part of the configuration, not a detail. The tiers span the same documented effort range, so a high-effort run measured against a default-effort one tells you about the setting rather than the model. Pin it explicitly on both sides or the comparison is meaningless.

The deeper reason this example belongs here: separating a generation number from a durable capability tier is the vendor conceding the argument of this article. The tier is a role you assign; the model behind it is expected to be replaced. A workflow built around roles survives that replacement, while one built around a specific model name does not.

Watch who actually does the work

A failure mode to watch for specifically: the planner, seeing weak output, quietly rewrites the code itself. Cost returns to the single-model baseline while the workflow still looks delegated. Instruct the planner to send defects back to a fresh worker rather than fixing them, and verify it by checking which role consumed the tokens.

The allocation I would default to, in decreasing order of capability: a top-tier model for architecture, roadmap shaping and periodic whole-project review; a mid-tier model for orchestration inside a phase; a cheap or local model for each implementer.

5. Design the Handoff Packet

The handoff packet — the instructions, context and constraints the planner prepares before delegating — is the interface between the two roles, and the main lever that makes the split succeed or fail. It has to be sized for the worker's actual capacity: its context window, its tool-calling reliability, its tendency to improvise.

What belongs in one:

  • The repo-relative paths the worker may write, and nothing beyond them.
  • The paths it must read but never modify — the interface it implements against, the acceptance suite that scores it.
  • The complete required final state in prose: declarations, behaviour, error handling, and which existing behaviour must survive unchanged.
  • Exact identifiers where they are contract requirements: a type name, a signature, a build target, an error string a test asserts on.
  • The scoreboard command, named explicitly, to be run once as the final action.
  • An explicit stop condition — report the scoreboard result whether it passes or fails, and do not continue past it.

What to leave out matters just as much. Do not point the worker at the specification directory; following references costs context it does not have. Do not paste whole files. And do not hand it finished code — if the planner writes the implementation into the packet, you have paid the expensive model to produce it and the cheap one to copy it.

A packet for a typical C++ phase — one new concrete type behind an interface that already exists — comes out roughly like this. The module and type names are placeholders; the structure is what to copy.

Writable paths:
  include/core/component.hpp   (new)
  src/core/component.cpp       (new)
  src/core/CMakeLists.txt      (modify: add the two sources to
                                the existing core target)

Read-only — read these, never modify them:
  include/core/component_base.hpp   (the interface to implement)
  tests/acceptance/                 (the suite that scores you)

Required final state:
  - Component publicly implements ComponentBase and overrides
    every pure virtual member.
  - Fallible operations return the project's error type rather
    than throwing; the failure cases named in the acceptance
    tests map to the documented error codes.
  - Every owned resource is held in an RAII member, so a
    partially constructed object releases what it acquired.
  - Construction either succeeds or fails through the project's
    result type; there is no half-initialised, reachable state.
  - The core target keeps its current public include directory
    and link dependencies; add no new third-party library.

For every writable file, use `write` with its complete final
content; never use `edit`.

While implementing, build and run targeted tests as often as
useful — the compiler is your fastest feedback.

Scoreboard, run once as your final action:
  cmake --workflow --preset ci
Stop after it, pass or fail, and report the result.

Every clause in the required-final-state block is a contract the acceptance suite can check and a reviewer can reject on. None of them describe how to write the code, which is the line worth holding: the packet fixes the obligations, the worker chooses the implementation.

Two properties make this worth the effort. The packet is model-independent — the same brief works on a frontier worker, a hosted open-weight one, and a local model, which is precisely what makes the roles swappable. And it is inspectable while the run is still going: reading the packet tells you whether the delegation matches your intent long before the diff does.

6. Enforce Boundaries with Tools and Permissions

Prompt instructions are advisory. Configuration is enforced. This distinction is not theoretical: in the recorded runs, a worker told not to write complete code obeyed the instruction in one phase and partially ignored it in the next, with no other change. What you write in a prompt or an agent definition body is persuasion; small models in particular have a mind of their own.

So anything that actually matters belongs in the part of the agent definition the harness applies — and it should be written as an allowlist. A rule that permits everything except the specs still leaves the worker free to edit the dependency manifest, the build presets, the acceptance suite and its own definition: every input the comparison depends on.

<!-- .opencode/agents/implementer.md -->
---
description: Minimal implementer for one well-specified phase.
mode: subagent
model: <small-or-local-model-id>
steps: 12
permission:
  edit:
    "*": deny
    "include/core/component.hpp": allow
    "src/core/component.cpp": allow
    "src/core/CMakeLists.txt": allow
  bash:
    "*": deny
    "cmake --preset ci": allow
    "cmake --build --preset ci *": allow
    "ctest --preset ci *": allow
    "cmake --workflow --preset ci": allow
  glob: deny
  webfetch: deny
  websearch: deny
---

This is OpenCode's syntax, chosen because it is the one that expresses path-level write rules directly. Claude Code and Codex give you the coarser boundaries from section 4 — whether the agent may write at all — so the "these files and nothing else" clause stays in the packet and becomes something review has to check rather than something the harness refuses.

Every line maps to an observed failure:

Constraint Failure it prevents
Step ceiling Retry loops that run until the context is exhausted
Write allowlist Editing the specs, tests, manifest or presets to match what was built
Command allowlist Package installs, network fetches, anything bypassing the project's presets
Search and web tools disabled Wandering the repository and exploding its own context
Whole-file writes, never anchored edits A mismatched anchor retried forever — the most common small-model failure
Read the real file before changing it Rewriting a half-remembered version held in context
No recursive listing of generated trees One command flooding the window from build/, _deps/ or a vendored tree
Run the scoreboard once, report, do not repair The rerun-and-fix death spiral after the result is in

That last one needs a distinction that is easy to get wrong, and I had it wrong at first. The worker's inner development loop is not the enemy: compiling and running targeted tests while writing code is the fastest feedback a C++ worker has, and forbidding it makes the compiler useless as a tool. The allowlist above therefore permits the ordinary configure, build and test commands.

What must happen exactly once is the scoreboard — the full run whose exit status you record. After it reports, the worker stops. Without that boundary a worker reacting to a red result will edit and rebuild indefinitely, and in a C++ project each iteration is expensive enough that a great deal of wall clock disappears before anyone notices. One scoreboard run, reported upward, keeps the failure cheap and legible; whether to repair is the planner's decision, not the worker's.

Note the asymmetry with the planner: broad read access, no write access during review. Read-only review is what lets you trust a report about work produced by a model you would not trust to implement unsupervised.

The cost of a path allowlist is that the packet and the agent definition must agree, which means regenerating the permission block per phase. That is a fair trade — it forces the decision about what a phase may touch to happen before the worker starts, rather than in the diff.

7. What Changes When Inference Becomes Local

Serving the model from your own hardware — LM Studio, Ollama, llama.cpp, vLLM — takes the metered inference cost of a run to zero, works offline, and means the model itself never transmits your source anywhere. For code under a confidentiality obligation, that last point can be the entire justification.

Local closes one egress path, not all of them

Web-fetch tools, package installs, MCP servers and telemetry in the surrounding tooling can still send data outward. If confidentiality is why you went local, audit the tool list, not just the model endpoint.

What gets harder is specific and predictable:

Constraint Symptom Mitigation
Small context window The worker loses the earlier half of the task Smaller phases; self-contained packets; never reference spec files
Weaker tool calling Malformed or repeated edit calls Whole-file writes; step ceiling; one permitted command
Slower generation Minutes per file on consumer hardware Quantisation sized to available memory; keep worker output short
Loose instruction following Unrequested changes, invented dependencies Deny-by-default permissions rather than prose
Platform-specific model builds Identifiers differ between hardware-specific formats Read the served model ID from the runtime rather than copying it

The design consequence is that the unit of work is sized for the weakest participant. In the measured runs, one roadmap phase had to be split in two before a local worker could complete it. Splitting costs a capable model nothing, so the granularity should be set by whatever you intend to run at the bottom end. For a C++ project that argues for phases scoped to a single target or a single translation unit's worth of behaviour, with the interface fixed beforehand by the planner.

One piece of local-inference advice runs against instinct and is worth repeating: do not maximise the served context window. A larger window on a small model invites exactly the oversized, unfocused sessions that make small models fail. Keep the worker's context modest on purpose and control size through the packet instead.

The honest summary of the state of the art is that the weights are ahead of the harnesses. Most of the work in making a local worker succeed is hand-written guardrails of the kind in the previous section, because few frameworks ship that scaffolding yet. That is the layer worth watching — more than the model leaderboards.

8. What to Measure

Run each configuration against the same phases and record the same columns, split between planner and worker. The split is more informative than the totals, because delegation is precisely a claim about moving work between those two columns.

Metric How to read it
Total context processed Tokens billed and re-read across the session. A cost and repetition measure — track per role, or you will miss relocation
Peak and average active context How full the window actually got on a given turn. This, not the total, is what predicts degraded output
Tool calls An activity proxy, not a work measure — a full build and a one-line read each count once
Turns Interaction style, not work done — see the caveat below
Wall-clock time Useful but noisy; hardware load and network affect it
Metered cost Zero for local inference, which is the entire point of going there
First-pass validation result The correctness signal, taken before any repair by planner or human
Interventions How often you had to step in — the cost that does not appear on any dashboard

Separating the two context measures matters because they answer different questions. A session that reads the same header twenty times has a large total and a small active context: it is expensive but not confused. A single turn carrying an entire subsystem has the opposite profile, and that is the one that produces subtly wrong code. Delegation improves the second while often worsening the first, which is precisely why reporting only the total makes the trade invisible.

The turns caveat is not pedantry. In the fully local run, total turns rose from 6 to 45 while tool calls went from 51 to 57. Seven times the turns for essentially identical tool activity: the models were simply taking more, smaller steps between actions. Ranking configurations by turn count would have produced a completely wrong conclusion.

Intervention count is the one most often omitted and the one most likely to reverse a decision. A configuration that is an order of magnitude cheaper but needs three corrective rounds and half an hour of your attention is not cheaper in any sense that matters for paid work. It may still be the right choice for a personal project where your time is not billed.

Finally, run each configuration more than once. These systems are stochastic; a single green result proves less than it appears to.

9. Choosing a Configuration per Task

The measurements produce a preference, but the choice is usually settled by the nature of the work rather than the benchmark table.

Situation Reasonable configuration
Novel architecture, unclear requirements, a subtle bug in threading or lifetime Single capable model, one context. Judgement is the bottleneck; delegation only adds overhead
Well-specified phases in an established codebase Capable planner, cheap implementers. The best default for routine work
Cost pressure, or unwillingness to depend on one vendor Open-weight workers behind a router, planner unchanged
Confidential code, offline work, unmetered experimentation Local worker, capable planner. Phases sized accordingly
Mechanical work with strong test coverage Fully local, with review as the only cloud step — or no cloud step at all

Mixing is the mature answer. The constraints, the roadmap and the acceptance suite are the durable assets; the model configuration is a per-task dial. A project with that contract in place can run a local worker on boilerplate in the morning and a frontier model on a data race in the afternoon without changing anything about how the work is described.

10. A Compact Case Study

The figures quoted throughout come from the course's experiment: one small FastAPI application — a home page, a list view, and a submission form — specified in three Markdown files and rebuilt from scratch in each configuration, with a fresh context each time and a revert in between.

# Configuration Key figures
1 Cloud harness, capable model, single context 19 turns, 28 tool calls, 474K context. A subagent spawned by the harness itself took 54% of context
2 Same model, one subagent per phase Planner 217K → 192K; workers 257K → 511K; total context and turns +50%, cost up
3 Capable planner, cheap workers Turns +50%, tool calls +48%, context +29% — and cost down notably. Context per worker turn 21K → 17K
4 Open-source harness, router, open-weight model 25 turns, 38 tool calls, 530K, ~$0.02. Cheaper tokens, not better orchestration
5 Same, one subagent per phase Planner down to 90K; workers 94% of context; total context +179%, cost ~3×
6 Capable planner, small workers via agent definition 8 workers instead of 2; per-worker context 694K → 110K; planner 90K → 712K; total context +8%, cost −28%
7 Cloud planner, local worker (12B, quantised) Workers 117K across three phases; planner 69% of context; ~$0.02 total; 8m52s
8 Fully local (27B planner, 12B worker) Planner 178K, workers 158K, total context −11%; turns 45 vs 6 for 57 vs 51 tool calls; $0.00

Rows 1–6 are a controlled comparison: same task, same phases, same prompt shape, one variable moving at a time. Rows 7 and 8 are not. Reaching a local worker required changing the workflow as well as the model — the roadmap was split from two phases into three, the worker gained the guardrails described in section 6, and the single-shot prompt became one run per phase. Those rows measure a different way of working, not just different weights, and their totals cover three phases rather than two. Read them as evidence that local inference is reachable, not as a like-for-like delta against row 6.

With that caveat, three findings generalise beyond the toy project. Rows 1→2: delegation on a single model costs more and buys only the interface. Row 6: shrinking worker sessions inflates the planner — the work relocates. Row 8: a 27B model on a laptop produced task briefs that held up against a much larger hosted model, and completed two of three phases with no reported defects; the third failed on an HTTP redirect detail caught by a test and repaired by delegating back to the worker.

How much weight to put on these numbers

Each row is a single recorded run of a deliberately small application, on one machine, with the models available at the time. They are evidence about direction and magnitude — that delegation initially costs more, that context relocates, that turns mislead — not benchmarks to reproduce. The methodology transfers; the figures do not.

Conclusion

The configuration that wins today will be obsolete within a year, and the models named in any article about this will age faster than the article does. What survives is the contract: constraints written where any agent can read them, one command that settles whether the work is done, acceptance tests that the worker cannot touch, and a delegation boundary explicit enough that the thing on the other side of it is replaceable.

Build that and the dials become real. You can put a local model on mechanical work and keep judgement in the cloud, or move the whole pipeline in-house when the code is confidential, or go back to a single capable model for a problem that is genuinely hard — and in each case you are choosing, with evidence, rather than inheriting a default.

Start with the smallest version: pin the constraints, wrap validation behind one command, make the acceptance tests immutable, and write one handoff packet by hand. Everything else in this article is a configuration change on top of that.

Source

The measurements cited here are from AI Coding Workflows: From Cloud to Local, a short course from DeepLearning.AI and JetBrains taught by Paul Everitt; its companion repository holds the specifications, subagent definitions and prompts. For the specification practices this workflow depends on, see also AI Spec-Driven Development.