
"Make a calculator for who owes what at a restaurant". A clear enough request, until you start digging into it. Do we split evenly, or does everyone pay for their own dishes? Is the tip already in the bill? What do we show if the total doesn't divide evenly between everyone?
Let's build the task description together with Claude Code: you explain the task and make the decisions, the agent writes them into a file, and you check what it wrote. We'll start with a short request and gradually end up with a TASK_SPEC you can actually work from.
"Just do it properly" is not a task
Picture this: you wanted a quick way to split the bill, and the agent added sign-up and a restaurant history. To store the bills it needed a server. You were counting on opening one file in the browser, and now you have to figure out how to run the thing and strip out what you didn't ask for. Each addition looks useful on its own, but the result is already far from what you had in mind.
When the work involves code, anything left unsaid can turn into real changes to files. Roughly speaking, it goes like this:
- A vague request
- The agent fills in the gaps
- Unwanted changes appear
- You sort it out and redo it
The diagram shows how a missing decision turns into extra work. The agent may ask you a clarifying question, but it's better to catch the ambiguity before any edits. The very first wording can already set the direction and the boundaries:
Still unclear:
Make a calculator for who owes what at a restaurant.
More specific:
One page: we enter the bill total and the number of people,
and see the amount for each person. We split evenly.
No accounts, no bill history, no splitting by dish.The second request doesn't answer every question yet. But it already rules out several different products you could have built from the first one. From here the agent will help you find the remaining gaps and write your decisions down.
The task in one file
A TASK_SPEC is a written record of the conditions for one task: what result you need, where the work ends and how you'll check it. It's usually saved to a Markdown file, TASK_SPEC.md, in the project folder. There's no special format or dedicated command behind the name. You can also pass the conditions in a message, but a file is easier to reread and update.
You don't have to write a TASK_SPEC by hand. It's easier to build it together with the agent and check how it wrote down your decisions. You can describe the task in plain words, answer questions and ask for the wording to be fixed. The agent maintains the file, and you check what it says.
- you describe what you want to get and talk through the unclear parts;
- the agent suggests options, you pick the one that fits;
- the agent writes the decision into the TASK_SPEC and shows the fragment it added or changed;
- you read that fragment in the file: the meaning is intact, no extra conditions crept in, and it doesn't contradict earlier entries. If something is off, ask for a fix and check again.
After each individual decision it's enough to check the lines it touched and the conditions tied to them. Before implementation, reread the whole file: entries can look right one by one and still demand incompatible things together. A message saying "I've updated the spec" doesn't yet show what actually ended up in the document.
What sets it apart from CLAUDE.md is its purpose. "All UI text in the project is in English" is a general project rule. "In this task we're adding a tip calculation" is a condition of one specific piece of work. The first belongs in CLAUDE.md, the second in the TASK_SPEC.
How big the document gets depends on the task. If you need to fix a typo on a finished page, a description like this is enough:
On the bill-splitting page, fix the button label:
"Calcualte" → "Calculate". Don't change anything else.
Check that the new label is visible and the button still calculates.That's a short TASK_SPEC, sometimes called a tiny spec. Nothing much to discuss here, really. A new calculator, on the other hand, could behave in several different ways, so two lines are no longer enough. It's worth writing down the decisions that affect the result; the number of headings on its own guarantees nothing.
Starting with the result
Let's say there's no project yet. A group of friends wants to open a page in the browser, enter the bill amount and find out how much each person pays. We'll have the agent create a draft:
Create TASK_SPEC.md for a bill-splitting page.
There's no project yet. We enter the bill amount and the number of people,
and after pressing "Calculate" we see each person's share.
The output should be an index.html that opens in a browser with nothing to install.
Write down the agreed conditions, mark anything unknown as a question.
Show me the text you wrote. Don't write the page code yet.Here's what the first fragment of the file might look like, give or take the wording:
## CONTEXT
A group at a restaurant wants to split the total bill quickly.
There's no project yet; the working folder is empty.
## DESIRED BEHAVIOR
The user enters the bill amount and the number of people.
After pressing "Calculate" they see the amount for each person.
Deliverable: an index.html page
that opens in a browser with nothing to install.Open TASK_SPEC.md in the editor and compare the entry with your request: both fields, the action and the result for each person are there. If the agent added name entry or mandatory sign-up, those are conditions nobody agreed to. Ask for them to be removed from the file and check the fix.
Now it's clear who uses the page and what they get. Along the way we've also named the artifact, that is, the concrete result of the agent's work: the page file. For a different task it could be an analysis of a bug or a plan for the changes with no code. Better to say so explicitly.
Notice that we haven't picked any JavaScript functions yet or dictated how to store the participants. Those decisions belong to the implementation. In the task description, what matters more is pinning down what a person will see: the input, the action and the result.
Where the task ends
Now let's pin down where the first version ends. We'll ask the agent to write down the agreed boundaries and show the updated block:
## SCOPE
One page: entering the amount and the number of people,
splitting the total evenly, showing each person's share.
## NON-GOALS
No accounts and no bill history: no data needs to be stored.
No splitting by dish: the first version splits evenly.
Implementation constraint: a single HTML file with the styles and script
inside, no server and no external libraries.
The page must open with a double-click.In this fragment we check more than whether the exclusions are there: the even split has to stay inside the scope, and splitting by dish has to stay outside it. If the agent mixed them up, we fix the document before any work on the page starts.
Scope describes the extent of the work. You can set it through a screen and a scenario, as we did here. Exact paths help when you know them, but you don't have to start with a list of files. If you're changing an existing project and don't know where the page you need lives, ask Claude Code to find it first without making edits and explain why it picked that particular file. Then add the path to the task description. Unknowns are fine. Made-up facts are not.
Non-goals are what you deliberately left out. "No bill history" explains the boundary better than "don't do anything extra". A short reason helps you too, since a week later you'll still see that storing data was considered and turned down.
Implementation constraints answer a different question: which approaches work for us. Accounts are an unneeded feature, while a server is a way of building the solution that we've ruled out here. In a short document you can keep these conditions in one block, as long as the constraints are clearly marked.
The boundaries have to leave room for the result. If shared accounts with a history across devices are needed later, the "one local HTML file" requirement will have to be revisited. You can't ask for a new capability and keep a restriction that makes it impossible at the same time.
The forgotten cent
So far everything looks fairly well defined. Let's test the task description before any code: a group of three, a bill of 1000. What amount do we show each person?
333.33 + 333.33 + 333.33 = 999.99One cent is missing. You could add it to the first person, to the last one, or let the user choose. "We split evenly" doesn't settle that. And this is now a decision for you, not a JavaScript question.
For our page we'll go with this rule: shares differ by at most one cent; the remainder goes out one cent at a time to the first people in the list. Then 1000 split three ways gives 333.34; 333.33; 333.33. And for 1000.01 there are two leftover cents: 333.34; 333.34; 333.33. All the money is accounted for, and the shares add up to the bill.
Now let's ask the agent to carry the chosen decision over into the document:
Add the rounding rule to the desired behavior in TASK_SPEC.md.
Show me the changed lines. Don't change any code yet.We check that an entry like this has appeared in the file:
The sum of the shares is exactly equal to the total.
Shares differ by at most 0.01.
Leftover cents go to the first participants, one each;
the page includes an explanation of this rule.Read the words "to the first participants, one each" especially carefully. If the agent wrote "the whole remainder to the first person", it has changed the decision: with two leftover cents, the first person would pay 0.02 more than everyone else. We ask for that line to be fixed and look at the file again. What we check is the meaning; the wording doesn't have to match word for word.
This is why plugging numbers into the task description pays off. We found the missing decision before the agent picked its own option and wrote code around it. So far it's cost us a few edited lines, and that's it.
Let Claude ask the questions
You won't spot every gap on your own. Hand the draft to the agent and ask it to help specifically with the task description:
Read @TASK_SPEC.md. Help me find the missing conditions.
Ask one question at a time, and suggest an answer for each.
Don't treat your suggestion as agreed until I answer.
After each agreed decision, update TASK_SPEC.md
and show me the changed fragment so I can check it.
Don't write any code yet.Below is an example of such a conversation. In your session the questions will probably be different (that's normal); what matters here is following how the answers change the document.
Claude: "Is the tip included in the bill amount or added separately? I suggest a separate percentage field, 0 by default".
You: "Separately. The percentage is calculated on the bill amount, the tip is added on top and everything is split together. Show the tip amount and the total on the page".
Claude: "If the tip comes out with a fraction of a cent, how should it be rounded? I suggest rounding to the nearest cent, with exactly half a cent rounded up".
You: "Yes. First round the tip amount, then add it to the bill. After that, split the total using our rule".
Claude: "Which values do we accept? I suggest a positive amount with a dot or a comma, a whole number of people from one up, and a whole non-negative percentage. If the input is invalid, show a hint next to the field".
You: "That works. For the amount, up to two digits after the separator, no thousands separators. If a field is empty or the value is invalid, hide the result, even if something was calculated before".
We clarified more than the tip. Now the valid input, the rounding order and the behavior on errors are all defined. Once the answers are written down, we check the updated fragment of the file:
Tip: a separate field with a whole percentage, 0 or more, initial value 0.
The tip amount is calculated from the bill and rounded to the nearest cent;
exactly half a cent is rounded up.
The rounded tip is added to the bill, then the total is split.
We show the tip amount, the total and each person's share.
If a value is empty or invalid, the result is hidden
and the relevant field shows a hint.We check the order: first the tip is rounded, then it's added to the bill, then the total is split. The same words in a different order would make a different requirement. We also ask the agent to update the scope: the tip field and the total calculation have been added to the first version. and then we check that it actually changed both blocks, not just confirmed it in the chat.
Ask the agent to write exactly that: "Tip handling is not decided yet". You can discuss the options, or explicitly leave this feature out of the first version. The agent's suggestion helps you choose, but on its own it doesn't become your requirement.
The result and how to check it
"The sum of the shares equals the total" is a requirement for the result. "Enter 1000, three people and a 0% tip; press the button; see 333.34, 333.33 and 333.33" is a check. It sets out an action and the observation you expect.
Let's ask the agent to add a few checks like that to the file now, before implementation. We'll verify the expected numbers ourselves (a calculator on your phone is plenty). Otherwise it's easy to go along with whatever came out and quietly bend the expectations to fit the finished page.
| What we enter and do | What we should see |
|---|---|
| 1000; 3 people; 0%. Press "Calculate" | total 1000.00; shares 333.34 / 333.33 / 333.33 |
| Change the bill to 1000.01 and calculate again | total 1000.01; shares 333.34 / 333.34 / 333.33 |
| 1000; 3 people; 10% | tip 100.00; total 1100.00; shares 366.67 / 366.67 / 366.66 |
| 10.05; 3 people; 10% | tip 1.01; total 11.06; shares 3.69 / 3.69 / 3.68 |
| 1000; 1 person; 0% | a single share of 1000.00 |
| After a successful calculation, clear the amount and calculate; then put the amount back and enter 0 people | no shares in either case, a hint next to the invalid field |
The 10.05 row checks the order of operations: 10% gives 1.005, which rounds to 1.01. Round at a different step and the total may come out different. To check the format, repeat it with a comma: 10,05 should give the same result. Separately, try a negative amount, a fractional number of people, a negative or fractional percentage and an empty tip field: there should be no calculation.
Every important condition has its own observation. "The page opened" doesn't yet prove the amounts are right, just as a correct link address doesn't prove the right page loaded. Check the behavior that was the whole point of the task.
Putting the TASK_SPEC together
The agent collected the decisions in the file as the discussion went on. Now let's reread it in full: are the answers reflected, do the checks match the requirements, are there any leftover old conditions? Here's what the final document for our example looks like. It rests on six pillars: context, desired behavior, scope, non-goals, verification plan and safe start. The headings help you find the right part quickly, and the content itself came out of working through the task.
# TASK_SPEC.md
## CONTEXT
A group wants to split a restaurant bill.
There's no project yet; the working folder is empty apart from TASK_SPEC.md.
## DESIRED BEHAVIOR
Deliverable: an index.html that opens with a double-click,
plus a short description of how it was checked.
The page has three fields and a "Calculate" button:
- bill amount greater than 0, up to two decimal places;
the separator is a dot or a comma, no thousands separators;
- number of people - a whole number, 1 or more;
- tip percentage - a whole number, 0 or more, initial value 0.
The tip is calculated from the bill and rounded to the nearest cent;
exactly half a cent is rounded up.
The rounded tip is added to the bill, then the total is split.
The tip, the total and the numbered shares are shown.
The shares add up to the total and differ by at most 0.01.
The remainder goes out one cent at a time to the first participants;
the page includes an explanation of this rule.
Empty or invalid value: the result is hidden,
and the invalid field shows a hint.
## SCOPE
One page: three fields, the calculation, hints and the amounts shown.
We split the total evenly, with the remainder distributed as described.
## NON-GOALS
No accounts and no bill history: we don't store data.
No splitting by dish: that's a different version of the calculator.
Constraint: styles and script inside index.html,
no server and no external libraries, so the file opens locally.
## VERIFICATION PLAN
Open index.html with a double-click. Press "Calculate" for:
- 1000 / 3 people / 0% → 333.34; 333.33; 333.33;
- 1000.01 / 3 / 0% → 333.34; 333.34; 333.33;
- 1000 / 3 / 10% → tip 100.00, total 1100.00,
shares 366.67; 366.67; 366.66;
- 10.05 / 3 / 10% → tip 1.01, total 11.06,
shares 3.69; 3.69; 3.68; entering 10,05 gives the same result;
- 1000 / 1 / 0% → a single share of 1000.00.
In each case, add up the shares and compare them with the total.
Check zero and a fraction for the number of people, a negative amount,
a negative and a fractional percentage, more than two decimal places
in the amount, and each field left empty in turn:
a hint next to the field, the result hidden, including after a calculation.
Check the share numbering and the explanation of how cents are distributed.
## SAFE START
Read the task description and look at what's in the working folder.
If there are already project files there, stop and clarify the task;
don't overwrite or delete existing files.
Questions and a plan without code first, then wait for approval.
If the implementation needs changes outside the scope,
clarify the task description before making them.
The document grew with the decisions that were actually needed. There's no step-by-step recipe for writing the JavaScript in it, but you can see what to do with the tip and how to check the cents. Your own task may need fewer details.
Here's a short cheat sheet worth running through when you put together your own task description:
| Pillar | What to ask yourself |
|---|---|
| CONTEXT | what's happening now, and why is the task needed? |
| DESIRED BEHAVIOR | what will work, and what do we get as output? |
| SCOPE | which scenario and which part of the project are we changing? |
| NON-GOALS | what did we leave out, and which constraints must hold? |
| VERIFICATION PLAN | what will we do, and what should we see? |
| SAFE START | what do we find out and agree on before any edits? |
When the conditions change
Now a small exercise for you. The user has looked at the task description and says: "A percentage is awkward. I want to enter the tip as an amount, say 100". Which parts of the TASK_SPEC will need updating? Try to name them before you read the breakdown (no peeking).
In the desired behavior, the percentage field is replaced by a tip amount: non-negative, with a dot or a comma and at most two decimal places. The initial value stays 0. The percentage formula and the rounding of the calculated tip go away: the amount entered is simply added to the bill. In the scope the calculation changes, and in the verification plan the input data and the invalid-input cases change. Splitting the total and the non-goals stay as they were.
The check "bill 1000, tip 100, three people" gives the familiar 366.67; 366.67; 366.66. But these numbers alone can't tell the new version from the old one with a 10% tip. Add a different bill: 500 plus a fixed 100, two people. Each should get 300; the old 10% would have given 275 each. That's a check that catches the change of rule.
Have the agent update the desired behavior, the scope and the checks, then show all the changed fragments. Open the file and make sure the old percentage formula is gone and the new checks cover entering an amount. Don't leave the old formula alongside a new note saying "now as an amount": the task description should give one answer. In the main example above we kept the original percentage version; here we worked through a separate change to it.
How this works with Claude Code
Once the individual changes are checked, reread the whole TASK_SPEC before starting implementation. Make sure the goal, the boundaries and the checks describe the same task. Then hand the file to the agent explicitly:
Read @TASK_SPEC.md. First check whether there are any contradictions
or conditions that still need clarifying.
Show me a short plan and a list of the files you'll create or change.
Don't change any code until the plan is approved.Now you have something to check even before implementation. If a server for storing bills shows up in the plan, send it back to be reworked: history is excluded, and the page has to open locally. If the plan looks right, give the go-ahead for implementation. Then open the resulting file and walk through the scenarios you wrote down, including invalid input after a successful calculation.
Non-goals are only written conditions; they don't technically block any changes. That's why you look at the plan and at the result, both of them. The agent's "done" message helps you understand what it did, but it doesn't replace your own reference numbers.
If you keep the TASK_SPEC in the project after the work is finished, mark the task as closed. While the work is still going, keep the decisions in the file up to date. Leave the wording and the writing to the agent, and check the decisions against the document itself: the changed fragment after each discussion, the whole file before implementation.
GO TO FULL VERSION