Lately a surprising share of my time goes to showing people what it looks like when software gets built this way, rather than building it. And then fielding the question that always comes next, which is some version of: okay, but what does that mean for me?
That question has a different answer depending on who's asking. Developers want to know what's left for them to do. Managers want to know what the process looks like and who's accountable when it goes wrong. And then there's a third group I keep running into, people who used to write code, stopped a long time ago, and now own a product. They know exactly what they want built. They've just been told for twenty years that wanting it isn't the same as being able to make it.
The Email
I'll call him Tiberius. Tiberius runs a software product company I build for. He grew up on a command line, same as I did, and then spent the next couple of decades on the business side. He hasn't shipped code in years. What he does now is decide what the product should do, and he's very good at it.
Our normal rhythm is simple. He says "hey, let's add this," we get on a call, I ask questions, and then I go write the ticket. On a Friday morning he sent me two requests. The first one was the kind of thing a product owner writes when they've been watching real users:
Who is this email from? If someone is working a request, they want to know who it originally came from. To do this, they must click on the email tab and scroll down to the originating email at the very bottom. Can we display, prominently somewhere on the top of the screen, something like "Email from: originating email address"? That lets them know who it came from without having to dig for it.
Requests come into a shared inbox, get forwarded around internally, and by the time someone is working one, the person who actually sent it is buried at the bottom of a chain. He wanted that surfaced. That's the whole ask. There's a pain, a workaround, a request, and even a UI suggestion, all in four sentences.
The second request was bigger, a classification lookup against a public reference dataset with a searchable dropdown and a toggle for AI auto-assignment. Under it, he'd pasted something like six hundred words from Claude about how to build it: a reference table loaded from the public data, a search tool the model would call at extraction time, confidence scores, a needs-review flag, a way to learn from corrections, even a caveat about the dataset's next scheduled revision.
It was a good plan. I'd have been happy to get it from a senior engineer. It was also written by something that had never seen the codebase and didn't know what tables existed or what the extraction step already returned. It was a good plan written blind, and that's the default state of almost everyone's experience with these tools right now. You ask a smart thing a question and get a smart answer that has no idea where it's standing.
What struck me reading it was that the work Tiberius had just done, having that conversation with Claude, was the work I was about to do. The only difference was I'd be doing it inside the repo, where Claude could see the code and had my process to follow. So I wrote back:
I'm almost afraid to make this suggestion. And tell me if it's a step too far for you. I wonder if we should set you up to be able to add and refine tickets the same way I do. We can hold off having you clank it. Might be a fun experiment.
I do this for a living and I still paused before suggesting it to a client. He wrote back two minutes later: "Let's explore."
The Conversation
He'd installed Claude Code and the GitHub CLI the week before and hadn't touched either. The first fifteen minutes of our session were the unglamorous part: make a folder, clone the repo, type claude, log in.
I had him type /skills. The whole framework was already there, because it lives in the repo. Every rule, every stage, every standard I've written down over the last eight months was sitting in his terminal waiting for him. He didn't have to know any of it. He just had to know which one to call first.
The skill is called add-story. You give it a narrative of what you want and it starts a conversation. I told him the easiest thing to do was paste in the email he'd sent me, so he did.
What happened next is the part I wanted him to see. Claude read the codebase. It found an existing ticket that had already tried to solve this and noted that it matched on the wrong sender, the coworker who forwarded the email, not the person who originally sent it. Then it said it needed his input before proposing anything, and asked three questions.
Name and address, or just the address? New requests only, or backfill the old ones? Show it only on the detail page, or also as a column in the list?
He answered the first two without thinking. On the third he opened the live application in another window and looked at the list view, decided it was already crowded, and went with detail page only. I pointed out that this was a cheap decision: "We ain't typing a stitch of code, and if we want it later, we can."
Then Claude proposed the story. Summary, acceptance criteria, dependencies, out-of-scope. Tiberius read the acceptance criteria line by line and checked each one against how his users actually behave. The originating sender is the earliest, bottom-most message in the chain. Good. The chain detection recognizes the common forward and reply header styles. Good. If there's no chain, the outer sender is the originator. "If it hasn't been forwarded, that would be true." If the bottom message has a display name but no address, which happens with internal forwards from certain mail systems, show the name on its own. If neither, store nothing. The first email sets the value; later emails don't override it.
He stopped at the display-name case. "Did you or I even mention this?"
We hadn't.
Before accepting it he asked Claude what he was missing, and took one suggestion from the answer: as written, there was no way to fix a wrong value. So the field became editable, and he told Claude where on the screen it should go.
The Cold Read
The story went to GitHub as an issue. The next thing the process does is hand the ticket to a fresh agent with no memory of the conversation and ask it to read the ticket cold. The idea is that if the ticket only makes sense to the agent that wrote it, it isn't done.
The cold read came back with a short list, and some of it was in developer language: a question about status transitions, one about whether the integration API should expose the new field, one about audit entries. Tiberius read it and said, reasonably, "I don't understand what the status of the ticket has to do with reading the email."
So he asked Claude to explain those three in plain terms. It did. The status question turned out to be a confirmation that the sender value never changes when a request moves through its workflow, which he agreed with instantly. The API question was whether a downstream system should receive this field now, and he had an answer for that too: eventually, yes, but we haven't mapped that field yet, so UI only for now. The audit question was whether the system filling the field automatically should write an audit entry the way a user edit does. No. Only the human edits get audited.
Three questions that looked technical turned out to be product decisions once they were translated, and he made all three without any help from me.
I started to say "so this is how a developer is going to—" and he cut me off.
Or not a developer. This is how all the requirements are going to be written. It could be a developer, but the beauty of it is it doesn't have to be.
The Seam
There's one more step before a ticket is ready to build, and I had him run it. The refinement skill takes the story and layers the technical approach on top: which files, which tables, which tests, what the code review of the spec found. It asked him one more question first, how the system should know which email domains are internal so it can skip his own staff and find the original sender. He didn't hesitate: use the domains of everyone in the organization, no new setting required.
Then it generated the technical plan, with an ALTER TABLE, a dependency injection registration, a list of test fakes that needed updating, and a code review of the spec that found eight gaps, each with a proposed fix. Tiberius looked at it and said, more or less, "I have no idea what it's talking about there."
That's the seam, and I want to be precise about where it is. He wrote the ticket. He answered every product question. He translated three developer-speak items back into product decisions and made them. And then the process reached the part that's about how the code is structured, and he was done.
That's where he's supposed to be done. Somebody who knows the code should look at that refinement before it builds, and somebody who knows the code should look at the pull request after. On his team that's a developer, and she'd already asked, sensibly, whether she could review requirements before they went in. This is where she does that. What she doesn't do is write the code, and neither does anyone else. The thing that was always the bottleneck is now the part of the process that runs unattended.
I didn't have him kick off the build. Partly because you'd normally batch a few tickets and run them together, and partly because, well, I'd said we'd hold off on that. I ran it from my side, showed him where to watch it in GitHub, and told him it'd be in the development environment in an hour or two, which it was.
The Two Emails
The thing I keep coming back to is the two emails. The first conversation produced a competent plan that didn't know where it was standing. The second produced a ticket that found the existing half-solution, surfaced an edge case nobody had mentioned, asked the right three questions, and ended up with a technical spec a developer could review in ten minutes. Same person, same week, same model. What changed was that the second conversation happened inside the code, on top of a process that knew what a good ticket looks like.
I don't think most people have caught up to what that means. Everyone's excited that the model can write code. The more interesting thing is that when the process is written down and the model can see the code, specifying what to build becomes the work. Getting the specification right is the job now. And a person who owns the product, who has watched the users and knows what the screen should do, is better at that part than I am.
I'm not saying developers go away. Far from it. When the people writing tickets can't read the code, and the thing writing the code never gets tired or asks whether this is a good idea, the need for someone who understands how it's built goes up, not down. Somebody has to design the process, review the refinement, read the PRs, and own the architecture when the agents get it wrong. That's still a skilled job and it's still mine. But the shape of the team changes. The people who know what to build end up driving, the people who know how it's built end up reviewing, and a digital workforce does the part in the middle that used to eat everyone's week.
Tiberius had to run to another meeting. On his way out he said this had been a lot of fun, that he'd enjoyed the requirements part, that he's nowhere near taking it through the whole cycle but he liked being able to contribute in that way. And then: "Getting back into a command line prompt is kind of fun. That's how I grew up."
It wasn't a step too far. It was about one step short of the whole thing, which is exactly where I wanted him to stop. For now.
Kevin Phifer is the founder of Theoretically Impossible Solutions LLC, specializing in agentic AI development and consulting. You can reach him at kevin.phifer@theoreticallyimpossible.org.