How to write a one-page AI feature design
A one-page design says how a model-backed feature will work and fail before anyone builds it. It names the gateway, the queue, the evals, the budget, the fallback and the security rules in one place. It matters because each of these is cheap to decide on paper and costly to retrofit.
Two engineers each remember a different rate limit. The design page settles it, and a script can check the page.
By the end of this lesson
Note
I can write a one-page design for a model-backed feature.
Key words
| Word | What it means |
|---|---|
| Design page | one page that says how a feature works |
| Requirement | a statement the design must satisfy |
| Fallback | what happens when a model call fails |
| Budget | the most a feature may spend |
| Eval | a test of answer quality over fixed cases |
The cells students fill in are left blank in this preview.
Six sections cover a feature
Write one short section for each concern. Gateway: keys, limits, model choice. Queue: which calls are jobs and how retries are bounded. Evals: the cases and the pass mark. Budget: the limit and what happens at it. Fallback: what the user sees when a call fails. Security: what the prompt may hold and what is logged.
One page forces choices. Two sentences a section is enough.
Worked example: what each section must say
| Section | A requirement it meets | Phrase to look for |
|---|---|---|
| Gateway | Callers never hold the provider key | client key |
| Queue | Slow work does not block a request | job, retry |
| Evals | A change is judged on fixed cases | cases, pass rate |
| Budget | Spending has a ceiling | daily limit |
| Fallback | The user always gets something | plain answer |
| Security | Personal data is minimised and logs are safe | personal data, log |
The cells students fill in are left blank in this preview.
A script can check a design page
Turn each requirement into a section and a few phrases that must appear. A short script reads the page and lists what is missing. It cannot judge whether the design is good. It only proves the page answered each question.
Run it in review, and keep the page short: a limit on words is a requirement too.
A common mistake
Warning
Many people think a design that passes the script is a good design. The script checks that a topic is mentioned, not that the choice is right. Passing is the start of the review, never the end of it.
Write the model helper
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const base = process.env.AI_URL || \"http://ai:4000\";' 'async function ask(messages, sample, max) {' ' try {' ' const res = await fetch(base + \"/v1/chat/completions\", {' ' method: \"POST\",' ' headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" },' ' body: JSON.stringify({ model: \"lab\", messages: messages, max_tokens: max || 200 }),' ' signal: AbortSignal.timeout(30000),' ' });' ' if (res.ok === false) throw new Error(\"status \" + res.status);' ' return (await res.json()).choices[0].message.content;' ' } catch (error) {' ' console.log(\"Recorded sample: no model answered (\" + error.message + \").\");' ' const list = [].concat(sample);' ' const turn = messages.filter(function (m) { return m.role === \"assistant\"; }).length;' ' return list[Math.min(turn, list.length - 1)];' ' }' '}' 'module.exports = { ask };' > model.js"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Write the design check, part 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' '// A one-page design for a ticket summary feature, invented for the lesson.' 'const design = {' ' gateway: \"Callers use a client key. The gateway applies a rate limit of 60 a minute and picks the model.\",' ' queue: \"A summary is a job. A worker runs it and a retry is bounded to three tries.\",' ' evals: \"Forty cases with known answers. We compare the pass rate of each prompt version.\",' ' budget: \"A daily limit per team. Past it, the feature says so and stops.\",' ' fallback: \"If the model fails we try a second model, then show the first lines of the ticket.\",' ' security: \"Tickets may hold personal data, so the prompt gets only what it needs.\",' '};' > design.js"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Write the design check, part 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const reqs = [' ' { id: \"R1\", section: \"gateway\", words: [\"client key\", \"rate limit\"] },' ' { id: \"R2\", section: \"queue\", words: [\"job\", \"retry\"] },' ' { id: \"R3\", section: \"evals\", words: [\"cases\", \"pass rate\"] },' ' { id: \"R4\", section: \"budget\", words: [\"daily limit\"] },' ' { id: \"R5\", section: \"fallback\", words: [\"plain answer\"] },' ' { id: \"R6\", section: \"security\", words: [\"personal data\", \"log\"] },' '];' >> design.js"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Write the design check, part 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function check(d, rs, maxWords) {' ' const out = [];' ' rs.forEach(function (r) {' ' const text = (d[r.section] || \"\").toLowerCase();' ' if (text.trim() === \"\") { out.push(r.id + \": no \" + r.section + \" section\"); return; }' ' r.words.forEach(function (w) { if (text.indexOf(w) < 0) out.push(r.id + \": missing \" + w); });' ' });' ' let n = 0;' ' for (const k in d) n += d[k].split(\" \").length;' ' if (n > maxWords) out.push(\"too long: \" + n + \" words\");' ' return out;' '}' 'const problems = check(design, reqs, 120);' 'problems.forEach(function (p) { console.log(\"Problem:\", p); });' 'console.log(\"Requirements met:\", reqs.length - problems.length, \"of\", reqs.length);' >> design.js"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Check the design page
docker exec -w /home/node/project agent node design.jsShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
This Run needs no model
The check is plain code over text, so it makes no call. The helper is written for later exercises, and a Run that does call a model prints a labelled Recorded sample when none answers.
The design is invented. A real design names your own services and numbers.
One possible output
| Line | What it shows |
|---|---|
| Problem: R5: missing plain answer | The phrase is missing, though the section does say what the user sees |
| Problem: R6: missing log | The security section says nothing about logs |
| Requirements met: 4 of 6 | Four sections answered every question |
The cells students fill in are left blank in this preview.