How to go from an idea to a live app with Claude Code, with a CLAUDE.md that works and tests that are enforced
Claude Code can take a one-page idea to a live URL in an afternoon, if you set it up so it cannot skip the tests. This is the setup we use: a short CLAUDE.md, plan mode, hooks that enforce the rules, and a Vercel deploy we run ourselves.
Claude Code ignores my rules and fakes green tests. Go from idea to a live app with Claude Code: a CLAUDE.md that works, plan mode, tests enforced by a Stop hook, and a Vercel deploy. Written for first-timers.
Write the idea on one page before you open the terminal
Claude Code is very good at building what you describe and has no way to build what you meant. So the first hour is ours, not the model's. We write one page: who the app is for, the three things a user can do, what a finished first version looks like, and what is out of scope. We also write down the stack, even if the reason is only that we have heard of it. For a first app we use Next.js with TypeScript, because Vercel deploys it with no configuration and the models know it better than anything else.
Keep the page concrete. "Users can save a link with a note and see their links newest first" is a feature Claude can build and test. "A clean, modern bookmarking experience" is not. If you cannot write a sentence that could be checked, it is not in the first version.
Save the page as SPEC.md in the project folder. We will point Claude at it in step 4, and it becomes the thing we check the app against in step 7. The spec changes as we go, and that is fine; it just has to change in the file, not in our heads.
# Linkbox ## Who it is for Us. One user, signed in with a password we set. ## What a user can do 1. Save a link with an optional one-line note. 2. See saved links newest first, with the note and the date. 3. Delete a link. ## Done means All three work in the browser on a phone and a laptop. Each has a test. The app is live at a public URL and the password is not in the repo. ## Out of scope for version 1 Tags, search, sharing, more than one user, a browser extension. ## Stack Next.js, TypeScript, a Postgres database from the hosting provider, Vercel.
Install Claude Code, start it in an empty folder, run /init
Install Claude Code with npm, which needs a recent Node, then sign in once with your Claude account. Make an empty folder, start git in it, and start Claude from inside it. Claude reads the folder it is started in, so where you run it matters.
Run /init first. It looks at the folder and writes a CLAUDE.md at the root. In an empty folder the result is short, which is what we want. Do not let it grow by itself; we will edit it by hand in the next step.
Then run /context. It shows what Claude has loaded into its context right now: the CLAUDE.md files it found, the rules, the skills, and how much of the window they take. This is the command we come back to every time Claude seems to forget something. If a file is not in that list, Claude has not read it, whatever you think you saved.
Two files we create at the same time. A .gitignore, so secrets and private notes never reach the repo:
.env
node_modules
CLAUDE.local.md
And a CLAUDE.local.md, for notes that are ours alone, such as a test account or a path on our machine. Claude reads it like CLAUDE.md, but because it is in .gitignore it never lands in the repo.
$ npm install -g @anthropic-ai/claude-code $ mkdir linkbox && cd linkbox $ git init $ claude > /init (asks about the project, writes ./CLAUDE.md) > /context (lists the memory files, rules and skills loaded, and their size)
Keep CLAUDE.md short and specific
CLAUDE.md is read at the start of every session and it competes with everything else in the context window for Claude's attention. The best-practices page says it plainly: keep it short, and put in it only what Claude would get wrong without it. Under 200 lines. Ours for a new app is under 40.
Three sections. Commands: how to run, test and typecheck, exactly as typed. Conventions: the handful of choices Claude cannot guess, such as where components live, which data library we use, and that we write a test before a feature. Gotchas: the things that bit us, one line each, added as they happen. That is all. Not the stack description, not a style guide, not "write clean code". Claude knows what clean code is; it does not know that our test command needs a flag.
The open issue on the Claude Code repository about mandatory rules being ignored is full of long files. A rule diluted among fifty others is a rule that gets skipped. And if a rule matters so much that skipping it would break something, it does not belong in CLAUDE.md at all. It belongs in a hook, which we set up in step 5.
For rules that apply only to part of the codebase, use .claude/rules/*.md, which are scoped by path, and @path imports to pull in a file such as SPEC.md without copying it.
Plan first, in plan mode, then build in small prompts
Open Claude, point it at the spec, and ask for a plan before any code. Press Shift+Tab until the mode reads plan; in plan mode Claude reads and thinks and proposes but does not edit files. Ask it to read SPEC.md, propose the file structure, the data model and the order it would build the features in, and to list what it is unsure about. Read the plan. Push back on anything you do not understand, because you will have to maintain this. Then approve it.
Then build in small prompts. One feature per prompt, in the order the plan gave. "Build the whole app" produces a large, tangled change that you cannot review. "Add the save-link form and the API route, with a test, and stop" produces a change you can read in five minutes.
After each feature, run the app yourself in the browser. Not because the tests are wrong, but because the spec was. The moment you see the thing working you will notice what you meant to ask for. Update SPEC.md, then ask for the next feature. When a session gets long and Claude starts repeating itself, run /clear and start fresh; CLAUDE.md and the spec are what carry the memory, not the chat.
Unsure about: should a saved link fetch the page title, or is the note enough for version 1? The spec does not say.
Enforce the rules with hooks instead of hoping
Here is the setting that separates a good afternoon from a bad week. CLAUDE.md is advice. Hooks are rules. A hook is a shell command that Claude Code runs at a fixed point, such as when Claude is about to stop or before it edits a file, and the command's exit code decides what happens. Exit 0 and Claude carries on. Exit 2 and Claude is blocked, and whatever the command printed to stderr is fed back to Claude as the reason.
We set two. A Stop hook that runs the test and typecheck commands when Claude says it is done and exits 2 if either fails. Claude then reads the failing output and goes back to work, and it cannot declare victory until the commands pass. "All tests pass" becomes a fact rather than a claim. The command also checks the stop_hook_active flag that Claude Code passes in, so it does not loop for ever on a failure Claude cannot fix. And a PreToolUse hook on Edit and Write that reads the path Claude wants to change and exits 2 if it matches our forbidden list: migrations, env files, anything with secrets.
The builder writes the lean CLAUDE.md from step 3 and the .claude/settings.json with both hooks. Commit both, so the rules travel with the repo. Add a PostToolUse hook for your formatter later if you find yourself asking Claude to format things. The hooks need jq installed, which most systems have or can add in one command.
Ask for the test first, then the feature
The order of the words in the prompt matters. "Build the save-link feature and add tests" gets you a feature and some tests that pass because they were written to match it. "Write a failing test for the save-link feature from SPEC.md, run it, show me it fails, then make it pass" gets you a test that means something. The Stop hook enforces that tests pass; this habit is what makes passing worth anything.
Keep every prompt to one feature and say where to stop. Ask Claude to report what it changed in three lines. Read the diff, not the summary. If a diff touches files that the feature should not need, ask why before you accept it; this is where tangles start.
When Claude gets stuck on the same bug twice, do not send a third "try again". Ask it to explain the bug in plain words, what it has tried, and what it would try next. Half the time, writing the explanation finds the bug. The other half, you will spot that it misunderstood the spec, and the fix is a sentence in SPEC.md.
Commit after every green feature. Claude can write the commit message. A small commit you can revert is worth more than a tidy history.
Feature 2 from SPEC.md: save a link with an optional note. 1. Write a failing test for the API route that saves a link. Run it and show me the failure. 2. Make it pass with the smallest change. 3. Add the form on the list page that calls the route. 4. Run the test and typecheck commands from CLAUDE.md. Do not touch the delete or sign-in code. When it is green, stop and tell me in three lines what changed and which files.
TipIf Claude says a test passes, ask to see the command output. The Stop hook makes this automatic, but the habit of looking keeps you honest too.
Review before you call it done
Before we call the first version done we run /code-review in Claude Code. It reviews the current diff or branch for correctness bugs and reports findings with a confidence level. It is a second pair of eyes from the same model, which is less than a human review and more than nothing, and on a first app it catches the obvious: an unhandled error, an input that is never checked, a query that is wrong for an empty list.
Then our own list, which is about the things a model does not think to check. Is .env in .gitignore, and has it ever been committed, which means checking the git history, not just the current tree. Does the app work in a fresh clone, with no files that only exist on our machine. Is there a README that says how to run it, mostly for us in three months. Does every feature in SPEC.md have a test, and is every test in the repo about a feature in SPEC.md.
Run the whole thing once more from an empty database. Then tag the commit, because the next step puts it on the internet and you want a point to come back to.
Put it online with Vercel
Vercel's command line does the deploy in three commands. Install it globally, sign in, then run vercel from the project folder. The first run of a new project asks a few questions, creates the project in your Vercel account, and deploys. The Vercel CLI docs say the first deploy of a new project is a production deploy, so what you see at the end of the command is the live URL. Every later vercel without a flag is a preview deploy with its own URL, and vercel --prod promotes to production.
Secrets go in with --env KEY=value on the command, or better in the project's environment variables in the Vercel dashboard, so they are not in your shell history. They must match what is in your .env locally, name for name. The most common failed first deploy we see is an app that works on the laptop and crashes on Vercel because one variable was never added on the host.
Push the repo to GitHub too. Connect the GitHub repo in the Vercel project settings and every push to the main branch deploys on its own, which is the point where a side project starts to behave like a product. Claude Code can do the git part for you; the Vercel login and the first deploy we do ourselves, so the account and the keys stay ours.
$ npm i -g vercel $ vercel login $ vercel (answers the setup questions, creates the project, deploys) Production: https://linkbox.vercel.app $ vercel --env APP_PASSWORD=change-me --prod (later deploys are previews unless you pass --prod)
TipOpen the live URL on your phone before you tell anyone. Half of what looks fine on a laptop is wrong at phone width.
When Claude ignores CLAUDE.md, and how to make the setup travel
If Claude keeps ignoring a rule, the tree below is the order we check things in, and the first answer is almost always the file itself. A long, vague CLAUDE.md is the top cause, and the fix is to delete, not to add. The second cause is that the rule is the kind that advice cannot enforce; "always run the tests" is a hook, not a sentence. The third is that the file is not loaded at all, which /context shows in a second.
Last, make the setup travel. Commit .claude/settings.json and, if you connected any services through MCP, the .mcp.json that claude mcp add --scope project writes. A new machine, a teammate, or you in a year then gets the same hooks and the same connections by cloning the repo. CLAUDE.local.md stays out of git by design, and a personal .claude/settings.local.json can add to the shared settings without touching them.
That is the whole method: a page of spec, a short CLAUDE.md, a plan, small prompts, hooks that make the tests a fact, a review, and a deploy you ran yourself once. The first app took us a weekend. The second took an afternoon, because all of this was already in the repo.
Claude keeps ignoring a rule. Which is closest?
How long is CLAUDE.md?
Would skipping the rule break something?
Run /context. Is CLAUDE.md in the list?
You're done when
Questions people are asking
Can I build an app with Claude Code if I cannot code? Yes, for a small app, if you can write a clear page about what it should do and are willing to read what Claude changes. The hooks in step 5 do the checking a developer would, and the deploy is three commands. You will learn to read code faster than you expect.
What should go in CLAUDE.md? Only what Claude would get wrong without it: the exact commands to run, test and typecheck, the conventions it cannot guess, and the gotchas that bit you. Under 200 lines, ideally far less. Not a style guide and not a sentence about writing good code.
Why does Claude ignore my CLAUDE.md rules? Usually because the file is long and the rule is diluted, or because the rule is the kind only a hook can enforce. Occasionally because the file is not loaded at all, which /context shows. The tree in step 9 walks through it.
How do I make Claude run the tests before it says it is done? A Stop hook in .claude/settings.json that runs your test and typecheck commands and exits 2 when they fail. Claude is then sent back with the output and cannot stop until they pass. The builder in step 5 writes it.
How do I put the app online? Install the Vercel CLI, run vercel login, then vercel from the project folder. The first deploy of a new project goes to production; later ones are previews until you run vercel --prod. Add your environment variables in the Vercel project so the hosted app has what the local one had.
Sources
- Claude Code Docs, Manage Claude's memory code.claude.com/docs/en/memory
- Claude Code Docs, Best practices for Claude Code code.claude.com/docs/en/best-practices
- Claude Code Docs, Get started with hooks code.claude.com/docs/en/hooks-guide
- Claude Code Docs, Connect Claude Code to tools via MCP code.claude.com/docs/en/mcp
- Vercel Docs, vercel deploy vercel.com/docs/cli/deploy
- GitHub, anthropics/claude-code issue #2544: CLAUDE.md mandatory rules consistently ignored github.com/anthropics/claude-code/issues/2544
- Hacker News, Claude Code as a Daily Driver, May 2026 news.ycombinator.com/item?id=48289950
How to tell when an AI answer is made up, in under two minutes
One email a week. Written by people.
New how-tos, the tools we tested and what we think, in one short email.