# Specs and Plans

Course: [Markdown](https://www.devtutorials.ai/learn/markdown) · Section: AI-Native Markdown
Source: https://www.devtutorials.ai/learn/markdown/ai-native/specs-and-plans

> Turn a vague ticket into a spec an agent can build from. Write a goal, non-goals, requirements and checkable acceptance criteria, remove vague words and open questions, and write plans, decision records and reusable prompt files.

## The Ticket That Built the Wrong Thing

The support lead writes a ticket. A coding agent picks it up and builds it. The result is a PDF export with every refund since 2021, a new date picker, and a redesigned page. Nobody asked for any of that.

```md runnable file="spec.md" expect-lint="SPC001,SPC002,SPC003" title="A ticket an agent cannot build from"
# Refund export

Make the refund export better. It should be fast and easy to use.
Support staff need the data for their reports, so add CSV, PDF etc.
```

Open the **Checks** tab. Three spec rules fire:

- **SPC001**: no goal. Better for whom? Which reports?
- **SPC003**: no non-goals. Nothing says "do not redesign the page", so the agent did.
- **SPC002**: no acceptance criteria. Nothing says what "done" looks like, so the agent decided.

A person reading this ticket would ask five questions first. An agent usually does not ask. It **guesses**, and then builds the guess carefully and confidently.

In this lesson, you will learn how to write the Markdown files an agent works from: specs, plans, decision records and prompt files.

**In simple words:** a spec is a short Markdown file that says what to build, what not to build, and how to check it is done. The agent fills every gap you leave with a guess.

## TL;DR

- A **spec** says what to build and why. It has a **goal**, **non-goals** and **acceptance criteria**.
- **Acceptance criteria** are a list of checks, one per line, that prove the work is done. Each one must be something you can test.
- Words like "fast", "easy" and "etc." cannot be checked. Replace them with numbers, examples or exact behaviour.
- A **plan** breaks the work into numbered steps, each with a check.
- A **decision record** (ADR) records one decision and why it was made.
- A **prompt file** saves a prompt you use often, as Markdown, so the whole team can reuse it.
- Answer every open question before an agent starts. `TBD` in a spec is a guess waiting to happen.

## A Real-World Example

Think about planning a trip.

"Plan a weekend trip" could lead to many different results. The destination, budget, travel dates, number of travellers, and activities are all unclear.

"Plan a two-day trip to Pondicherry for four people, with a budget of ₹20,000, including travel, accommodation, and family-friendly places" gives clear requirements.

A specification, or spec, works in the same way. It clearly describes what needs to be created, the rules it must follow, and how to check whether the final result is correct.

## What You Will Learn

In this lesson, you will learn:

1. The parts of a spec: goal, non-goals, requirements and acceptance criteria.
2. How to write acceptance criteria that can be checked.
3. Which words make a spec vague.
4. How to write a plan with numbered, checkable steps.
5. How to record a decision in an ADR.
6. How to save a prompt you reuse as a prompt file.

## Cheat Sheet

```md runnable clean file="spec.md" title="A spec an agent can build from"
# Refund export

## Goal

Support leads need last month's refunds in a spreadsheet for the monthly finance report. Today they copy them by hand, which takes about two hours.

## Non-goals

- No PDF export.
- No changes to the refunds page layout.
- No refunds older than 12 months.

## Requirements

1. Add a **Download CSV** button to the refunds page.
2. The CSV has one row per refund, with the columns `order_id`, `refund_date`, `amount_inr` and `reason`.
3. The default range is the previous calendar month.

## Acceptance criteria

- `GET /refunds/export.csv?month=2026-09` returns status 200 and a file with a header row.
- The file has exactly one row for each refund in September 2026.
- `amount_inr` is written in rupees with two decimals, such as `129.99`.
- For 5,000 refunds, the download starts in under 3 seconds.
- The refunds page looks the same as before, except for the new button.

## Open questions

None.
```

The Checks tab is clean. Every acceptance criterion is something a test, or a person, can check with a yes or a no.

## The Parts of a Spec

### Goal

The **goal** says what problem the change solves, and for whom. One or two sentences.

A goal stops the agent from solving a different problem. "Support leads need last month's refunds for the finance report" rules out a dashboard, an archive of five years, and a PDF.

### Non-Goals

The **non-goals** say what this change will **not** do. They are the most skipped part of a spec, and one of the most useful for agents.

An agent tries to be helpful. Without non-goals, "helpful" can mean redesigning the page you asked it to add one button to. One line, "No changes to the refunds page layout", prevents that.

### Requirements

The **requirements** say what to build. Number them, so you can refer to "requirement 2" in a review. Keep each one to one thing.

### Acceptance Criteria

The **acceptance criteria** say how to check that the work is done. They are a list, one check per line. Many teams turn each line into a test.

These are file-level rules for a spec in Markdown. How to discover the real goal, interview a stakeholder and write requirements in a formal style like EARS is the subject of the Intent Engineering course.

## Checkable Acceptance Criteria

### Vague Words

Some words sound like requirements but cannot be checked. Is 4 seconds "fast"? Is a button "easy to use"? Nobody can say yes or no.

```md runnable file="spec.md" expect-lint="SPC004" title="Acceptance criteria nobody can check"
# Refund export

## Goal

Support leads need last month's refunds for the finance report.

## Non-goals

- No PDF export.

## Acceptance criteria

- The export is fast.
- The CSV is easy to read.
- It handles large exports properly.
- Columns include order, date, amount, etc.
```

Open the Checks tab: **SPC004** fires on each line. Here is each one rewritten:

| Vague | Checkable |
|---|---|
| The export is fast. | For 5,000 refunds, the download starts in under 3 seconds. |
| The CSV is easy to read. | The first row is a header with the column names. |
| It handles large exports properly. | An export of 50,000 refunds completes without an error. |
| Columns include order, date, amount, etc. | The columns are exactly `order_id`, `refund_date`, `amount_inr`, `reason`. |

"etc." is the worst one. It tells the agent to invent the rest of the list.

### The Yes-or-No Test

For each criterion, ask: **could two people check this and always agree?** If one would say "yes" and the other "it depends", rewrite it with a number, an example, or the exact behaviour.

A good acceptance criterion often names the exact input and the exact output: "`GET /refunds/export.csv?month=2026-09` returns status 200." An agent can turn that into a test without asking anything.

## Open Questions

A spec that still has questions in it is not ready. An agent does not stop at `TBD`. It picks an answer.

```md runnable file="spec.md" expect-lint="SPC005" title="A spec with a question left in it"
# Refund export

## Goal

Support leads need last month's refunds for the finance report.

## Non-goals

- No PDF export.

## Acceptance criteria

- The file has one row per refund.
- Amounts are in TBD.
```

**SPC005** fires on the `TBD`. Answer it: rupees or paise? Then write the answer into the criterion. If you cannot answer it yet, keep the open question in its own `## Open questions` section and do not hand the spec to an agent until it is empty.

You do not need to write code to write a good spec. A spec is a **brief**: the same parts work for a report, an event or a campaign you hand to an AI assistant or a colleague. Try it:

```md runnable file="briefs/refund-report.md" title="A brief for a non-code task"
# Monthly refund report

## Goal

Finance needs one page on last month's refunds by the 5th of each month.

## Non-goals

- No charts.
- No customer names.

## Acceptance criteria

- The page lists the total refunded in rupees and the number of refunds.
- It names the three most common refund reasons, with a count for each.
- It is under 300 words.
```

Each criterion is a yes-or-no check, so anyone can tell whether the report is done.

## Plans

A **spec** says *what* to build. A **plan** says *in what order*, with a check after each step. For a large change, an agent often writes the plan first, and you review it before any code is written.

```md runnable file="plan.md" title="A plan with a check after each step"
# Plan: refund export

1. Add the query that lists refunds for one month.
   - Check: a unit test returns 3 refunds for the test month.
2. Add the `GET /refunds/export.csv` route.
   - Check: the route returns status 200 and a header row.
3. Add the **Download CSV** button.
   - Check: clicking it downloads `refunds-2026-09.csv`.
4. Run the full test suite and `npm run check`.
   - Check: both pass.
```

Numbered steps, because the order matters. One check per step, so the agent, and you, know each step is really done before the next starts.

For a big change, ask the agent to write `plan.md` first and stop. Read the plan, fix it, then let the agent build. Fixing a wrong step in a plan takes a minute; fixing it in finished code takes much longer.

## Decision Records

A **decision record**, often called an **ADR** (architecture decision record), records one decision: what was decided, why, and what it costs. It is short, and it is never edited later; a new ADR replaces an old one.

```md runnable file="docs/adr/0007-store-money-as-paise.md" title="A decision record"
# 7. Store money as integer paise

## Status

Accepted, 2026-03-02.

## Context

Refund totals were off by one paisa in some reports, because amounts were stored as floating-point numbers.

## Decision

Store every amount as an integer number of paise. `12999` means ₹129.99.

## Consequences

- Totals are exact.
- Every display must divide by 100.
- Old reports must be migrated once.
```

ADRs matter to agents for one reason: they explain **why** the code looks the way it does. An agent that reads this ADR will not "fix" the integer amounts back to decimals. A link from `AGENTS.md` to the ADR folder makes sure it can find them.

## Prompt Files

A **prompt file** is a prompt you use often, saved as Markdown in the repo, so anyone on the team can reuse it. It is useful for writers, designers and support staff as much as for developers. Some tools, such as VS Code, can run `.prompt.md` files directly.

```md runnable file="prompts/refund-reply.prompt.md" title="A reusable prompt file"
# Reply to a refund request

You are writing a reply to a customer who asked for a refund.

## Input

The customer's message and the order details.

## Rules

- Follow the refund policy in `docs/refunds.md`.
- Keep the reply under 120 words.
- Use the customer's first name. Do not promise a date unless the policy gives one.

## Output

A plain-text email reply, with no headings and no bullet points.
```

A prompt file has the same parts as a good spec: the task, the input, the rules and the shape of the output.

## Where This Is Used

- **Tickets and issues:** a spec in the ticket, or linked from it, before an agent starts.
- **Spec folders:** `specs/` or `docs/specs/` in the repo, one file per feature.
- **Plan review:** an agent writes `plan.md`, a person approves it, then the agent builds.
- **ADR folders:** `docs/adr/`, numbered, linked from `AGENTS.md`.
- **Team prompt libraries:** a `prompts/` folder of tested prompts for common tasks.

## Common mistakes

| Symptom | Cause | Fix |
|---|---|---|
| The agent built something nobody asked for | No goal and no non-goals | Write both before anything else |
| The agent changed things outside the task | No non-goals | Add "No changes to …" lines |
| "Done" means different things to different people | No acceptance criteria, or vague ones | Write one checkable line per criterion |
| The agent picked a value nobody agreed | `TBD` or an open question in the spec | Answer it, or keep the spec back |
| The agent undid an old decision | The reason was never written down | Write an ADR and link to the ADR folder |
| Each person writes the same prompt differently | The prompt lives in chat history | Save it as a prompt file in the repo |

## Quick Check

## Exercises

## What to Remember

- A spec has a goal, non-goals, requirements and acceptance criteria.
- Non-goals keep an agent from improving things nobody asked about.
- Each acceptance criterion is one line that two people would always agree on: yes or no.
- Replace "fast", "easy", "properly" and "etc." with numbers, examples and exact values.
- No `TBD` in a spec an agent builds from.
- A plan is numbered steps with a check after each. An ADR records one decision and why.
- Save prompts you reuse as prompt files, with the task, input, rules and output.

## Further Reading

- [Michael Nygard: Documenting architecture decisions](https://cognitect.com/blog/2011/11/15/documenting-architecture-decisions): the original ADR format.
- [GitHub Spec Kit](https://github.com/github/spec-kit): one way to keep specs and plans in a repo for AI agents.
- The **Intent Engineering** course on this site: how to find the real goal and write requirements an agent cannot misread.

Next: **LLM-Friendly Docs**, where you write an `llms.txt` file for the project docs and restructure a long page so its headings make good chunks.
