Note: general recommendations only, not professional advice. You are responsible for checking before use. The full text is at the end.
What you'll have at the end of the hour
- One skill (an instructions file) for the agent, telling it to write a plan before code, and to stop until you answer.
- One HTML template, a single file with no outside libraries, that works in English and Hebrew and looks right on a phone screen.
- A first plan page for a real task of yours, with:
- a two or three sentence summary, without jargon;
- outcomes as statements you can check, each with an example or a sketch of the screen;
- 3 to 5 open decisions, each with 2 or 3 options and a marked recommendation;
- risks, and what is deliberately left out;
- a "Send answers" button that copies a ready answer block to paste.
- A 2-minute habit: read, mark, send. "skip" tells the agent to go with every recommendation.
What you need
- One coding agent: Claude Code, Cursor or Codex, and a project it works in.
- A phone with a browser.
- A way to get a file to your phone: email to yourself, a WhatsApp or Telegram message to yourself, or a cloud folder.
Why it works: nobody reads a long text plan, and then after an hour of code you find out the agent understood something else. A statement like "A client gets one reminder, 24 hours before class" takes a second to check and say "no, 3 hours". That change costs a minute before the code, and an hour after it.
The kit, step by step (60 minutes)
Step 1 (5 minutes): Put the template in the project
What to do: In the project folder, create a folder plans, and in it a file template.html with the template from the appendix at the end of this kit.
How: Open the file in a browser on your computer (double-click). You see a sample plan page with one card and one decision. Tap "Approve", then "Send answers", and the answer block appears at the bottom. If it works on the computer, it will work on the phone.
What's in the template: all the content sits in one JSON block inside the file. The agent replaces only that. The design, the buttons and the answer block builder are already in, so the agent doesn't write HTML from scratch and can't break the button. The page loads nothing from the network, and strips scripts, images and links from the sketches.
Step 2 (10 minutes): Install the skill
What to do: Copy the instructions file from the appendix.
How, per agent:
- Claude Code: create the file
.claude/skills/plan-page/SKILL.mdin the project and paste the instructions as they are. The top lines (name,description) are what lets Claude Code use the skill on its own. - Cursor: create the file
.cursor/rules/plan-page.mdc, paste the instructions, and change the top lines so they havedescriptionandalwaysApply: false. - Codex: add the instructions (without the top lines) to the
AGENTS.mdfile at the root of the project.
Step 3 (5 minutes): A first task
What to do: Pick a real, medium-sized task: a small feature, not a one-line fix. Write to the agent:
Before you write code, make a plan with the plan-page skill.
The task: [one or two sentences, the way you'd explain it to a new hire].
Who uses it: [clients / the team / me].
What matters to me: [for example: no new monthly cost, works on a phone].
Write the plan in English, and stop until I send answers.
The agent reads what it needs in the project, writes a file like plans/2026-10-04-class-reminders.html, and tells you where it is.
Common mistake: a task that's too small. A button fix doesn't need a plan, and the agent will invent decisions to fill the page. The skill tells it not to ask what it can decide from the code. If you still get empty decisions, tell it "delete decisions that don't change what gets built".
Step 4 (5 minutes): Get it to your phone
What to do: Send the file to yourself and open it in the phone's browser.
How: an email to yourself with the file attached, a message to yourself on WhatsApp or Telegram, or a cloud folder. Some apps show an HTML file in a preview that doesn't run buttons. If the buttons don't respond, choose "Open in browser" (Chrome or Safari).
Want to skip this step? You can ask the agent to send the file itself, if you've connected a sending tool to it. That's optional.
Step 5 (2 minutes): Answer
What to do: Go through the page from top to bottom.
How:
- The summary: is this what you asked for? If not, it's better to write to the agent in your own words and ask for a new plan.
- Each outcome: "Approve", or "Change" and write what. An outcome you don't mark counts as approved.
- Each decision: the recommendation is already selected. Change it only if you disagree.
- "Send answers": the block is copied. Paste it into the chat with the agent.
Agree with everything? Write one word to the agent: skip. It will work by the plan and by every recommendation.
Step 6 (15 minutes): The agent builds and reports by outcome
What to do: The agent writes the code according to your answers. At the end, ask for a report by the same outcomes, so you check against what you approved and not against memory.
Done? Give a report by the plan: for each outcome (O1, O2...) say whether it was done, and how you checked it (an automated test, a screenshot or a command you ran).
Then list everything you did differently from the plan, and why. If an outcome wasn't done, don't mark it as done.
Step 7 (10 minutes): Fit the skill to you
What to do: After a plan or two, add your own rules to the skill. One line per rule, at the end of section 2.
Examples of rules worth adding:
- "Every outcome a user sees gets a sketch of a phone screen."
- "A decision that adds a monthly cost always comes first, with the price."
- "If the task touches client data, add a risk that says what is stored and where."
No skill at all: you can paste this prompt at the start of a chat, together with the template:
Before you write code, write a plan as an HTML page. Here is the template: [paste the template, or write: plans/template.html].
Replace only the JSON block inside <script id="plan">. In it: lang ("en"), title, summary (2-3 sentences in business language), outcomes (2-6 checkable statements, each with an example of kind mockup, text or code), decisions (3-5, each with 2-3 options and recommended), risks, out_of_scope.
Don't ask what you can decide from the code. Save the file in plans/, tell me where, and stop until I send an answer block or "skip".
Full example: Gal Pilates Studio (a fictional business)
Everything in this example is fictional: the studio, the clients, the instructors and the classes.
The studio has a class booking site. The owner asked the agent: "a reminder to clients a day before class". This is the plan the agent wrote, as it appears on the page.
The summary: Every client booked for a class gets an automatic reminder before the class, with a cancel link. A spot that opens up is offered to the first person on the waitlist. The booking system, prices and class schedule don't change.
The outcomes, and what appears under each:
| Outcome | Example on the page | |
|---|---|---|
| O1 | Every client booked for a class gets one reminder before the class, with the class name, time and instructor. | A sketch of the message: "Hi Maya, a reminder: tomorrow 18:00 Reformer Pilates with Roni. Can't make it? Cancel" |
| O2 | A client who taps the cancel link gives up their spot in one tap, without signing in. | A sketch of the cancel screen with a "Yes, cancel" button |
| O3 | When a spot opens up, the first person on the waitlist gets a message and has two hours to confirm before the spot moves to the next one. | The waitlist message text |
| O4 | The studio owner sees in the class log who got a reminder, who cancelled and who came in from the waitlist. | A sample row from the class log |
The open decisions:
| Question | Options | Recommended | |
|---|---|---|---|
| D1 | Which channel? | Email (free, read less) / SMS (almost always read, a cost per message) / Email, and SMS only for those who chose it | Email, and SMS only for those who chose it |
| D2 | When to send? | 24 hours before (time to fill the spot) / 3 hours before (fresh, little time to fill) | 24 hours before |
| D3 | What happens when someone cancels? | Message the first on the list, two hours to confirm / Message the whole list, first to confirm gets it | Message the first on the list |
Risks: clients without a valid email or phone won't get a reminder, and the log will flag them. A cancellation less than two hours before class probably won't be filled from the waitlist.
Out of scope: cancellation fees or no-show charges. Changing the booking system or the class schedule. WhatsApp reminders.
What the owner answered, from her phone, in under two minutes: she approved O1, asked for a change in O2, switched D2 to 3 hours before, and tapped "Send answers". This is the block pasted to the agent:
Answers to the plan: Reminder to clients before class
O1: approve
O2: change: also notify the studio owner when someone cancels
O3: not marked
O4: not marked
D1: Email, and SMS only for those who chose it (recommended)
D2: 3 hours before
D3: Message the first on the list, two hours to confirm (recommended)
What the agent did with it: it added to O2 a message to the owner on every cancellation. Because of D2 (3 hours before) and a two-hour confirmation window in D3, it wrote that a spot freed by the reminder would reach the waitlist with only an hour left before class, and asked one question: shorten the confirmation window to one hour? That's exactly the question worth asking before the code.
Checklist
plans/template.htmlis in the project, and opens in a browser on the computer- The skill is installed in your agent (Claude Code, Cursor or Codex)
- A first plan for a real task was written in
plans/ - The file opens in the phone's browser, and the buttons respond
- The answers were pasted to the agent (or "skip")
- The agent gave a final report by O1, O2...
- At least one rule of your own was added to the skill
Appendix A: the skill (SKILL.md)
---
name: plan-page
description: Before writing code for a feature or any change bigger than a small fix, write the plan as one self-contained HTML page that the owner approves from a phone, then stop and wait for the answers. Use when asked to build a feature, change several files, or "plan first".
---
# Plan page
The owner will not read a long plan. They open one page on a phone, check the statements, pick options, and paste the answers back to you. Write that page, then stop.
## 1. Write the page (before any code)
- Read only what you need to understand the task.
- Copy `plans/template.html` to `plans/<yyyy-mm-dd>-<short-name>.html`.
- Replace only the JSON inside `<script type="application/json" id="plan">`. Do not change anything else in the file.
- Never write `</script` anywhere inside the JSON.
## 2. What goes in the JSON
- `lang`: `"he"` or `"en"`, the language the owner writes to you in. Write every text field in that language.
- `title`: up to 8 words.
- `summary`: 2-3 sentences in plain business language. What changes for the people who use it, and what stays the same. No file names, no jargon.
- `outcomes` (2-6): what the owner will have at the end. Each `statement` is one checkable sentence a non-developer can disagree with. Good: "A client gets one reminder 24 hours before class." Bad: "Reminder improvements." Ids `O1`, `O2`, ...
- Each outcome has an `example`:
- `{"kind": "mockup", "caption": "...", "html": "..."}`: a small phone-width HTML fragment with inline styles. No scripts, images, links or `url()`; the page removes them anyway.
- `{"kind": "text", "caption": "...", "text": "..."}`: the real message or text people will see.
- `{"kind": "code", "caption": "...", "code": "..."}`: only when the outcome is technical.
- `decisions` (3-5): only choices that change what gets built and that you cannot decide from the code or the request. Each has a `question`, an optional one-line `why`, 2-3 `options` (`label` + one-line `detail` with the cost or effect), and `recommended` (the index of your recommendation). Put choices about money, privacy or data first. Ids `D1`, `D2`, ...
- `risks`: 1-4 lines. `out_of_scope`: what you deliberately will not do.
- Plain short sentences. One idea per sentence. No superlatives.
## 3. Check and hand over
- Check that the JSON parses, ids are unique, and every `recommended` is a valid index.
- Tell the owner the file path and one line: "Open it on your phone, answer, press Send answers, and paste the block here. Or reply skip to follow all recommendations."
- Stop. Do not write code until the answers arrive.
## 4. Read the answers
The answers arrive as a block that starts with "Answers to the plan:" or "תשובות לתוכנית:".
- `approve` / `מאשר`: build that outcome as written.
- `change: ...` / `לשנות: ...`: adjust that outcome. If the change is large, write an updated plan page and wait again.
- `not marked` / `לא סומן`: treat as approved.
- A decision line names the chosen option. "(recommended)" / "(ההמלצה)" means the owner kept your recommendation.
- `skip` / `דלג` on its own: approve everything and follow every recommendation.
- The answers override the plan.
## 5. When you finish
Report per outcome: the id, done or not, and how you checked it (a test, a screenshot, a command). List anything you changed from the plan and why.
Appendix B: the template (plans/template.html)
<!doctype html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Plan to approve</title>
<style>
:root{--ink:#16202e;--muted:#5a6475;--brand:#0f4c81;--accent:#e8743b;--ok:#1f7a4d;--soft:#f3f6fa;--line:#dfe5ee;--card:#fff;--bg:#f7f8fb}
*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--bg);color:var(--ink);font:16px/1.6 system-ui,-apple-system,"Segoe UI",Arial,sans-serif}
main{max-width:720px;margin:0 auto;padding:16px 16px 120px}
header.top{background:var(--brand);color:#fff;border-radius:14px;padding:18px 18px 16px;margin-bottom:16px}
header.top small{opacity:.8;font-weight:600}
h1{font-size:22px;line-height:1.3;margin:4px 0 8px}
header.top p{margin:0;color:#dbe7f5}
h2{font-size:17px;margin:24px 0 10px;color:var(--brand)}
.card{background:var(--card);border:1px solid var(--line);border-radius:12px;padding:14px;margin-bottom:12px;overflow-wrap:anywhere}
.stmt{font-weight:600;margin:0 0 10px}
.id{display:inline-block;font-size:12px;font-weight:700;color:var(--brand);background:var(--soft);border-radius:6px;padding:0 6px;margin-inline-end:6px}
.ex{border:1px dashed var(--line);border-radius:10px;padding:10px;background:var(--soft);margin:0 0 10px;overflow-x:auto}
.ex .cap{display:block;font-size:12px;color:var(--muted);margin-bottom:6px}
.ex pre{margin:0;white-space:pre-wrap;direction:ltr;text-align:left;font:13px/1.5 ui-monospace,Consolas,monospace}
.seg{display:flex;gap:8px;flex-wrap:wrap}
.seg button,.opt{font:inherit;font-size:15px;border:1px solid var(--line);background:#fff;color:var(--ink);border-radius:10px;padding:9px 12px;cursor:pointer;min-height:44px}
.seg button[aria-pressed=true].ok{background:var(--ok);border-color:var(--ok);color:#fff}
.seg button[aria-pressed=true].chg{background:var(--accent);border-color:var(--accent);color:#fff}
textarea{width:100%;font:inherit;font-size:16px;border:1px solid var(--line);border-radius:10px;padding:8px 10px;margin-top:8px;min-height:64px}
textarea[hidden]{display:none}
.why{color:var(--muted);font-size:14px;margin:-4px 0 10px}
.opts{display:grid;gap:8px}
.opt{display:block;width:100%;text-align:start}
.opt[aria-pressed=true]{border-color:var(--brand);box-shadow:inset 0 0 0 2px var(--brand)}
.opt b{display:block}
.opt span{display:block;color:var(--muted);font-size:14px}
.rec,.opt span.rec{display:inline-block;font-size:12px;font-weight:700;color:#fff;background:var(--ok);border-radius:6px;padding:0 6px;margin-inline-start:6px}
ul.plain{margin:0;padding-inline-start:20px}
.bar{position:fixed;inset-inline:0;bottom:0;background:rgba(255,255,255,.96);border-top:1px solid var(--line);padding:10px 16px calc(10px + env(safe-area-inset-bottom))}
.bar .in{max-width:720px;margin:0 auto;display:flex;gap:10px;align-items:center}
.bar small{color:var(--muted);flex:1;line-height:1.3}
#send{font:inherit;font-weight:700;font-size:16px;background:var(--accent);color:#fff;border:0;border-radius:12px;padding:12px 18px;min-height:48px;cursor:pointer}
#out{display:none}
#out.show{display:block}
#out textarea{direction:auto;unicode-bidi:plaintext;min-height:180px;font-size:14px}
.status{font-weight:700;color:var(--ok);margin:6px 0 0}
</style>
</head>
<body>
<main id="app"></main>
<div class="bar"><div class="in"><small id="hint"></small><button id="send" type="button"></button></div></div>
<!-- The agent replaces only the JSON below. Everything else stays as is. -->
<script type="application/json" id="plan">
{
"lang": "en",
"title": "A short title for the task",
"summary": "Two or three sentences in business language: what will change after the work, and what won't.",
"outcomes": [
{
"id": "O1",
"statement": "A sentence you can check and disagree with, for example: the client gets a reminder a day before class.",
"example": {
"kind": "mockup",
"caption": "How it will look",
"html": "<div style=\"border:1px solid #ccc;border-radius:8px;padding:8px\">Example</div>"
}
}
],
"decisions": [
{
"id": "D1",
"question": "A question that changes what gets built",
"why": "One line: why it matters",
"options": [
{
"label": "Option A",
"detail": "What it costs and what it gives"
},
{
"label": "Option B",
"detail": "What it costs and what it gives"
}
],
"recommended": 0
}
],
"risks": [
"One risk per line"
],
"out_of_scope": [
"What is deliberately not done"
]
}
</script>
<script>
(function () {
var UI = {
he: { dir: 'rtl', kicker: 'תוכנית לאישור לפני כתיבת קוד', outcomes: 'מה יהיה בסוף', decisions: 'החלטות פתוחות', risks: 'סיכונים', scope: 'מחוץ לתוכנית', ok: 'מאשר', chg: 'לשנות', note: 'מה לשנות?', rec: 'המלצה', send: 'שלח תשובות',
hint: 'החלטה שלא בחרתם תישלח כהמלצה. רוצים לאשר הכל כמו שהוא? כתבו לסוכן: דלג', head: 'תשובות לתוכנית', approve: 'מאשר', change: 'לשנות', noAnswer: 'לא סומן', recTag: '(ההמלצה)', general: 'הערות כלליות', copied: 'הועתק. הדביקו את זה בשיחה עם הסוכן.', manual: 'סמנו את הטקסט, העתיקו והדביקו בשיחה עם הסוכן.', notes: 'הערות כלליות (לא חובה)' },
en: { dir: 'ltr', kicker: 'Plan to approve before any code', outcomes: 'What you will have', decisions: 'Open decisions', risks: 'Risks', scope: 'Out of scope', ok: 'Approve', chg: 'Change', note: 'What should change?', rec: 'Recommended', send: 'Send answers',
hint: 'A decision you skip is sent as the recommendation. Approve everything as is? Tell the agent: skip', head: 'Answers to the plan', approve: 'approve', change: 'change', noAnswer: 'not marked', recTag: '(recommended)', general: 'General notes', copied: 'Copied. Paste it into the chat with the agent.', manual: 'Select the text, copy it and paste it into the chat with the agent.', notes: 'General notes (optional)' }
};
var plan = JSON.parse(document.getElementById('plan').textContent);
var t = UI[plan.lang] || UI.he;
document.documentElement.lang = plan.lang === 'en' ? 'en' : 'he';
document.documentElement.dir = t.dir;
document.title = plan.title;
var state = { outcomes: {}, notes: {}, decisions: {} };
function el(tag, attrs, kids) {
var e = document.createElement(tag);
Object.keys(attrs || {}).forEach(function (k) { if (k === 'text') e.textContent = attrs[k]; else e.setAttribute(k, attrs[k]); });
(kids || []).forEach(function (c) { if (c) e.appendChild(c); });
return e;
}
// Mockups are the agent's own HTML: keep the markup, drop anything that can run or load
function safeHtml(html) {
var doc = new DOMParser().parseFromString('<div>' + html + '</div>', 'text/html');
doc.querySelectorAll('script,iframe,object,embed,link,meta,base,form,img,video,audio').forEach(function (n) { n.remove(); });
doc.querySelectorAll('*').forEach(function (n) {
[].slice.call(n.attributes).forEach(function (a) {
if (/^on/i.test(a.name) || /^(href|src|action|xlink:href)$/i.test(a.name) || /url\(/i.test(a.value)) n.removeAttribute(a.name);
});
});
return doc.body.firstChild;
}
function example(ex) {
if (!ex || ex.kind === 'none') return null;
var box = el('div', { class: 'ex' }, [ex.caption ? el('span', { class: 'cap', text: ex.caption }) : null]);
if (ex.kind === 'mockup') box.appendChild(safeHtml(ex.html || ''));
else if (ex.kind === 'code') box.appendChild(el('pre', { text: ex.code || '' }));
else box.appendChild(el('div', { text: ex.text || '' }));
return box;
}
function list(title, items) {
if (!items || !items.length) return [];
return [el('h2', { text: title }), el('div', { class: 'card' }, [el('ul', { class: 'plain' }, items.map(function (x) { return el('li', { text: x }); }))])];
}
var app = document.getElementById('app');
app.appendChild(el('header', { class: 'top' }, [el('small', { text: t.kicker }), el('h1', { text: plan.title }), el('p', { text: plan.summary })]));
app.appendChild(el('h2', { text: t.outcomes }));
plan.outcomes.forEach(function (o) {
var note = el('textarea', { 'aria-label': t.note + ' ' + o.id, placeholder: t.note, hidden: '' });
note.addEventListener('input', function () { state.notes[o.id] = note.value; });
var ok = el('button', { type: 'button', class: 'ok', 'aria-pressed': 'false', text: t.ok });
var chg = el('button', { type: 'button', class: 'chg', 'aria-pressed': 'false', text: t.chg });
function pick(v) {
state.outcomes[o.id] = v;
ok.setAttribute('aria-pressed', String(v === 'ok'));
chg.setAttribute('aria-pressed', String(v === 'chg'));
if (v === 'chg') { note.removeAttribute('hidden'); note.focus(); } else note.setAttribute('hidden', '');
}
ok.addEventListener('click', function () { pick('ok'); });
chg.addEventListener('click', function () { pick('chg'); });
app.appendChild(el('section', { class: 'card', id: o.id }, [
el('p', { class: 'stmt' }, [el('span', { class: 'id', text: o.id }), document.createTextNode(o.statement)]),
example(o.example),
el('div', { class: 'seg' }, [ok, chg]),
note,
]));
});
if (plan.decisions && plan.decisions.length) app.appendChild(el('h2', { text: t.decisions }));
(plan.decisions || []).forEach(function (d) {
var btns = d.options.map(function (op, i) {
var b = el('button', { type: 'button', class: 'opt', 'aria-pressed': String(i === d.recommended) }, [
el('b', { text: op.label }, [i === d.recommended ? el('span', { class: 'rec', text: t.rec }) : null]),
op.detail ? el('span', { text: op.detail }) : null,
]);
b.addEventListener('click', function () {
state.decisions[d.id] = i;
btns.forEach(function (x, j) { x.setAttribute('aria-pressed', String(j === i)); });
});
return b;
});
app.appendChild(el('section', { class: 'card', id: d.id }, [
el('p', { class: 'stmt' }, [el('span', { class: 'id', text: d.id }), document.createTextNode(d.question)]),
d.why ? el('p', { class: 'why', text: d.why }) : null,
el('div', { class: 'opts' }, btns),
]));
});
list(t.risks, plan.risks).forEach(function (n) { app.appendChild(n); });
list(t.scope, plan.out_of_scope).forEach(function (n) { app.appendChild(n); });
var general = el('textarea', { 'aria-label': t.notes, placeholder: t.notes });
app.appendChild(el('div', { class: 'card' }, [general]));
var outText = el('textarea', { 'aria-label': t.send, readonly: '' });
var status = el('p', { class: 'status', role: 'status' });
var out = el('div', { class: 'card', id: 'out' }, [outText, status]);
app.appendChild(out);
function answers() {
var lines = [t.head + ': ' + plan.title];
plan.outcomes.forEach(function (o) {
var v = state.outcomes[o.id];
var n = (state.notes[o.id] || '').trim();
lines.push(o.id + ': ' + (v === 'ok' ? t.approve : v === 'chg' ? t.change + (n ? ': ' + n.replace(/\s*\n\s*/g, ' ') : '') : t.noAnswer));
});
(plan.decisions || []).forEach(function (d) {
var i = d.id in state.decisions ? state.decisions[d.id] : d.recommended;
lines.push(d.id + ': ' + d.options[i].label + (i === d.recommended ? ' ' + t.recTag : ''));
});
var g = general.value.trim();
if (g) lines.push(t.general + ': ' + g.replace(/\s*\n\s*/g, ' '));
return lines.join('\n');
}
document.getElementById('hint').textContent = t.hint;
var send = document.getElementById('send');
send.textContent = t.send;
send.addEventListener('click', function () {
var text = answers();
outText.value = text;
out.classList.add('show');
function manual() { outText.focus(); outText.select(); status.textContent = t.manual; }
function done() { status.textContent = t.copied; }
if (navigator.clipboard && window.isSecureContext) navigator.clipboard.writeText(text).then(done, function () {
outText.select(); try { document.execCommand('copy') ? done() : manual(); } catch (e) { manual(); }
});
else { outText.select(); try { document.execCommand('copy') ? done() : manual(); } catch (e) { manual(); } }
out.scrollIntoView({ block: 'center' });
});
window.planAnswers = answers; // handy for tests
})();
</script>
</body>
</html>
Disclaimer
This content is general recommendations only, not professional, legal, accounting or tax advice. Every business and organization is different. You are responsible for checking that it fits your situation, and for checking the data, prompts and code before you use them. Outside tools, prices and terms of service change, so check them at the source.
What's next
Here you move the file to your phone and paste the answers yourself. A process can be connected where the task comes in from a message, the plan reaches your phone on its own, and your answer starts the build.
Want this running automatically in your business? aviad@gindiinnovation.com · gindiinnovation.com