The effort did not disappear when I stopped writing code by hand. It moved to the front.
“Vibe coding” arrived as a half-joke. The image it conjures is someone describing what they want to a model, accepting whatever comes back, and shipping it on a wing and a prayer — fast, loose, and unaccountable. The opposite of engineering.
I want to argue the reverse. Done with any discipline at all, what gets called vibe coding is not a lesser form of the craft. It is the craft, with the centre of gravity shifted. The keyboard work is delegated, but almost everything that made you good at the job is needed more than before, not less. By the end of this I would like to retire the name. Done properly, it is just coding.
Here is how I actually work.
The job changed
The clearest way to describe the shift is that I stopped being the typist and became the architect.
Three things did not change, and it is worth saying them plainly before anything else. I still design the system — the boundaries, the contracts, where each thing lives, all decided up front and on purpose. I still direct the agents — through dialogue, plans, and review, because delegation is not abdication. And I still own the judgement — I need to understand exactly how the thing works and why, without exception. That last point is non-negotiable, and most of what follows exists to protect it.
What did change is the proportion of my time spent typing versus thinking. Almost all of it is now thinking.
Decompose into loosely coupled systems
The first principle is the oldest one in software, and it matters more in an agentic workflow than it ever did: carve a large project into small, independent components that talk to each other over clean contracts. The canonical example is a frontend and a backend joined by a single API.
There are three reasons this is now load-bearing rather than merely nice.
- It is easier to reason about. Each component fits in one head — and, just as importantly, in one agent’s context window.
- It shrinks the blast radius. A change to a dependency cannot ripple silently across the whole codebase when the codebase is several walled gardens with narrow gates between them.
- It prevents context bloat. An agent working on the frontend loads the frontend, not the entire system. You are not paying — in tokens, in latency, or in confusion — to drag the whole project into every conversation.
The old reasons for modularity were about human comprehension and safe change. Those still hold. The new reason is that your collaborators have a finite attention span measured in tokens, and a tightly scoped component is the difference between an agent that holds the whole picture and one that is guessing.
Rules: global, then local
Agents work to standing instructions, and I keep them in two layers.
Global rules apply everywhere: coding style and conventions, the docstring standard, the list of security concerns to flag before proceeding, the format for logging bugs. Project rules add local context: this service’s architecture, its API contracts, its particular gotchas, its deploy quirks.
The small trick that makes the global layer work is a symlink. There is exactly one global rules file, edited once, linked into every project. No copy-paste, and therefore no quiet divergence between repositories as the standards evolve. One source of truth.
Docstrings that carry pseudocode
One rule earns special mention because it has an outsized effect. Docstrings are mandatory and thorough — and for any non-trivial function, the docstring contains a pseudocode sketch of the logic.
def reconcile(batch: Batch) -> Report:
"""
Info: match payments to invoices.
effects: reads S3, writes DynamoDB.
pseudo code:
for each payment in batch:
find invoice by ref
if amounts agree -> settle
else -> flag for review
"""
...
The pseudocode block is the highest-leverage line in the whole docstring. It lets a reader — human or model — understand the intent of a function before parsing a single line of its implementation. When an agent later edits that function, it edits against the stated intent rather than reverse-engineering it from the code, and the change stays faithful to what the function was meant to do.
Learning from your own mistakes
A good setup does not just produce code. It produces a record of its own failures, and learns from them.
A Cursor rule writes every bug into a progress.md file in one fixed shape: date, symptom, problem, solution.
2026-06-18
symptom: Lambda 500 on cold start. problem: Pydantic unbundled in
src/(SAMCodeUri). solution: Use@dataclass, or ship the dependency in a layer.
On its own, this is a tidy diary. The point is what happens to it. Once a week, agents read every progress.md across every project, surface the patterns, and propose new global rules. A mistake that recurs, or a root cause that shows up in more than one place, gets promoted into the global rule set — at which point the whole fleet stops making it. Yesterday’s bug becomes tomorrow’s standing instruction.
This is the part that compounds. The system is not merely remembering what went wrong; it is generalising from it. Measure twice, cut once — applied to the process itself.
The great inversion: where the effort goes
If you tracked my time on a non-trivial feature a few years ago, it split roughly like this: 10% planning, 85% building, 5% testing. Today the same feature is closer to 90% planning, 5% building, 5% testing.
The work did not shrink. It relocated. The build step has collapsed because, by the time I reach it, the hard thinking is already done. Almost everything now lives in the careful construction of the plan — and that plan is built through dialogue, not in isolation.
A typical complex task runs through five deliberate stages before a line is built:
- Dialogue. Think the problem through with a high-level model — the kind of conversation this article came out of.
- Draft plan. Turn that conversation into a preliminary plan.
- Ground it. Take the plan to the coding agents on each affected project and discuss it against the reality of their codebases.
- Final plan. Fold everything into one fully-formed, agreed plan.
- Sign-off. Have a high-level model review the finished plan — and only then build.
Two high-level reviews bookend the plan: one at the start to think, one at the end to sanity-check. The coding agents ground it in the middle. By the time you start building, building is the easy part.
Giving agents the whole map
Two kinds of tooling make the difference between an agent that edits in a tunnel and one that edits with the whole system in view. Both are built on MCP — the Model Context Protocol — which lets external tools feed live context to an agent.
The first is a code knowledge graph. Tools such as Git Nexus build a graph of how the codebase actually connects — callers, imports, shared types, dependencies — so that an agent editing one file is aware of everything downstream of it. The change is made with the big picture in view rather than from the narrow vantage of a single open file. Seven loose files become one connected graph.
The second is agent-to-agent communication. I run a small MCP chat server that connects the agents working on different components. When the backend changes an API contract, the frontend’s agent hears about it directly, through the channel, instead of waiting for me to carry the message between two Cursor windows. This is the natural counterpart to decomposition: once you have split the system into independent components, their agents still need a way to coordinate, and a message bus is cleaner than a human relay.
Accountability: the buck stops with you
Here is the part that rarely gets mentioned, and it is the most important.
You cannot fire a model.
When a developer on your team shipped a security flaw, there was — at least in principle — somewhere for the responsibility to go. You could let them go, learn the lesson, and move on. The accountability had an address other than your own.
That address is gone. You are still the coder: responsible and accountable for every line your agents write, with no exceptions. None of that responsibility transfers to the model. It converges, entirely, on you. There is no one downstream to absorb the blame.
The instinctive read on AI-assisted development is that it lowers the bar — that it makes engineering casual. The truth is the opposite. By removing the person you could once hold responsible, it raises everyone’s responsibility. You inherit all the accountability your agents generate, and you inherit it personally. That is not a reason to avoid the workflow. It is a reason to take it more seriously than the one it replaces.
The second inversion: security over features
Accountability changes what you optimise for, and it produces a second inversion to sit alongside the first.
A disciplined setup — good architecture, strong rules, the weekly learning loop — makes functionality close to a given. The features arrive; that part is largely solved. So the scrutiny moves to the thing you cannot delegate and now solely own: security.
Where I once split my attention something like 50:50 between functionality and security, I now sit closer to 5:95. The ratio is deliberately provocative, and the honest version of the claim is about marginal attention rather than total effort — features still matter, they simply are no longer where the risk lives. The risk lives in the security flaw that is now yours, and only yours, to own. So that is where the judgement goes. Guard what is yours.
So let’s just call it coding
There is an analogy I keep coming back to, and it is the whole argument in miniature.
Nobody should be writing code by hand any more. It is like doing complex arithmetic by hand. You should understand how it works, and you should be able to do it yourself if you had to — that competence is the price of admission, not optional. But in practice you would reach for a calculator. A firm that insisted on doing every calculation by hand would not be more rigorous for it. It would simply be slower, more error-prone, and quietly absurd.
The skill was never the keystrokes. It was the understanding, the judgement, the design, and the willingness to stand behind the result. All of that is still required. More of it is required than before, because the accountability no longer has anywhere else to go.
Which is why I would retire the name. What we are calling vibe coding, done with this much structure — decomposition, rules, a learning loop, the right tooling, and someone genuinely accountable at the centre of it — is not a vibe. It is the discipline.
It is just coding.