
You haven’t opened the file that holds half your app in maybe two months. It compiled. The tests passed. You’ve been adding from one end and the AI has been adding from the other, and the last time you looked at the whole thing it was already past a thousand lines.
That file is fine, you tell yourself. Nothing has broken. The features keep landing. Your velocity is on track.
This is the part of AI-assisted coding that does not surface in the demo reels. The features arrive cleanly, the tests turn green. The codebase keeps growing in two directions while no one is reading the middle.
The Archive Tag
On May 10, a developer who goes by shvbsle published a dev log titled “Im going back to writing code by hand”. The post climbed HN that week. It hit #1 on daily.dev for the week and #5 for the month. It reads as a culture-war headline and works as a structural report.
shvbsle spent 30 weekends building k10s, a GPU-aware Kubernetes terminal UI for people running NVIDIA clusters. 234 commits, almost all of them vibe-coded with Claude. The basic k9s clone shipped in 3 weekends. Then the fleet view, the live updates, the mouse handling, the contexts, the namespaces. Each feature landed clean. He was building, by his own count, at maybe 10 times his normal speed.
Then he typed a view-switch command and the previous view’s data ghosted across the new one. Tab counts wrong. Live updates stopped. He opened the file that held the model. All 1,690 lines of it. One struct held everything:
type Model struct {
// 3rd party UI components
table table.Model
paginator paginator.Model
commandInput textinput.Model
help help.Model
// cluster info and state
k8sClient *k8s.Client
currentGVR schema.GroupVersionResource
resourceWatcher watch.Interface
resources []k8s.OrderedResourceFields
listOptions metav1.ListOptions
clusterInfo *k8s.ClusterInfo
logLines []k8s.LogLine
describeContent string
currentNamespace string
navigationHistory *NavigationHistory
logView *LogViewState
describeView *DescribeViewState
viewMode ViewMode
viewWidth int
viewHeight int
err error
pluginRegistry *plugins.Registry
helpModal *HelpModal
describeViewport *DescribeViewport
logViewport *LogViewport
logStreamCancel func()
logLinesChan <-chan k8s.LogLine
horizontalOffset int
mouse *MouseHandler
fleetView *FleetView
creationTimes []time.Time
allResources []k8s.OrderedResourceFields // fleet's unfiltered set
allCreationTimes []time.Time // fleet's timestamps
rawObjects []unstructured.Unstructured
ageColumnIndex int
// ...
}
The Update method below it was a 500-line function dispatching on msg.(type) with 110 branches.
He archived the repository. He started a Rust rewrite. This time he wrote the architecture by hand, before any prompt.
The Discipline Argument Stops Here
Three weeks ago I argued that vibe coding had not died, it had been disciplined. The mega-prompt was over. What replaced it was tighter loops, smaller decompositions, single-session scope, review-the-diff cadence. The discipline argument is still right. It is also incomplete.
shvbsle did the prompt-level work the April piece would call discipline. Each prompt was tightly scoped to a single feature. The diffs compiled. He shipped in single sessions and moved on. By his own account he never sat down to actually read the code Claude wrote. He checked the diff, tested the happy path, and moved to the next feature. The codebase still produced an unsalvageable god-object he could not refactor in place.
The discipline argument addresses authorship inside a known architecture. It does not address authorship that has no architecture at all. The April piece named discipline as the practice that replaced mega-prompt. The k10s archive shows discipline working at the prompt level while a different variable, never named, drove the codebase to collapse.
That variable is the architecture itself. The constraints that hold across views, across time, across not-yet-written features. The work that asks:
Where does state live?
Which views can read which fields?
How do background tasks return data to the render loop?
What may a new feature touch and what must it leave alone?
None of these are prompt-level questions. None of them are answerable inside a single Claude session. All of them are the work AI does not do.
What AI Generates by Default
shvbsle’s writeup names three defaults the AI fell into when no architecture told it not to. Each is a language-agnostic pattern; the Go code is the evidence, not the point.
The god-object. One struct holds everything because that is the shortest distance from “add a feature” to “feature works.” New features add fields to it. The struct passes 30 fields. The dispatch function passes 500 lines. The compiler stays green because the code is technically correct. Architecturally, it is unsalvageable.
Positional data. Rows arrive as flat strings. Column identity lives in array indices: the third column is the GPU allocation, the second is the compute class, the first is the name. Adding a column between two existing ones silently breaks every place that hardcoded the index. The compiler cannot help. The JSON config cannot help. The AI picks the shortest path to satisfy the prompt now, not the path that catches what a column insert will do six months later.
Shared mutable state. Background tasks mutate the same fields the render loop reads. The race works 99% of the time and corrupts the display 1%. The fix is message passing; message passing requires more types and more plumbing, so the AI takes the shorter path.
Three patterns, same shape: the model honestly responding to a prompt that did not name an architecture. The shortest path satisfies the prompt. It does not produce a system.
The Verification Tax, Upstream
Three months ago I argued that AI moved the bottleneck from writing code to verifying it. Generation got cheap, verification stayed expensive, and the time saved typing got consumed reviewing code nobody wrote. Sonar’s 2026 survey of more than 1,100 developers found that 96% do not fully trust AI-generated code while only 48% always check it before committing. The 48-point gap is the verification tax accruing.
The k10s archive is the same tax, paid at a different point in the loop. The verification tax accumulates at review time. The architectural tax accumulates at authorship time, while no one is looking. By the time it surfaces as a bug, the cost is “rewrite this.”
Review-time tax is the bill arriving monthly. Architecture-time tax is the bill arriving all at once, when the codebase must be archived. The first is expensive. The second is not negotiable.
Review-time comprehension catches mistakes you can read on the page. Architecture-time comprehension catches mistakes that were never written on the page.
You can verify every line of shvbsle’s model.go and still not learn why 30-plus fields share one struct. That decision was never made. It accreted.
I Have Done What shvbsle Is Describing
I should say this plainly. I have done what shvbsle is describing. Inside a SaaS I have been building on weekends, I have shipped a dozen features with Claude, reviewing only the surface, only at the critical paths. The diffs compiled. The happy-path tests passed. The shape kept bending the same way shvbsle’s model.go bent: one module holding too many concerns, conditional branches stacking on a shape that should have split features ago. It has surfaced as a bug many times. I patched the bug each time. The structure underneath is still the shape it was.
The discipline at the prompt level was real. The architecture at the codebase level was not.
The Architecture Work Was Always Pre-Architecture
The vocabulary needs to split. There is AI-assisted feature development inside a human-authored architecture, and there is AI-driven authorship from architectural zero. Most of the public discourse conflates them. shvbsle’s k10s was the second case. The architecture nobody wrote is what archived it.
The disciplined-vibe-coding playbook works for the first case. It fails silently for the second, and the failure mode is not visible from the inside of a single prompt. The prompt sees the file it is editing. It does not see the 9 other places the same cleanup pattern repeats, the 20-plus type checks that special-case on view, the column index drift across configs. The AI cannot perceive the codebase shape any human reader would notice within a minute of opening the file.
The author has to. Before any prompt. The concrete invariants that say what the model is allowed to do and what it is not. The CLAUDE.md or AGENTS.md directives shvbsle proposes near the end of his piece are an architecture, written in English, handed to the AI as constraints it must read every time. Each rule names a category of mistake the model will otherwise make.
- Each view declares its own keymap. The app dispatches; views own.
- No view-specific fields on the App struct. New views are new files.
- All data flows as typed structs until the render call. No positional
[]string. - Background workers send typed messages. Only the main loop mutates render-visible state.
These are the work the AI cannot do, written down once so the AI does not have to. The architecture moves out of the session and into the file the session reads first.
The View From Outside the Valley
The discourse on this is going to keep saying that AI is replacing senior engineers, that the model can architect a system if the prompt is good enough, that a sufficiently advanced Claude will solve this category at the next model jump. From more than13,000 kilometers outside the Bay engineering epicenter, where the discourse arrives half a day late through whichever browser tab the timezone happens to favor, the claim looks structurally wrong.
The architecture work is a category of work that requires a continuous view of a codebase the model cannot see in a single prompt. The model can produce excellent local code. It cannot produce a coherent system because it never sees the system at once. That gap closes when context windows stretch to hold an entire codebase and reasoning loops can hold architectural invariants across multiple sessions, neither of which is the work the current generation of agentic frameworks is doing. The benchmark-vs-reality gap on architectural correctness will be invisible until someone like shvbsle archives a project and writes about it.
The story we keep telling is “AI cannot replace you.” That story keeps the conversation on the model. There is a work category that was always yours, that you have been treating as the AI’s weak spot. The model cannot see this category at all. You can keep delegating it implicitly and pay the bill at the archive tag. Or you can write it down once and let the AI do the work it is good at, inside the system you defined.
The File Still Sits There
The file holding half your app still sits there. It compiles, the tests pass, the features keep landing. The architecture you have not written is still not being written. The invariants you have not declared are still being violated, one shortest-path commit at a time. The bill for that is accruing in the background, one commit at a time, until the day the file opens and the shape no longer holds.
The architecture is the document you have not written: the concrete invariants that say where state lives, which views own which fields, what a new feature may touch and what it may not. The model was never going to write that. It was always yours.
—Viz