How to Write a README With AI From Your Project Facts
Your README works perfectly on the one machine where the tool was already installed. Everyone else hits a missing prerequisite in the first ninety seconds. Here's how to build a README from your real setup facts — and the clean-machine run that decides whether any of it is true.
Build a README PromptIt works on the machine where everything is already installed
The README is honest, as far as its author knows. Install, usage, a line about what the thing does. It has been correct for eighteen months, because the only person who reads it is the person who wrote it, on a laptop where the runtime was installed in 2023, the environment variable is in a shell profile nobody remembers editing, and the command is on the path because of a decision made during a different job. Then someone clones it. They are ninety seconds in, they have an error nobody warned them about, and the README has nothing to say — because the thing that broke was never a step. It was a fact about the author's machine that never made it onto the page.
That's the whole difficulty of a README, and it isn't a writing problem. The person who knows the project is the worst-placed person to notice what a newcomer needs, and no amount of care fixes it, because you can't see the assumption you've been standing on for two years. AI helps in a narrow, real way: it holds a structure and pushes back on "install the dependencies" until you give it a command. What it will not do is know any of it. NewPrompt builds a README prompt in your browser, and that's where its involvement ends — there's no connection to your repository or source control, nothing reads your file tree, nothing runs your install command or your run command, and nothing checks whether that environment variable exists or that the package name is real. Which matters more here than in most documents, because a model asked to fill a README produces a plausible install command, a plausible port, a plausible package name — all invented, all looking exactly like the real thing. Any command that didn't come from you is a guess. And no README is finished on the strength of reading well: the only thing that establishes it is someone running it on a machine that isn't yours, which is a thing you do, not a thing the draft does.
You have about ninety seconds
Time the reader instead of imagining them, because the clock is what settles every argument about what belongs. They arrived from a search result. In the first ten seconds they're deciding whether this is even the right kind of thing — and if the answer is no, the kindest README lets them leave immediately. By thirty they want to know what it'll cost them to try: a runtime they don't have, an account they'd need to create, a platform it doesn't support. Somewhere around sixty they're typing the install command. By ninety they've either seen it work or they've hit something and started deciding whether you're worth the debugging.
That clock is brutal about ordering. Anything the reader needs at second thirty cannot be on the third screen, which is why limitations belong near the top even though they read like an admission, and why a paragraph of positioning is worse than a sentence. It's also brutal about scope: the document ends the moment the thing runs. Everything past that moment is a link — the API reference for someone integrating, the architecture notes for someone about to contribute, the changelog for someone upgrading. Each of those is a different reader arriving later through a different door, and every one of them you let in pushes the install command further down the page, away from the only person who is actually here.
Step 1: Say who's arriving and what they came for
Start with the sentence the model can't write for you: what this is and who it's for, in a form that lets the wrong reader leave quickly. "A CLI that normalizes messy spreadsheet exports into flat CSV, for people who receive .xlsx files from other teams" does more work than a paragraph of positioning, because it answers the first question and disqualifies everyone it should. Vagueness here isn't a style problem — it costs you the reader who would have been perfect, because they couldn't tell.
Then give the model the material it has no other way to get: what the project does, who uses it, what they use it for, and the awkward specifics — the runtime version, the exact package name, the real command with its real flags. Be precise about what you don't have. If nobody has run this on Windows, that's a fact and it belongs in the draft rather than being smoothed over. And keep every secret out of what you paste and out of the document: a README is the most-copied file in the project, so a token in an example is a token in every fork of it forever. Environment variables get named and their values shown as placeholders, always, including the ones that look harmless.
Step 2: Separate the commands a user runs from the ones you type
This is the single most common way a README fails, and it's almost invisible from the inside. The maintainer writes down the commands they type — clone the repo, install the dependencies, run it from the project directory. Those are contributor commands. The person reading the README isn't contributing; they want to *use* the thing, and for them the install is a completely different line. A README whose install section starts with a clone has quietly told every user they're about to work on the project, which is not what they came for.
So sort the material before you prompt: prerequisites are what must already be true on their machine, install is how they get it, configuration is what they set, usage is what they run. Then get concrete about each, because this is where the model's help is real and its limits are absolute. The rule pushes it to reject "install the dependencies" and ask for a command — good, that's the pressure you want. But the command it offers to fill the gap is a guess dressed as a fact. The README Prompt Template is a copy-paste prompt built around that pressure: it pins Overview, Installation, Usage, Examples and Configuration, and its rule is that code examples must be usable as written — no pseudo-code, no placeholder ellipses. It's worth knowing what it says about itself: it produces a new document and there's no source text to summarize, which is exactly right — everything in it comes from your description. The Markdown Output Builder is the tool that builds that prompt. Its README document type carries the rules that a project description opens the file and the most common use case comes before the edge cases; its README setup goes further and turns code examples from allowed into required. You run the result in your own AI assistant.
Step 3: Make first success observable
A run command on its own is half an instruction. The reader types it, something scrolls past, and they can't tell whether that was success, a warning worth caring about, or a failure that exited zero. So show what a working run looks like: the command, and the output it prints when it worked. Two lines, and it converts "I think it ran?" into something the reader can check for themselves.
Keep the example minimal and real. One command, one representative input, the actual output — not a tour of every flag, because the reader isn't learning the tool yet, they're confirming it works. The temptation is to make the example impressive; the job is to make it *verifiable*. And this is where the model's confident helpfulness is most dangerous: asked for expected output it will compose something that looks like your program's output, formatted convincingly, invented completely. Paste the real thing from your terminal — and paste it, don't type it from memory, because the line you remember is the line from before you changed the output. If it contains a run-specific number, say so, rather than letting the reader think their row count is wrong. Then add the failure that happens most: not a troubleshooting section that guesses at what might go wrong — the model's suggestions there are fiction about a system it has never seen — but the one or two failures you've actually watched people hit, with the fix you actually gave them.
Step 4: Say what it doesn't do
Limitations feel like an admission and they're a service. The reader is deciding whether to invest, and the cheapest thing you can give them is a fast no: the formats you don't support, the platform nobody has tested, the scale where this stops being appropriate, the thing it's routinely mistaken for. Every one of those saves someone an hour and saves you an issue that was never a bug.
The model won't produce this section unprompted, and it can't — it doesn't know what your project can't do. Ask for it explicitly and fill it yourself, from the questions you keep getting and the ones you've had to say no to. One practical note on placement: the five-section skeleton has no Limitations heading, and its rule is that extra material folds into the closest existing section rather than sprouting a new one — so limitations ride at the end of Usage or Configuration. Which section matters less than the clock: the reader has to hit them before they invest, not after. And keep each one to a line and a link. "Reads .xlsx only — .xls is not supported" is the whole entry. The reader who needs to know why is a different reader, arriving later, through a different door.
Step 5: Run it on a machine that isn't yours
Everything up to here produces a draft, and a draft is a hypothesis about your own project. The only thing that settles it is watching the path run somewhere clean — a fresh container, a colleague's laptop, a VM, anything without your accumulated history on it. Go through the document literally: copy each command as written, paste it, and fix nothing from memory. The instinct to type the flag you know is missing is exactly the instinct that produced the broken README in the first place.
What surfaces is rarely subtle. It's a prerequisite you never knew was a prerequisite, a command that only works from the project directory, an environment variable your shell has had set since a previous job. It's also where stale content shows up — the output line that hasn't matched what the tool prints since you added a column to it. One check is cheap enough to run before you spend a person's afternoon on it. The AI Output Validator reads the headings out of your draft and compares them against the list you asked for, in your browser, and hands back a repair prompt when something's off — a dropped Examples section, or Configuration sitting where Examples should be. The Validate Markdown Structure resource is that check already pointed at a README; its own sample is one that shipped without its Installation and Examples sections, which are the two drops it exists to catch. It tells you the heading is there. It has no opinion about whether the command underneath it works, and that part is what the clean machine is for.
Common mistakes
A README is read once, quickly, by someone with no patience and no context. What loses them:
- Documenting the contributor's install instead of the user's. A first step that says clone the repo has told everyone who just wanted to use the thing that they're now working on it.
- Prerequisites written from memory. The runtime you've had since 2023 isn't a memory, it's a prerequisite — and it's the most common ninety-second failure there is.
- Running the model's invented commands. If you didn't supply it, it's a guess, however well it's formatted.
- A run command with no expected output. The reader can't tell success from a warning from a silent failure, so they assume it worked and find out later.
- Badges that lie. A build badge pointing at a branch nobody runs, or a version badge two releases behind, is worse than no badge — it's a claim, and the reader believes it until something breaks.
- Documenting `main` instead of the published version. You're writing from the working tree; they're installing what's on the registry. Every flag you added last week is a command that fails for them.
- Shipping it because it reads well. Prose quality is not evidence — and NewPrompt doesn't run your commands or check that any of it is true.
A CLI's README, and the clean run that graded it
A small fictional utility, its README as it stood, and what happened when someone who'd never seen it followed the document exactly.
A CLI README rebuilt from its maintainer's real setup facts, and the clean-container run that still caught a prerequisite nobody could see and the one output line that was typed from memory instead of pastedTHE README AS IT STOOD (honest, and wrong in four ways):
# tabtidy
Cleans up spreadsheets.
## Install
npm install
## Usage
Run tabtidy on your file.
what's wrong isn't the prose:
- "npm install" is the CONTRIBUTOR command. it installs this
project's dependencies after a clone. a user needs -g and a
package name. the maintainer wrote the line he types.
- no runtime version. he's had it since 2023; it isn't a memory,
it's a prerequisite.
- "Run tabtidy on your file" is not a command.
- nothing about what a working run prints, so nobody can tell.
THE FACTS ONLY THE MAINTAINER HAS (all fictional, for the example)
does normalizes messy .xlsx exports -- merged cells, stray
header rows -- into one flat CSV
for people who receive spreadsheets from other teams
needs Node 20+ (18 fails at startup, not at install -- so the
global install succeeds and the first run doesn't)
install npm install -g tabtidy
run tabtidy input.xlsx -o clean.csv
prints Wrote clean.csv (1204 rows, 8 cols; dropped 3 empty
header rows) <- typed from memory. he did not
re-run it to check.
config TABTIDY_SHEET=<sheet name> default: the first sheet
can't do .xlsx only, no .xls. formulas are read at their last
cached value -- it does not recalculate them.
seen fail "command not found" right after a global install, when
npm's global bin isn't on PATH
THE DRAFT (built from the facts above -- nothing invented)
# tabtidy
Normalizes messy .xlsx exports into one flat CSV. For anyone who
receives spreadsheets from other teams and needs them usable.
## Overview what it does, who it's for, in two lines
## Installation Requires Node 20+. npm install -g tabtidy
## Usage tabtidy input.xlsx -o clean.csv
-> Wrote clean.csv (1204 rows, 8 cols; dropped
3 empty header rows)
(row counts vary -- yours will differ)
Limitations: .xlsx only. formulas read at last
cached value.
## Examples one messy input, one clean output
## Configuration TABTIDY_SHEET=<sheet name> default: first sheet
If "command not found" after install: npm's
global bin isn't on your PATH.
THE CLEAN RUN (a colleague, a fresh container, fixing nothing from
memory)
1. npm install -g tabtidy -> worked. as predicted: the
install never touches the runtime version.
2. tabtidy input.xlsx -o clean.csv -> FAILED at startup. the
container had Node 18. the draft SAID Node 20+ -- and the tester
read straight past it, because it sat as prose at the end of the
install line instead of standing on its own where someone
checking prerequisites would look.
fix: its own line, above the install command.
3. retried on Node 20 -> ran, but the output line was
stale. it prints "columns"; the README said "cols". that fact was
the one thing in the block typed from memory rather than pasted
from a terminal, and it was the one thing that was wrong.
4. TABTIDY_SHEET -> worked, and the tester asked
what happens with a sheet name that doesn't exist. nobody knew.
that is now an open question, not a sentence in the README.
two of the four defects came back in a new shape: the missing
prerequisite became a misplaced one, and the absent output line
became a stale one. neither was a writing problem, and neither was
visible from the inside -- the container found both in four minutes.
Where this fits in NewPrompt
The concrete pieces line up as build-then-check. The README Prompt Template is the copy-paste prompt — the five-section skeleton with runnable examples required — and the Markdown Output Builder is the tool that builds it, with a README document type of its own that opens on a project description and puts the common case before the edge cases. Then the Validate Markdown Structure resource, run through the AI Output Validator, does the heading scan against that same skeleton. Both tools build or check in your browser; the running is yours. Those two steps sit inside the AI Code Documentation Workflow, whose write-up step reaches for this exact README prompt. Two honest notes about that fit: the workflow starts from existing code, and most of a README isn't in the code at all — your audience, your prerequisites, your configuration, what a working run prints, what the thing can't do, none of that is readable from a source file. And its validation step checks that the markdown structure holds, which is not the same as checking the commands work. That part is the clean machine, and the workflow doesn't have one.
Where a README ends is worth stating once. It's the front door: what this is, and how to get it running. API documentation is the reference someone reads once they're integrating against an endpoint — a README links it, or shows one call, and stops. A codebase explanation is for the person who has already decided to contribute and needs the map; a README is what they read before they cared enough to clone it, and it's the input that pass assumes you already have. Architecture notes explain why the system is shaped the way it is. A changelog tells an existing user what moved.
A README's accuracy has no relationship to how carefully it was written. You can spend an afternoon on it, get the structure right, get the tone right, and still ship the version that fails in ninety seconds — because the defect was never on the page. It was in the gap between your machine and everyone else's, and no amount of re-reading closes a gap you can't see. That's why the clean container in the example found two things a careful draft from real facts hadn't: it wasn't smarter, it just didn't know anything, and not knowing anything is the exact qualification the job requires. So get someone with no context to run it start to finish, watch where they stop, and write down what stopped them. The model can shape the document all day. It can't be the person who doesn't already know.