What does building a paid feature with Claude Code actually look like?

It looks like one clear instruction, a few minutes of the agent reading before it writes anything, a
diff covering six or seven files, a test run it does itself, and one review pass from you. The
feature that comes back is account-scoped, permission-checked, paywalled, and tested, because those
are the conventions it found in the codebase rather than things you asked for.

Here is the loop in detail, and the parts where it goes wrong.

## The setup that makes the difference

Claude Code works in your terminal. It reads files, writes changes, and runs commands, which means it
can check its own work. That last capability is the one that changes the character of a session, and
it only pays off if there is something worth running.

So before anything else, the codebase needs two things:

1. **A guide file it reads first.** `CLAUDE.md` in the project root, telling it the one right way to
   do each thing here.
2. **A test suite it can run.** `bin/check` in this case, which runs the tests, the linter, a static
   security scan, a dependency audit, and a secret scan in one command.

Without the first, it guesses at your conventions. Without the second, "done" is something it asserts
rather than something it verifies.

## The instruction

Here is the entire prompt for a real feature:

```
Add a paid Bookmarks feature. A bookmark has a url, a title, and an optional note.
Use the crud-with-billing skill.
```

That is it. Note what is not in there: no mention of accounts, no mention of permissions, no mention
of tests, no mention of the design system. All of that is already written down, and repeating it in
the prompt is how you end up with a prompt that is longer than the feature.

## What it does before writing anything

The first thing that happens is reading, and it is worth watching rather than skipping.

It opens `CLAUDE.md` and finds the rule that governs everything: every model belongs to an account,
every query goes through the current account, every controller checks permissions. Then it opens the
worked example that already exists in the codebase, the one deliberately left there to be copied, and
reads the whole vertical slice: the model, the permission policy, the controller, the screens, and
the tests.

By the time it writes its first line it has a template. It is not inventing a structure, it is
following one.

## The diff

What comes back is about seven files:

- The model and its migration, with the account reference and validations.
- A permission policy that denies by default and filters every query to the current account.
- A controller that queries through the current account rather than through the model directly, and
  carries the one line that requires a paid subscription.
- Screens, using the existing design system classes rather than inventing new ones.
- The route.
- Model, permission, and request tests, including the one that matters most: a request for another
  account's bookmark returns a 404 rather than someone else's data.

That last test is the one people forget when they write this by hand, and it is the difference
between a feature and an incident.

## Where you actually step in

Three places, and none of them is the code style.

**The data model.** The agent will make reasonable choices and some of them will be wrong for your
product. Should a bookmark belong to a user or to the whole account? Should the url be unique per
account? These are product decisions wearing schema clothing, and they are much cheaper to fix now
than after there is data.

**Whether it should be paid at all.** You said paid, so it made it paid. Whether that is right is not
something it can know.

**The empty state and the copy.** It will write something sensible and generic. Sensible and generic
is exactly what your product should not sound like.

## Where it goes wrong

Being honest about the failure modes, because they are consistent.

**It over-builds when the request is vague.** "Add bookmarks" with no further detail produces
bookmarks with tags, folders, search, and bulk import. Every one of those is a thing you now own.
Being specific about what you do *not* want is worth more than being specific about what you do.

**It follows a bad example faithfully.** The flip side of pattern-matching your codebase is that it
will copy your mistakes with the same enthusiasm as your conventions. If the worked example has a
flaw, every feature built after it inherits the flaw. Fix the example, not the copies.

**It declares victory on a partial run.** If the test command is slow or noisy it will sometimes
summarize rather than actually check. The fix is a single command that exits non-zero on any failure,
and a guide file that names it as the definition of done.

## The part that surprises people

The tests. Not that the agent writes them, but that it uses them.

A run where the suite goes red partway through does not come back to you broken. It reads the
failure, fixes it, and runs again. You see the finished state. This is the practical difference
between an agent that can execute commands and one that only writes text, and it is why the setup
work at the top of this post is worth doing before the first feature rather than after the third.

## What this does not remove

You still have to review. The diff is small and it is entirely about your feature, which makes the
review genuinely quick, but "quick" is not "unnecessary". Read the migration and the permission
policy properly, every time. Those are the two files where a mistake is expensive and silent.

And it does not remove the need to know what you are building. The agent is very fast at producing
the thing you described. It has no opinion about whether the thing was worth describing.

## If you want to try it

The shape above works because the codebase was arranged for it: a guide file, a worked example, one
verification command, and the plumbing already built and tested. That is [what a starter kit
is](/blog/what-a-starter-kit-is), and it is [why the first run otherwise disappears into
plumbing](/blog/where-the-first-run-goes).

The same loop works with [Codex](/blog/building-with-codex), [Cursor](/blog/building-in-cursor),
[Hermes](/blog/building-with-hermes), and [OpenClaw](/blog/building-with-openclaw), with differences
worth knowing about in each.
