Open your backlog. Pick a ticket that’s marked ready for development. Read it as if you knew nothing about the company.
“Fix the retry behavior on webhook delivery.”
A human on your team reads that and knows six things the ticket doesn’t say. They know which service owns webhook delivery. They know retries were already changed once last year and why it got reverted. They know the customer who complained. They know that “fix” means make it idempotent, not make it faster. They know there’s an unwritten rule about not touching the backoff constants because a downstream partner rate-limits aggressively. They know that if this breaks, finance notices before engineering does.
None of that is in the ticket. All of it is required to do the work correctly.
That was fine for forty years, because the ticket was never the specification. The ticket was a pointer to a specification that lived distributed across people’s heads, Slack history, tribal memory, and the code itself. A human decompressed it on the fly using context nobody ever wrote down.
Then we handed the same ticket to something that has no head to keep context in.
A ticket is a lossy compression of intent. Humans have the decompression key. Agents don’t, and they never say so — they just produce something confident and wrong.
This is the second piece in Rethinking the SDLC. The first argued that execution stopped being the constraint and intent quality became one. This one is about what actually replaces the ticket.
The frustration everyone reports is an intent-fidelity problem wearing a model costume#
Stack Overflow’s survey data has the top developer frustration with AI tools, cited by 66% of developers, as output that is “almost right but not quite.” That number gets read as a model-capability complaint. It isn’t.
“Almost right but not quite” is precisely what you get when the instruction was underspecified and the executor filled the gaps with plausible defaults. The agent didn’t misunderstand the words. It understood the words perfectly and then guessed at everything the words left out. It guessed about idempotency. It guessed about the backoff constants. It guessed that “fix” meant “improve,” and improved three files you didn’t ask about.
Watch what happens next in most organizations. Someone says the model isn’t good enough, and waits for the next release. The next release arrives, better at everything, and produces a more elegant version of the same wrong system faster.
You cannot buy your way out of ambiguity. Ambiguity is not a model problem. It’s a specification problem that used to be invisible because a human silently absorbed it.
And here’s what makes this the most important unfixed thing in most engineering organizations: unlike verification or observability, nobody has even named it as a workstream. There’s a team that owns CI. There’s a team that owns observability. There is nobody who owns whether the unit of work is executable.
Requirements engineering never got its DevOps moment#
Think about how much rigor we applied everywhere else.
Code got version control, review, static analysis, and type systems. Infrastructure got declarative definitions and drift detection. Deployment got pipelines and gates. Tests got frameworks, fixtures, and CI. Observability got structured events and SLOs.
Requirements got… a text box. With a rich-text editor, if you’re lucky. No schema, no validation, no tests, no drift detection, no ownership contract, no versioning against the code it describes. The most upstream artifact in the entire lifecycle — the one every downstream cost derives from — is the only one we never engineered.
We got away with it for one reason: a human stood at the boundary and did the engineering informally. They asked a clarifying question in standup. They noticed the ticket contradicted the architecture. They remembered the partner’s rate limit. That human was the requirements compiler, and their error-correction was so reliable that we mistook the source language for being adequate.
Remove that compiler from the loop — or, worse, keep them in the loop but give them forty times the volume to compile — and the source language’s inadequacy becomes the dominant cost in your system.
What agents actually need, and it isn’t a longer description#
The instinct is to write more prose. Longer tickets, richer descriptions, acceptance criteria paragraphs. That helps a little and scales terribly, because prose has the same failure mode at any length: it’s unverifiable. Nobody can tell whether a paragraph is complete.
Serious agent systems don’t run on prose. Look at how the people operating at scale actually structure it. Stripe’s one-shot coding agents don’t scavenge context from a wiki — they pull from a central Toolshed MCP server exposing 400+ internal tools. Anthropic’s engineering team, writing about pointing 16 parallel agents at building a C compiler, landed on a sentence that should be on a poster in every engineering org: “the task verifier must be perfect.” Not the model. The verifier.
Both of those are the same lesson from different angles. Reliable autonomous execution needs its inputs and its success criteria built as infrastructure, not written as narrative.
So here’s the unit of work I’ve settled on.
The intent package replaces the ticket#
Four sections. Every one of them mandatory. Together they’re the smallest artifact that an agent can execute and a human can be accountable for.
1. Intent — what should be true when this is done.
Written as an outcome, not a task. Not “add retry logic to the webhook handler.” Instead: “a webhook delivery that fails transiently is retried until it succeeds or exhausts a bounded budget, and a receiver that gets the same delivery twice sees one effect.”
The test for good intent: could a competent engineer who’s never seen your codebase tell whether you achieved it? If achieving it is only checkable by the person who wrote the ticket, you wrote a task, not an intent.
2. Context — what the executor needs to know, with pointers, not prose.
The service that owns this. The specific files and modules in scope. The prior attempt and why it was reverted. The architectural decision record that governs this boundary. The tool or MCP server that exposes the relevant internal capability. The dashboard that shows current behavior.
Context is the section that exposes your organization’s real maturity, because it can only be assembled cheaply if the underlying knowledge is owned, current, and machine-reachable. If assembling context for one piece of work takes an hour of archaeology, you don’t have a ticket problem — you have a knowledge infrastructure problem, and it’s about to be your throughput ceiling.
3. Constraints — what must not happen, in machine-checkable form wherever possible.
This is the section nobody writes and everybody needs. Constraints are the negative space of the specification: the invariants, the boundaries, the refusals.
- Do not change the backoff constants; partner X rate-limits at 10 req/s.
- No new outbound dependencies from this service.
- No schema change in this package.
- Latency budget: p99 under 200ms for the handler path.
- Nothing in this diff touches the auth module.
- No new secrets, no new IAM grants.
Notice how many of those can be enforced rather than merely stated. A dependency rule is a lint rule. A latency budget is a performance test. “Nothing touches the auth module” is a scope check in CI. A constraint that exists only as a sentence is a hope. A constraint expressed as a gate is a constraint.
This is also where architectural judgment enters the lifecycle at the only point where it’s cheap: before the work, as a boundary, instead of after the work, as a rejected PR.
4. Verification — how we will know, before a human opinion is involved.
The acceptance criteria, but executable. A failing test that demonstrates the bug now and passes after. A property that must hold across generated inputs. A load profile that must be sustained. A specific log or metric that must appear. An adversarial check written by something other than the implementer.
The verification section is the contract’s teeth. It converts “done” from a judgment call into a machine-decidable fact for everything a machine can decide, which is the only way you free human attention for the things it can’t. I’ll spend two whole articles on what belongs in here — one on review, one on testing — because this is where most organizations are weakest and most exposed.
The intent package is also a management artifact#
Four practical properties fall out of this structure, and they’re the reason I care about it beyond agent execution.
It makes readiness testable. “Ready for development” is currently a vibe. With an intent package it’s a checklist: intent stated as an outcome, context resolvable, constraints enumerated, verification defined. A work item that fails any of those isn’t ready — for a human or an agent. Which means the same discipline that unblocks your agents also fixes your sprint planning, and you get to stop arguing about whether refinement is worth the time.
It makes judgment legible. Everything senior engineers know that never makes it into an artifact — the partner rate limit, the reverted attempt, the module you don’t touch — has a home now. It becomes a constraint, then a gate. That’s how a senior engineer’s judgment stops being a bottleneck and starts being infrastructure. It’s also how they stay valuable when nobody’s paying for typing.
It routes work by risk. Once constraints and verification are explicit, you can see immediately which items are safe to run at high autonomy and which need a human between the work and its effect. Autonomy stops being a global setting and becomes a per-item decision with evidence behind it.
It makes the specification a versioned artifact. Intent packages live next to the code, in the repo, moving with the system they describe — not in a ticket tracker that drifts out of sync the moment work starts. When the constraint changes, the change is reviewed like a code change, because it is one.
Where this breaks, honestly#
Three real objections, and I’d rather raise them than have them raised at me.
“This is just waterfall with extra steps.” No, and the difference matters. Waterfall specified solutions up front and forbade change. An intent package specifies outcomes, boundaries, and proofs and is deliberately silent on implementation. It’s closer to a property-based test than a design document. It also gets written per work item, in minutes, not per project, in weeks. If your intent packages are taking a week to write, you’re specifying the how. Stop.
“Writing all this is more work than the ticket.” Sometimes, at first. But compare it to the real alternative, which is not “a short ticket and cheap execution.” It’s a short ticket, three agent attempts, a reviewer reconstructing the missing context from scratch, a revert, and a rewrite. That’s the 180% more code shipping 30% more software gap, viewed from upstream. The work didn’t disappear when you skipped the specification. It moved somewhere less visible and more expensive.
Also: agents write most of the first draft. Point one at the ticket, the repo, and the architecture notes and it will assemble a candidate package — files in scope, prior attempts, relevant constraints, proposed verification. Reviewing and correcting that is genuinely faster than writing a ticket from scratch, and it’s a much better use of the fifteen minutes.
“Our context isn’t good enough to fill in section 2.” Correct. That’s the finding, not the obstacle. If context can’t be assembled, your agents are already guessing at it — silently, every run, right now. The intent package doesn’t create that problem. It surfaces it in a place where someone has to sign their name.
Five moves for the next two weeks#
Concrete, in order, and none of them require a platform purchase.
- Rewrite one epic’s worth of work items as intent packages. Not the whole backlog. One epic, ideally one you’ve already shipped, so you can compare what you specified against what actually happened. The gap is your training data.
- Add a constraints section to your ticket template today. Even as free text. Just the question “what must not happen?” surfaces more risk in five minutes than most design reviews.
- Promote three constraints into gates this sprint. Pick the three that get violated most — dependency rules, scope creep across modules, secret introduction. Turn each into a check that fails the build. Now they’re real.
- Define readiness as a machine-checkable gate. An item can’t enter an agent lane without resolvable context and defined verification. Enforce it in the tool, not in a meeting.
- Instrument intent quality. Track, per work item: how many agent attempts before acceptance, and how many rejections trace to a missing constraint rather than a bad implementation. That ratio is the most useful number nobody is measuring. When it’s high, the fix is upstream, and no model upgrade will touch it.
The specification was always the engineering#
Here’s the part I find genuinely clarifying about all this.
For decades we treated specification as overhead — the paperwork you did before the real work. The real work was the code. Anyone who’s shipped a system knows that was backwards: the hard part was always deciding precisely what should exist and what must never happen, and the code was the easy consequence of getting that right.
We just never had to admit it, because the code was expensive enough to look like the main event.
Agents took away the disguise. When execution is nearly free, the quality of your output converges on the quality of your intent. That’s not a threat to engineers. It’s the job finally being about the part that was always the job.
So here’s the question I’d ask your team on Monday. Take your most recent piece of agent-assisted work that came back wrong. Read the original ticket. Then ask: was the model wrong, or was the ticket incapable of being right?
I’ve been running this exercise for a while now, and the honest answer is almost never the model.
I lead AI transformation for a global SaaS platform, and the intent package is the unit of work my agent lanes actually run on. If you’ve built something similar — or you’ve found a section I’m missing — I want to compare notes. Find me on X, LinkedIn, or Telegram.
