Prompt to component: the quality is bounded by the boundary you hand over
Ask a model for a component and you get either clean, well-placed code or a sprawling mess — and which one you get is decided almost entirely before you hit enter, by how sharply you scoped the request. The quality of the output is bounded by the quality of the boundary you hand over. This is why “prompt engineering” for components is not a bag of magic phrases; it is the ordinary engineering skill of drawing the box first: what layer this component lives in, what it may and may not do, what it takes and returns. Draw the box well and the model fills it well. Leave it vague and the model invents a boundary, usually the wrong one.
A vague prompt makes the model invent the boundary
“Make a user card component” leaves every architectural decision to the model, and it will decide — usually by taking the shortest path, which means fetching inside the component, holding its own state, and hard-coding styles. The result runs, and it is in the wrong layer, coupled to an endpoint, and un-reusable. The prompt did not fail; it never specified the thing that mattered.
A scoped prompt hands over the box
Compare a prompt that draws the boundary explicitly — the layer, the contract, the prohibitions. The model now has the constraints it needs to produce the right shape:
Write a UserCard as a PRESENTATIONAL atom in src/ui/atoms/.
Props: { name: string, email: string, avatarUrl: string, onMessage: () => void }.
It renders only. It must NOT fetch, must NOT import the store, must NOT hold state.
Use the design tokens (var(--space-md), var(--color-brand)), not raw values.
Return only the component file.
Every clause removes a way the model could have gone wrong. The output is a clean, prop-driven atom because you specified an atom, its contract, and what it may not touch.
Verify against the boundary, don’t trust the prose
The prompt draws the box; a check enforces it, because a model will occasionally cross a line you drew. After generation, verify against the same boundary you specified — ideally with a guardrail, so it is not on your memory:
// the same boundary the prompt stated, now enforced as a check
test("UserCard is a pure atom", () => {
const src = read("src/ui/atoms/UserCard.jsx");
expect(src).not.toMatch(/useSelector|fetch\(|useState/); // no store, fetch, or state
expect(src).not.toMatch(/#[0-9a-f]{3,6}/i); // tokens, not raw colours
});
The workflow, then, is: draw the box (layer, contract, prohibitions), ask the model to fill it, and verify it stayed inside — with the boundary encoded once as a prompt and a check. The leverage is not in clever phrasing; it is that you did the architectural thinking up front, which is exactly the part the model cannot do for you. The harness-atom-guardrail exercise builds the check that backs this workflow, and loading-button-atom and form-field-molecule are good “draw the box, fill it, verify it” reps.