Skip to content
← Back

Lesson 3 of 6

Define one useful feature with acceptance criteria

Turn one user action into a FEATURE.md brief with 4–6 checkable criteria, then review an OpenCode plan before any code changes.

Replace a wish with one sentence and one action

"Make it better" produces random output. An agent is fast and literal; without a target it will build the wrong thing at speed. You decide what done means before any edit.

Two rules keep this module finishable: one sentence (the outcome in plain language) and one action (one thing the user does, and one visible change). Reject for this module: login, payments, accounts, cloud sync, notifications, an in-app chatbot, or anything that needs a server database. Those are later work. This tracker stays in browser localStorage under task-tracker.tasks.v1.

Write criteria a stranger can pass or fail

Copy this into FEATURE.md in the project root:

# Feature: <short name>

## Outcome (one sentence)
After this feature, a user can ...

## User action (one action)
1. The user ...
2. The app ...

## Acceptance criteria
- AC1: Given ... when ... then ...
- AC2: ...
- AC3: ...
- AC4: ...

## Evidence for each criterion
- AC1: <what you will show>

## Out of scope (do not build)
- filters, accounts, sync, any API key

## Constraints
- Files: public/index.html, public/styles.css, public/app.js (no framework, no build step)
- Keep localStorage key task-tracker.tasks.v1
- No API keys, no network calls, keyboard accessible

## Definition of done
All criteria pass at the localhost URL, with no console errors.

A criterion is checkable when two people agree without discussion. Weak: looks good. Strong: a number, a visible element, or a reload state.

Worked feature: mark done and show how many are open

Use this feature for the rest of the module unless you pick an exercise alternate of the same shape.

Outcome: A user can mark a task done and immediately see how many tasks are still open.

Action: Tick a checkbox; the row shows as done; the status line updates.

Criteria

  • AC1: Every row has a checkbox whose accessible name includes the task text (for example Mark buy milk as done).
  • AC2: Done is visible without colour alone (strikethrough and/or the word Done).
  • AC3: Status reads N open of M and stays correct after toggle, add, and delete.
  • AC4: After a full reload, done states are still correct.
  • AC5: Unticking restores the task once; the row count does not change.
  • AC6: Tab reaches a checkbox, Space toggles it, focus ring stays visible.

Migration clause: existing tasks have no done field. Keep the storage key; treat missing done as false.

Give OpenCode a plan, not a vibe

In the OpenCode TUI, press Tab until Plan mode is active (lower-right indicator). The first reply must be a plan, not edits. Paste:

Feature: mark a task done and show how many are still open.
Read public/index.html, public/styles.css, public/app.js and FEATURE.md first.
Show a plan before changing anything. Do not edit files yet.
AC1–AC6 as in FEATURE.md.
Constraints: public/ files only. No framework, no network, no API keys.
Keep localStorage key task-tracker.tasks.v1; a saved task without done loads as not done.
Out of scope: filters, search, accounts, sync, any backend.
When criteria pass locally, show the diff and the exact hand checks.

Read the plan. Reply with at least one correction before Lesson 4. If the plan adds a backend, a new storage key, or a framework, send it back. You will implement in the next lesson.

Sources

How did this lesson go? Give feedback →