Agent-Native Software Engineering
The usual way to judge a coding agent is to ask how hard a bug it can fix, how large a repository it can hold, and how long it can run unattended. Those numbers are improving fast. But most failures I hit in daily use have little to do with code generation. The agent understands a function correctly and misreads the requirement. It passes every existing test and breaks a business rule that no test encodes. It executes a badly formed goal with great care.
The worst failures are not entirely on the agent’s side. I maintain several projects above 100K lines. Early on, coding agents made me much faster. I knew those systems well, I could state the requirement and the constraints, and the agent did the rest. As the codebase grew, my grip on it visibly weakened. There are modules whose internals I can no longer explain. I have to search the repo to find out whether a feature already exists. The architecture in my head got blurry. So when I describe a task to an agent, I now leave out considerations I should have stated. The agent implements what I said. Sometimes it rebuilds a capability that already exists somewhere else. The architecture decays and the rework piles up.
My most productive moment was not the moment the agent got strongest. It was the moment I still held the whole system in my head. What I lost is a model that lived only in my head and was never written down: which modules exist, why they look the way they do, what must not be touched. In conventional development, that model, plus team memory and repeated review, keeps custody of everything that never made it into a document. It is a safety net you only notice when it is gone.
Agents weaken both sides of this at once. They do not carry the model. Context is temporary, and when a session ends, the reason behind a change made hours ago goes with it. A constraint agreed verbally in a meeting is invisible to them. Agents also raise throughput, which pushes the codebase past the size any single person can hold, so the humans who did carry the model start to let go. Gaps that someone used to close now stay open on both sides, and they reach the architecture as decay and rework.
Here is the underlying problem. Our entire software engineering stack was built for humans, and agents lack the properties that stack assumes. Git, issues, pull requests, code review, and CI all assume a developer with long-term memory, an understanding of undocumented background, the instinct to stop and ask when something looks wrong, and accountability for the result. An agent copies instantly but loses its context at the end of a session. It works for hours but pursues a wrong goal consistently. It produces a lot of code and answers for none of it.
Classical software engineering optimizes collaboration among scarce humans who remember things and carry responsibility. Agent-native software engineering optimizes something else: reliable delegation to an executor that is cheap to copy, limited in context, probabilistic in behavior, and accountable for nothing. This post is about that delegation machinery. When agents become the actual implementers, tasks, context, verification, permissions, and responsibility all need to be reorganized.
This is not only my impression from daily use. Researchers have started to treat it as a distinct topic and to separate software engineering for humans from software engineering for agents [1][2], which reopens questions about actors, processes, tools, and artifacts. One line of work proposes redefining the basic unit of work from a code change to a supervised delegation [3]. Industry is filling in pieces from different angles: spec-driven development addresses how a task gets expressed, and AgentOps addresses what happens after deployment. This post puts those threads into one frame and adds what I have observed while using these tools.
Spec-driven development solves the first step
The early pattern with coding agents was to jump straight from prompt to code. You describe what you want. The agent interprets the requirement, decides the design, and edits files, all inside one conversation. For a small change this is fine. Fix a function, add a test, done.
The pattern breaks on larger tasks. Which judgment calls did the agent make? Why this design? What was explicitly out of bounds? Halfway through, the requirement turns out to be wrong — continue, or go back and revise the goal? All of that lives in a temporary conversation context. A human cannot inspect it before implementation, and a second agent cannot pick it up afterward.
Spec-driven development inserts steps between the prompt and the code: intent → spec → plan → tasks → code. On the surface it is more documents. In practice it changes how humans and agents divide the work. A human reviews whether the requirement is clear, whether the design holds, and whether the acceptance criteria are concrete — before any code exists. The agent gets a stable basis to work from instead of one ambiguous sentence. Over the past year, tools like Kiro [4] and Spec Kit [5] have productized this flow, which shows there is now a clear product direction beyond prompt-to-code.
A spec answers only one question: what to build. It does not determine what the agent sees, what it may modify, or which environment it runs in, and it does not establish that the work is actually done. A spec.md does not solve permissions, sandboxing, stale context, multi-agent conflicts, result verification, or accountability. The spec is the API of this delegation machinery, and an API is not the system.
A spec should not live long
The most common attack on spec-driven development lands here. As development proceeds, spec and code drift apart. Maintaining two sources of truth is expensive. The spec ends up as a document nobody trusts. This is the same failure mode as rotting design documents, and the criticism is fair.
I would like to point out that the criticism targets one specific misuse: treating the spec as a system-level truth that is written once up front and then synchronized with the code forever.
A spec is never perfect truth. Requirements clarify during implementation. Design constraints surface only once you read the existing code. Business rules appear only when you test against real data. There is a subtler risk too. When the spec, the design, the code, and the tests all come from the same agent, they may share one misunderstanding. Documents that agree with each other do not necessarily match the real intent. A green test suite may only confirm an assumption the agent invented.
A better shape is a three-way loop: intent ↔ implementation ↔ evidence. Intent states the problem worth solving. Implementation puts that goal into a real system. Evidence tells you whether the system actually changed the way you expected. Findings during implementation should be allowed to revise the spec, and runtime results often expose what the original requirement failed to state.
The cost problem has a straightforward fix: shorten the lifetime of a spec so it never needs long-term synchronization. A change-level spec states the intent, the boundaries, and the acceptance criteria for one change. Once the code merges and the acceptance passes, its job is finished. Archive it. Among constraints that must hold long-term, the mechanizable ones — idempotency rules, type contracts, module boundaries — belong in tests, types, and CI checks, where a machine verifies them continuously, rather than in a document a human keeps in sync by hand. Some constraints resist mechanization: why an architecture looks this way, why a field must stay, which external system a compatibility branch exists for. Those still need a maintained decision record. Otherwise you return to the state I described at the start, where only one engineer knows why.
Most drift cost comes from maintaining a change-level document as if it were system-level truth. Seen this way, spec-driven development does not remove software engineering. It moves part of it earlier, from the coding stage to the intent and design stage.
The delegation chain
If the spec is the entry point, the full chain covers at least these stages:
Solid arrows are the delegation direction. Dashed arrows are the feedback loops from the previous section: evidence revises the spec, and review results return to intent. The point of the chain is to take what used to rest on an individual engineer’s judgment and turn it into objects a system can store and check.
A task cannot be one line like “fix the double charge on payment retry.” It also needs to state what counts as fixed, which behaviors must not change, whether schema changes are allowed, whether historical orders must stay compatible, and under what conditions the agent should stop and ask a human. When one agent fails midway, the next one should resume from task state, recorded design decisions, and existing results — not by rereading a chat log and guessing. Sessions are temporary; tasks should be durable. That distinction is what separates agent-native software engineering from simply having a stronger agent session.
Context should be assembled per task
Once a task is expressed well, the next practical question is what the agent needs to know to finish it. The common approach is to keep growing AGENTS.md, or to push more code and documents into a longer context window. In real projects the hard part is different: deciding which information is relevant to this task, which has expired, and which holds only inside one module. An agent changing payment retry logic needs the boundaries of the payment module, the idempotency rules, the relevant schema, recent incident reports, and the acceptance criteria for this change. It does not need the company’s entire technical history.
Context works better when it is assembled per task, like a work packet. Each significant piece should answer a few questions: where it came from, where it applies, when it was last updated, and whether it still holds. This matters most in old systems. In a codebase that has been running for ten years, a strange-looking branch may exist for a customer behavior nobody remembers, and the documentation may still describe a rule that stopped being true two years ago. My read is that a wrong but confident context is worse than no context, because the agent will faithfully follow an expired rule. Part of the grip loss I described earlier works this way. The problem was never a shortage of information. The problem is that nobody can still tell which piece holds and which one expired. Context that is organized per task and labeled with source and freshness is how you move that in-the-head model back into the system.
The industry is moving in this direction. The practice with the most agreement is progressive loading: global instructions carry only invariants, and local knowledge loads on demand per file, per task, and per tool [6]. Detecting that a piece of context has gone stale remains an open problem, and I have not seen a good answer to it.
After the agent says “done”
When a coding agent finishes, you usually get a diff and a summary of which files changed and which tests ran. That summary is still model-generated text. The agent reports passing tests, but it may have run a subset, misread command output, or missed the risky path entirely. Empirical studies of agent-authored pull requests in public repositories point the same way: errors, conflicts, and unnecessary changes remain common [7][8].
Tests are the most important class of evidence, but whether they suffice depends on whether they actually cover the requirement. OpenAI’s audit of SWE-bench Pro is an extreme illustration: roughly 30% of the tasks had problems of their own, including tests that enforce implementation details the requirement never specified and tests that miss part of the functionality [9]. The point is not that tests are untrustworthy. The point is that as acceptance leans harder on automated referees, the referee itself enters the scope of what needs review.
In an agent-native workflow, the deliverable should grow from a diff into an evidence bundle. At minimum it holds the implementation; the verification behind it — how the old failure reproduces reliably, why the new test covers it, what changed in behavior before and after; the assumptions made during implementation; known risks and paths left unverified; and the rollback procedure. Concretely: a frontend change needs screenshots and interaction results, a schema migration needs data validation on both sides plus a rollback test, and a performance fix needs a benchmark rather than the sentence “removed one query.”
A diff tells you what the agent changed. An evidence bundle tells you why you should believe the change. That difference stayed in the background while humans wrote most of the code, because a reviewer could lean on knowing the author’s judgment and track record. Once agents produce a large share of the code, that interpersonal trust no longer transfers, and “why I believe this change” has to become an explicit engineering artifact.
Does running more agents make it faster?
Agents are cheap to copy, so the natural move is to start ten of them. This is one of the sharpest disagreements in the field right now. Cursor has shown dozens of agents reworking a large codebase in parallel [10]. Cognition argues against parallel writers: most coding tasks share too much state, parallel writers make locally reasonable decisions that contradict each other, and no participant ends up holding the full picture. They call it split-brain [11].
The two positions describe the same thing. Note where the engineering effort actually goes in the Cursor case: a task tree that manages dependencies, isolated workspaces for each writing agent, dedicated merge and review flows, and a maintained field guide recording what works. The coordination machinery is the investment; model calls are the cheap part. What Cognition rejects is parallel writing without that machinery.
The difficulty of parallel writing is underestimated because the dominant conflicts are not textual. Git resolves two diffs touching the same line. Git cannot resolve two diffs that merge cleanly, pass their tests individually, and jointly change the system’s boundaries. One agent adds rate limiting in the service layer while another implements quota control in the database layer. Each is defensible alone. Together they are duplicated logic under two inconsistent sets of semantics. These semantic conflicts surface at review time or later, and review is exactly where human capacity is scarcest. Double the agents, double the write throughput, and the combinations that can conflict grow faster than linearly — all landing on human reviewers. That is the concrete mechanism by which a swarm manufactures coordination cost.
Durable parallel gains come from read-write asymmetry. Searching code, diagnosing causes, designing tests, and reviewing are read operations. They parallelize naturally, and several agents can explore competing hypotheses at almost no coordination cost. Writes, and any operation with global side effects, need serialization. This is also where Cognition’s updated position landed: still opposed to multiple writers mutating shared state, but comfortable with many agents supplying intelligence while writing stays single-threaded [12]. Anthropic’s recent migration of Bun from Zig to Rust with Claude Code shows the shape of it [13]. Fixer agents patch in parallel, but only one background daemon rebuilds the binary. It batches patches, rebuilds once, and feeds results back, isolating the most expensive and consistency-sensitive step instead of letting every agent trigger it.
Parallel writing pays off only when several demanding preconditions hold at once, and large-scale migration is close to the only workload that satisfies all of them for free. That Bun migration produced about a million lines in under two weeks, with the existing test suite green in CI before merge. Migration hands you every precondition: the old code is a nearly complete, unambiguous spec; the existing test suite is a broad ready-made referee; files and crates are naturally isolated write units; and each compile or test failure enqueues the next work item automatically. Ordinary feature work satisfies none of these. There is no spec waiting, no referee with real coverage, and changes share a lot of state. I would suggest being cautious about reading the migration result as general evidence that swarms work, since that reading drops exactly the conditions that made it work.
This is why a swarm is a conditional optimization. The things worth designing are how tasks decompose, how write authority is allocated, how design decisions get shared, and how results are combined and verified. Agent count should be an output of those decisions, not an input.
Where engineering effort moves
The real question is where the bottleneck goes once writing code stops being one. Spotify reported a direct observation: coding is no longer the constraint, and roughly 76% more pull requests now need review, so the pressure moves to human judgment [14]. Whether a large volume of locally correct changes erodes long-term consistency is, in my view, the more interesting question ahead. Engineering effort moves to roughly three places.
The first is designing acceptance. Evidence bundles do not appear by themselves. What counts as done, which criteria a machine can check, which ones require human judgment, and how much evidence a given risk level demands — a person defines all of that. Writing a good acceptance contract is no easier than writing the implementation, because it forces the engineer to make explicit the “you can’t change that” instinct that used to stay implicit. Judging productivity also needs evidence. METR ran a randomized controlled trial in 2025 with experienced open-source developers working in codebases they knew well. They believed AI tools made them faster; measured task time was 19% slower [15]. That is a snapshot of early-2025 tooling in a specific high-context setting, and METR itself notes current tools may differ [16]. It still shows that an engineer’s sense of their own speedup is unreliable, which turns acceptance and measurement into real engineering work.
The second is infrastructure that makes a codebase legible to agents: short navigable documents, executable commands, deterministic environments, clear module boundaries, automated checks. Agreement formed fastest here, because the same investments help humans and agents alike. This work used to count as engineering hygiene — nice to have, survivable without, because people patched the gaps through conversation and experience. Agents cannot patch gaps. They only work from what exists explicitly. Hygiene has become a direct input to agent productivity.
The third is guarding long-term consistency. Each individual agent change can be locally correct while the accumulation produces duplicated abstractions, architectural drift, and temporary compatibility branches that exist only to satisfy acceptance. This decay shows up in no single review. Only someone tracking the system over time notices it. That in turn requires engineers who still read code deeply, because judging whether an agent copied an inappropriate pattern or quietly eroded a boundary depends on understanding the system yourself.
All three share a property: they design and maintain the process that produces code, rather than producing code directly. Execution is genuinely being reallocated. My read is that the evidence supports a shift in where engineers spend their effort, and does not support their disappearance.
Closing
The compressed version: human engineers work inside a safety net woven from conversation, memory, experience, and accountability, and agents are outside it. Agent-native software engineering is the work of turning the load-bearing parts of that net into infrastructure an agent can use. A spec writes down task boundaries. Context hands over the organizational knowledge that matters. Evidence makes completion independently verifiable. Coordination rules decide when parallelism is safe and when writing must stay single-threaded. Each rebuilds one strand. Spec-driven development is the strand that got productized first — an entry point, not the whole thing.
To see how far your team is from this, take the last task you handed to an agent and ask three questions. First, if a different agent picked it up, where would it learn the task boundaries and acceptance criteria — from a durable task definition, or from a chat log? Second, at acceptance time, did you rely on the agent’s own summary, or on evidence you could check independently? Third, how many constraints in that task live only in one engineer’s head, covered by neither tests nor docs? The three map to durable tasks, evidence-based acceptance, and explicit context — the three things the safety net loses first. Wherever you cannot answer, that is where the next engineering investment belongs.
Two open problems stand out to me. Staleness detection is the first: nobody has a good mechanism for noticing that a piece of context stopped being true, and progressive loading does not address it. The second is semantic conflict detection between concurrent changes. Merge tools work at the text level, and the conflicts that matter for parallel agents are at the level of system boundaries. Both look like infrastructure problems rather than model problems, which is a reason to expect progress from tooling rather than from the next checkpoint.
References
[1] https://doi.org/10.1145/3807901
[2] https://arxiv.org/abs/2509.06216
[3] https://arxiv.org/abs/2606.28791
[5] https://github.github.com/spec-kit/
[6] https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents
[7] https://arxiv.org/abs/2606.13468
[8] https://arxiv.org/abs/2607.04697
[9] https://openai.com/index/separating-signal-from-noise-coding-evaluations/
[10] https://cursor.com/blog/agent-swarm-model-economics
[11] https://cognition.ai/blog/dont-build-multi-agents
[12] https://cognition.ai/blog/multi-agents-working
[13] https://claude.com/blog/ai-code-migration
[14] https://engineering.atspotify.com/2026/6/code-with-claude-coding-is-no-longer-the-constraint
[15] https://metr.org/blog/2025-07-10-early-2025-ai-experienced-os-dev-study/

