One Sentence to Production
This is the entire feature request, word for word:
I want a total views counter that sums all the individual blog views into a total view counter put in the top bar of the website.
That's it. No spec, no acceptance criteria, no punctuation to speak of. It reads like a note you'd text yourself at 2am.
Four minutes and twenty-six seconds later it was live.
Not a prototype. Not a staging environment. The actual blog, with an actual counter in the actual header, adding up every post's views into one number — north of 37,000 of them at the time of writing.
We didn't type a line of that code. We wrote a sentence and clicked merge.
What Actually Happened
We keep the timeline because it still doesn't feel real:
| Time | What happened |
|---|---|
| 00:00:40 | The issue is opened. One sentence. |
| 00:00:43 | We comment /agent. |
| 00:00:44 | The agent acknowledges, and starts. |
| 00:03:25 | A pull request appears. 18 iterations, 157 seconds, 528,330 tokens in, 4,359 out. |
| 00:04:16 | We read the diff and merge it. |
| 00:05:06 | Production is running the new code. |
Four minutes, twenty-six seconds from sentence to production. The only human steps were the sentence and the merge.
The Part That Surprised Us
The diff was six files, +142/−21. But the interesting thing isn't that it worked. It's how it worked.
- It noticed the main stylesheet was at 486 lines and put the new CSS in its own file — because the repo's contributing guide says there's a 500-line ceiling and the next real CSS change should start a new stylesheet.
- It added a nil-database guard, because the offline test suite renders the about page without a database and it didn't want to panic there.
- It wrote table-driven tests for 0 views, 1 view, and 1,234 views, matching the pluralization the post cards already used.
- It put its one real assumption in the pull request body for the reviewer, instead of quietly picking a side.
None of that was in the sentence. All of it was in the repository.
That's the actual trick. The agent doesn't just have tools — it has conventions. Point it at a repo with a contributing guide, a test suite, and a build command, and it behaves like someone who read all three before starting.
Why This Works Now
Two things had to be true.
The models got good enough to hold a repository's conventions for the length of a real task. Not autocomplete — "this file is at 486 lines, so the CSS goes somewhere else."
And the tooling around them got boring. Containers, webhooks, signed payloads, CI runners. Nothing exotic. The hard part was never the intelligence; it was the plumbing that turns a paragraph into a reviewed, tested, deployed commit. That's the part we built.
The run itself cost a few hundred thousand tokens on a model we already host. Call it free.
The Plumbing
one sentence in an issue
│
│ /agent
▼
┌────────────────────┐
│ pr-bot-receiver │ verifies the webhook signature,
│ (on k3s) │ checks write access, creates a Job
└──────────┬─────────┘
│
▼
┌────────────────────┐
│ ephemeral Job │ clones the repo, reads the issue
│ (pr-bot image) │ and every comment, edits, tests
└──────────┬─────────┘
│
▼
┌────────────────────┐
│ pull request │ CI runs the tests again, on the PR
└──────────┬─────────┘
│
│ a human clicks merge
▼
┌────────────────────┐
│ deploy workflow │ builds, ships, waits for healthy,
│ (on push to main) │ smoke-tests, invalidates the cache
└────────────────────┘
Five moving parts, all on one machine:
toaster — the GPU box. Four Blackwell cards, 384GB of VRAM, and the model the agent thinks with runs on the same hardware hosting everything else.
k3s — a single-node Kubernetes cluster. The inference stack stays on plain Docker and systemd; the cluster exists for the things that want to be scheduled and thrown away.
Gitea — git, issues, pull requests and CI, self-hosted. Private repos, which matters in a minute.
act_runner — the CI runner, inside the cluster. Jobs get a container image with a real toolchain: the model client, git, Go, Python, ripgrep, jq, make.
pr-bot and pr-bot-receiver — the agent and its front door. The receiver is a small webhook service: it verifies the signature, checks that whoever commented actually has write access, and then creates a Kubernetes Job.
That Job is the whole trick. It clones the repo, reads the issue and every comment, does the work, pushes a branch, opens the pull request, comments the link, moves a label from "working" to "review" — and then the container disappears. Nothing to clean up, nothing to keep patched.
The Two Workflows
There are two, and the reason is not cosmetic.
One runs on pull requests. It holds no secrets. It checks formatting, vets, tests, and packages.
The other runs on a push to main. It holds credentials. It builds, ships, waits for the deployment to report healthy, smoke-tests the live site, and invalidates the cache.
Why split them? Because the CI system runs the pull request branch's copy of a workflow. If the workflow holding credentials also listened to pull requests, then anyone who could open one could reach those credentials — including the agent, and including anything that managed to talk the agent into something.
So the rule is one line: the workflow with credentials only ever listens to a merge.
The Security Story
The agent runs with no cluster credentials, no docker socket, as a non-root user, with a CPU and memory cap and a hard deadline.
The deploy credential can do exactly two things: replace the code of one function, and invalidate one cache path. It cannot read the bucket. It cannot touch the database. It cannot see the infrastructure state.
And the merge is always a human click. The agent's final line, in its own pull request, is "review before merging — the agent does not merge."
We didn't build it this way because we don't trust it. We built it this way because trust that isn't enforced is just optimism.
What This Actually Changes
The bottleneck was never typing code. It was everything around it: context switching, cutting a branch, remembering the test command, writing the PR body, deploying, invalidating the cache, checking the site. Individually trivial. Together, an afternoon.
Now the loop is: describe the thing, read a diff, click merge.
That isn't a 10x on coding. It's the removal of a dozen small frictions that were the real reason a one-line idea could sit in a notes file for three weeks.
We've been building toward this for a while — not the pipeline specifically, but the idea that we could hand each other work and trust the process around it. One of us describes the change. The other writes it. A human reads every diff before it ships. The machine in the closet does the rest.
The agent that opened that pull request is, more or less, the one writing this post. Same model, same tools, different harness.
The Honest Part
Code ships prompt → merge → production now. Content doesn't.
This post still goes out the old way: drop a markdown file in a bucket, an S3 event fires a Lambda, a row lands in the database, and the page renders. Which is fine. For now.
One sentence in. One click out. See you in production.
This blog post was written with the help of DeepSeek V4.1 Flash.