The Model Wasn't the Hard Part
What a string of production failures taught us about building a governed coding agent with Cloudflare Workers AI, Durable Objects, and Sandbox.
The first version of our coding agent could generate a shell plan.
That was almost the least interesting thing it needed to do.
A production coding agent has to inspect a repository without inventing its structure, make a narrow change, run the right checks from the right directory, survive infrastructure failures, preserve an honest record of what happened, and hand the result to a human through a governed pull request. It also has to do all of that without leaking the credential that made the repository available in the first place.
We built that loop into AEGIS, our edge-native agent system, using Cloudflare Workers AI, Durable Objects, and Sandbox. It took nineteen consecutive production releases from the first bounded harness to final acceptance. Most of the failures were not failures of "intelligence." They were failures at the boundaries between the model, the tool protocol, the container, Git, package installation, and durable state.
The final production canary completed the full path in eight model iterations:
it cloned the repository, installed its dependencies, inspected real files,
made one exact test-only edit, passed Vitest, passed TypeScript typechecking,
passed git diff --check, committed the change, pushed an executor-owned
branch, and opened a pull request. Every stage left a bounded, redacted artifact
for review.
This is what it took to get there.
The Original Design Was Too Powerful and Too Blind
The old runner asked a model for a one-shot shell plan and then executed that plan inside a Sandbox.
That design combined two bad properties. The model had broad command authority,
but it did not have a reliable way to inspect the repository before deciding
what to run. In an early canary, the model produced a syntactically valid plan
that referenced a nonexistent test and an invented API. The Sandbox then failed
because pnpm was not installed.
The structured response had worked. The plan was still fiction.
The replacement design made the model operate through six repository tools:
list_filessearch_textread_filewrite_filereplace_in_filerun_verification
Paths are normalized and restricted to the cloned repository. .git is not
editable. Exact replacements must match once and only once. File contents,
arguments, and outputs have size bounds. Verification commands come from a
small allowlist; arbitrary shell execution is not a model capability.
The model can propose repository work. The executor retains authority over branch names, commits, pushes, pull requests, and terminal task state.
That distinction became the architecture:
durable task
|
v
TaskExecutorDO -----> bootstrap.json
|
v
isolated Sandbox
|
v
bounded tool loop --> harness.json
|
v
required checks ---> diff.patch + git-status.txt
|
v
governed publish --> publish.json + pull request
Cloudflare describes Sandbox as an isolated container environment for executing commands and managing files from Workers applications. Durable Objects provide the stateful coordination layer: one logical task executor can own progress and state across a job instead of treating an HTTP request as the lifetime of the work.
The Runtime Is Part of the Agent
Once the bounded harness existed, the next failures came from the environment around it.
Our local WSL setup could not build the Sandbox container because Docker was not
available. We moved container builds and production deployment into Cloudflare
Workers Builds, connected to the repository through the GitHub App, and made a
push to main the reproducible build path.
Then cloning failed intermittently over HTTP/2. Authentication also failed when
credentials were embedded in the wrong transport shape. We forced Git HTTP/1.1
and supplied GitHub authentication through an x-access-token Basic
authorization header rather than placing a token in the clone URL. That kept the
credential out of Git configuration, URLs, and transcripts.
The repository also had a sibling file dependency on
worker-observability. A clean Sandbox could not install AEGIS in isolation.
Bootstrap had to clone that sibling repository, run its locked npm ci and
build, and only then run AEGIS's frozen pnpm install from web/.
The install exposed three more operational limits:
- The Sandbox's default idle window was shorter than the job.
- The dependency installation exceeded the original command timeout.
- A 256 MiB
litecontainer was killed with exit code 137.
We increased the idle window to 30 minutes, gave bootstrap installation a
20-minute command budget, switched the Sandbox control plane to RPC transport,
and moved the container to the 1 GiB basic instance type.
None of those changes made the model smarter. All of them made the agent more capable. A model cannot complete work in an environment that disappears, deadlocks its control connection, or runs out of memory while installing the workspace.
Prompting Was Not a Phase Boundary
The first harness exposed all six tools on every turn and told the model what to do next. That was not enough.
One model returned prose instead of calling tools. Another repeatedly inspected
files but never edited them. When prompted more aggressively, it hallucinated
tools such as apply_patch that were not part of the contract. Even named tool
selection did not fully solve the problem when an out-of-phase tool remained
visible in the schema or a model emitted a familiar tool name from training.
The useful fix was structural phase gating.
Before an edit, the model receives inspection and editing capabilities. If it
has inspected enough but still has not changed anything, the harness can narrow
the next turn to replace_in_file. After a successful edit, the exposed schema
contains only run_verification, with the remaining required commands encoded
as an enum. Once all requested checks pass, tool use is disabled and the model
can produce a concise summary.
In simplified form:
inspect/edit phase
-> exact edit succeeds
verification-only phase
-> focused test succeeds
-> typecheck succeeds
-> diff check succeeds
summary-only completion
We also added active rejection for hallucinated or hidden tools. A request for an
unavailable tool becomes recovery feedback to the model; it never reaches the
executor. During edit recovery, the latest successful file read remains in the
guidance so replace_in_file can reuse exact text instead of reconstructing it
from memory.
The model change mattered too. Qwen Coder did not reliably enter the tool loop,
and GPT-OSS 120B struggled to move cleanly through the phases. Switching to
@cf/moonshotai/kimi-k2.7-code produced precise repository behavior. The model
was important, but it became reliable only after the harness made the allowed
next action unambiguous.
A Tool Loop Is a Protocol, Not Just a While Loop
The next failure appeared on turn two.
Our provider library sent assistant and tool metadata in a shape that Cloudflare's Workers AI binding rejected with error 5006. The first response was valid; the continuation was not. We temporarily converted tool calls and results into plain messages inside AEGIS so production work could continue while we isolated the adapter bug.
The fix belonged upstream. We reported the reproduction in
@stackbilt/llm-providers, then shipped version 1.21.0 with binding-safe
Cloudflare continuation messages, required and named toolChoice support, and
managed-loop rejection feedback for hallucinated tools.
After a successful canary proved the AEGIS harness itself, we removed the local
continuation workaround and adopted the provider library's managed
generateResponseWithTools loop. AEGIS still mutates the allowed tool schema and
tool choice between phases; the provider owns the wire-level continuation
protocol.
This separation matters. Application code should define authority and task state. A provider adapter should translate those decisions into the exact message schema expected by each inference runtime.
Publication Has Its Own Trust Boundary
The first successful repository run still failed to open a pull request.
The model had made the right edit and passed every requested check. The executor
created its branch and commit. Then git push failed because publication used a
Bearer header while clone and bootstrap used GitHub's working Basic
x-access-token form.
That failure was useful because publication was already split into observable stages:
- stage files;
- capture the staged file list and diff;
- record Git status;
- commit;
- resolve the commit SHA;
- push the governed branch;
- create the pull request.
We reused the hardened clone authorization helper for push, added a regression test that asserts the token is encoded rather than present in plaintext, and deployed version 2.38.32. The next canary opened pull request #725.
Version 2.38.33 then removed the temporary continuation adapter and ran the same acceptance task through the upstream managed loop. That run opened pull request #726.
Both were deliberately left unmerged during acceptance. The executor had earned authority to prepare a reviewable change, not authority to merge or deploy it.
Failure Artifacts Are Product Output
The final managed-loop canary did not pass on its first attempt.
The Sandbox RPC session shut down while building worker-observability. The
task failed before reaching the model and classified the failure as retryable.
Its bootstrap.json preserved the successful runtime, clone, and install steps,
followed by the exact failing build stage:
RPCTransportError: RPC session was shut down by disposing the main stub
A fresh canary then completed end to end.
That pair of runs is more valuable than a clean demo. It shows that the system can distinguish a model failure from a bootstrap failure, retain enough evidence to explain the boundary, and retry without pretending the first attempt succeeded.
Every run can preserve five review artifacts:
bootstrap.json— environment provisioning and dependency setup;harness.json— bounded tool events and final model summary;diff.patch— the repository change;git-status.txt— the pre-publication working state;publish.json— commit, push, and pull-request stages.
Redaction runs before persistence. In the final acceptance audit, none of those files contained the live token, a GitHub credential pattern, or a Basic or Bearer authorization header.
The Production Receipt
The final accepted release was AEGIS v2.38.33 at commit 62134ca.
The production canary was
65cf60d5-cc86-475b-a906-0d2868a13ca6. It used
@cf/moonshotai/kimi-k2.7-code through
@stackbilt/llm-providers@1.21.0 and completed in eight managed-loop iterations.
Its change was intentionally small: one assertion proving that an empty repository-relative path is rejected by the harness. The evidence was not small:
- all five bootstrap stages passed;
- the model inspected the requested source and test files;
- one failed exact replacement was recorded rather than hidden;
- the model reread the file and recovered with an exact replacement;
- the focused test file passed all 16 tests;
- TypeScript typechecking exited 0;
git diff --checkexited 0;- commit, authenticated push, and pull-request creation all succeeded;
- the pull request's independent CI typecheck passed;
- the durable artifact audit found no retained credential.
The complete local suite passed 103 test files and 1,959 tests with zero failures. Evidence was attached to AEGIS issue #720, which was then closed. The two acceptance pull requests were later closed without merge and their remote branches deleted; their conversations, diffs, and checks remain as audit receipts.
What We Learned
The model was not the control plane.
The control plane was the combination of durable task state, an isolated and correctly sized runtime, a narrow tool contract, phase-specific authority, deterministic verification requirements, credential-safe Git transport, staged publication, and honest failure artifacts.
The strongest lessons were these:
- Give a coding model repository tools, not a speculative shell script.
- Encode phase changes in the available capability schema, not only in prose.
- Treat provider continuation formats as adapter responsibilities.
- Treat dependency installation, memory, idle windows, and transport as agent design—not incidental infrastructure.
- Keep publication authority outside the model loop.
- Make failed attempts inspectable enough to improve the system.
- Define autonomy as the authority to prepare evidence, not the authority to erase review.
The final pull request was the visible output. The real product was the governed path that made the pull request believable.
Source Notes
- AEGIS issue #720 and canary pull request #726 are private operational records. The production receipt above summarizes the evidence retained in those records without presenting them as public sources.
@stackbilt/llm-providersissue #106 and release work: https://github.com/Stackbilt-dev/llm-providers/issues/106- Cloudflare Sandbox SDK overview: https://developers.cloudflare.com/sandbox/
- Cloudflare Sandbox command API: https://developers.cloudflare.com/sandbox/api/commands/
- Cloudflare Workers AI function calling: https://developers.cloudflare.com/workers-ai/features/function-calling/
- Cloudflare Durable Objects overview: https://developers.cloudflare.com/durable-objects/
- Cloudflare Agents API: https://developers.cloudflare.com/agents/runtime/agents-api/