# PRD template in Markdown for AI coding

Canonical: https://specscore.md/articles/feature-spec-template/

Last updated: 5 November 2026

A product requirements document (PRD) is the prose that states the problem and the scope before the work is split into tasks. A [feature specification](https://specscore.md/feature-specification) is SpecScore’s file for one product capability: what it does, why it exists, and how it behaves. Markdown is the plain-text format of that file. [Spec-driven development](https://specscore.md/spec-driven-development/) (SDD) is the practice of writing the specification before the code and treating the specification as the source of truth. In [SpecScore](https://specscore.md/), a requirement (REQ) is a named rule inside a feature, an [acceptance criterion](https://specscore.md/acceptance-criteria-specification) (AC) is an optional abstract condition that points at one or more of those rules, and a scenario is a concrete example written as Given, When, and Then steps. A [plan](https://specscore.md/plan-specification) is the document that splits the feature into tasks, and a [task](https://specscore.md/task-specification) is one unit of work a person or an agent can finish. [Continuous integration](https://specscore.md/validators/) (CI) is an automatic check on every proposed change. The check is a [command-line interface](https://specscore.md/cli/) (CLI) command, `specscore spec lint`, from the CLI in [specscore/specscore-cli](https://github.com/specscore/specscore-cli). [Easy Approach to Requirements Syntax](https://specscore.md/articles/ears-requirements/) (EARS) is a sentence pattern a requirement may use. Claude Code is the AI coding agent the [CLI Skills](https://specscore.md/ai/cli-skills/) plugin on this site is written for. This feature spec template is that feature file, plus the plan and the task that point back at it.

## What this feature spec template is

A PRD is often one prose file a person reads. SpecScore keeps the same brief as files a linter can check. The [feature specification](https://specscore.md/feature-specification) calls a feature the atomic unit of product specification: a directory under `spec/features/` whose `README.md` is the single source of truth for what the feature does. The [plan specification](https://specscore.md/plan-specification) calls a plan the document that decomposes that feature into tasks. A scenario, in the [scenario specification](https://github.com/specscore/specscore/blob/main/spec/features/scenario/README.md), is a concrete Given/When/Then file in the feature’s `_tests/` directory. The [acceptance criteria specification](https://specscore.md/acceptance-criteria-specification) keeps the criterion abstract: it says what must be true, and the scenario says how to prove it.

The checkout file below is the template filled in. Together with the features index, a spec README, and `specscore.yaml`, `specscore spec lint` accepted it with 0 violations. That check was run on 2 November 2026 with specscore 0.55.1 and with 0.39.1, the tag [dogfood.yml](https://github.com/specscore/specscore/blob/main/.github/workflows/dogfood.yml) installs. The Studio toolbar line in the feature file is the line feature READMEs in [specscore/specscore](https://github.com/specscore/specscore) carry. The required-sections table in the feature specification does not list it.

## The feature README

The feature specification’s required-sections table says every feature README has a title `# Feature: {Title}`, a `**Status:**` line immediately after the title, a Summary, a Problem, a Behavior section, an Acceptance Criteria section, an Open Questions section, and an adherence footer. The status value is one of `Draft`, `In Review`, `Approved`, `Implementing`, `Stable`, `Amending`, `Rejected`, or `Deprecated`. A Contents section is required only when the feature has child directories. `**Source Ideas:**` is optional. The checked file sets it to `—`.

Open Questions is never omitted. When there are none, the section says `None at this time.` Acceptance Criteria is never omitted either. When no criteria are defined, that section says `Not defined yet.` and Open Questions must then include `Acceptance criteria not yet defined for this feature.` The footer is the last line, and its URL is `https://specscore.md/feature-specification`.

The [artifact-frontmatter convention](https://github.com/specscore/specscore/blob/main/spec/features/artifact-frontmatter-convention/README.md) says every artifact carries a `format:` key in YAML frontmatter, and a status-bearing artifact also carries `status:` mirroring the body `**Status:**` token. The same feature says the enforcing lint rules ship behind a grace period. The checked file includes both keys. This page does not claim that the v0.39.1 pin rejects a file that omits them.

### Feature README that specscore spec lint accepted (2 November 2026)

```markdown
---
format: https://specscore.md/feature-specification
status: Draft
---

# Feature: Checkout validation

> [SpecScore.**Studio**](https://specscore.studio): | [Explore](https://specscore.studio/app/github.com/example/checkout/spec/features/checkout?op=explore) | [Edit](https://specscore.studio/app/github.com/example/checkout/spec/features/checkout?op=edit) | [Ask question](https://specscore.studio/app/github.com/example/checkout/spec/features/checkout?op=ask) | [Request change](https://specscore.studio/app/github.com/example/checkout/spec/features/checkout?op=request-change) |

**Status:** Draft
**Source Ideas:** —

## Summary

The checkout form shows a validation error next to a field when the shopper submits invalid data, and it rejects an email that is not a valid address.

## Problem

A vague sentence such as "the form should handle bad input" does not say which event causes which response. Checkout needs those obligations written so a reviewer and a linter can point at them.

## Behavior

### Field validation

The checkout system checks the form when the shopper submits it.

#### REQ: show-field-error

When a shopper submits the checkout form with invalid data, the checkout system MUST show a validation error next to the invalid field.

#### REQ: reject-invalid-email

If the submitted email is not a valid address, then the checkout system MUST reject the form.

## Acceptance Criteria

### AC: invalid-submission

**Requirements:** checkout#req:show-field-error, checkout#req:reject-invalid-email

Submitting the checkout form with invalid data shows a validation error next to the invalid field, and an email that is not a valid address is rejected.

## Open Questions

None at this time.

---
*This document follows the https://specscore.md/feature-specification*
```

### Features index from the same lint run

```markdown
---
format: https://specscore.md/features-index-specification
---

# Features

| Feature | Status | Description |
|---|---|---|
| [Checkout validation](checkout/README.md) | Draft | The checkout form shows a validation error next to a field when the shopper submits invalid data, and it rejects an email that is not a valid address. |

## Open Questions

None at this time.

---
*This document follows the https://specscore.md/features-index-specification*
```

### Spec README from the same lint run

```markdown
# Checkout specification

## Open Questions

None at this time.
```

### specscore.yaml from the same lint run

```yaml
# SpecScore Repo Config Schema: https://specscore.md/repo-config

project:
  title: Checkout sample
  host: github.com
  org: example
  repo: checkout
```

The feature’s identifier is its directory path relative to `spec/features/`. The index link `checkout/README.md` means the file lives at `spec/features/checkout/README.md`, so the feature id used by requirements and criteria is `checkout`. The index lists every top-level feature. A child directory that is not listed is a violation of `index-entries`, which [lint specs in CI](https://specscore.md/articles/lint-specs-in-ci/) describes. The spec README in that tree has one section, Open Questions, and it says `None at this time.` The config file is what the CLI searches upward for. Without `specscore.yaml` the command exits 3 and names `specscore init`.

## REQ ids, acceptance criteria, and scenarios

The [requirement specification](https://github.com/specscore/specscore/blob/main/spec/features/requirement/README.md) puts each rule under a topic heading inside `## Behavior`. The heading is `#### REQ: {slug}`, with one space after the colon. The slug uses lowercase letters, numbers, and hyphens. The canonical id is `{feature-path}#req:{slug}`. In the checkout file that is `checkout#req:show-field-error` and `checkout#req:reject-invalid-email`. A requirement states one obligation. The specification says requirements SHOULD use the RFC 2119 keywords MUST, MUST NOT, SHOULD, SHOULD NOT, and MAY. A `REQ:` heading is not valid outside `## Behavior`. An EARS sentence can be that prose. The linter does not score the English. The patterns are in [EARS requirements syntax](https://specscore.md/articles/ears-requirements/).

### Acceptance criterion

The [acceptance criteria specification](https://specscore.md/acceptance-criteria-specification) says each criterion is a `### AC: {slug}` heading inside `## Acceptance Criteria`, then a `**Requirements:**` line listing `{feature-id}#req:{slug}` values, then an abstract statement of what must be true. Criteria are optional. The specification says to add one when bundling two or more related requirements adds clarity. The checkout file bundles both rules into `checkout#ac:invalid-submission`. The statement does not contain Given, When, or Then. [How to write acceptance criteria](https://specscore.md/articles/acceptance-criteria/) is the writing guide. Rule `ac-heading-format` ([ac_heading.go](https://github.com/specscore/specscore-cli/blob/v0.55.1/pkg/lint/ac_heading.go) at CLI tag v0.55.1) checks that the heading is `### AC: <id>` with a kebab-case id. The [lint article](https://specscore.md/articles/lint-specs-in-ci/) records that this rule does not require the `**Requirements:**` line and does not score words. The acceptance criteria specification still requires that line.

### Scenario

The [scenario specification](https://github.com/specscore/specscore/blob/main/spec/features/scenario/README.md) puts a scenario in `_tests/`, which is not a sub-feature and is excluded from the feature index. The file starts with `# Scenario: {Title}`, a `**Validates:**` line pointing at a requirement or a criterion, and a `## Steps` section whose keywords are uppercase GIVEN, WHEN, THEN, and AND. Every `_tests/` directory must contain a README with a scenario index. The sample below is that file shape. It was not part of the 2 November lint run. `specscore spec lint` does not check scenario step keywords. `specscore rehearse` runs scenario files. [Rehearse](https://specscore.md/rehearse) is that runner. The dogfood workflow runs the linter and does not call rehearse.

### Scenario file shape from the scenario specification

```markdown
# Scenario: Reject an invalid email

**Validates:** [checkout#ac:invalid-email-rejected](../README.md#ac-invalid-email-rejected)

## Steps

GIVEN the shopper is on the checkout form
WHEN the shopper submits the email "not-an-email"
THEN the page shows "Enter a valid email address" beside the email field
AND the order is not placed
```

Read the three layers in order. The requirement says the rule. The acceptance criterion says what must be true for the rules it names. The scenario gives one concrete flow. An agent that only sees the PRD prose has to invent that split. The template already has it.

## Plans and tasks

A plan README lives at `spec/plans/{plan-slug}/README.md`. The [plan specification](https://specscore.md/plan-specification) requires the title `# Plan: {Title}` and the header fields Status, exactly one source line, Date, Owner, and Supersedes. A feature-sourced plan uses `**Source Feature:**` plus the feature slug, here `checkout`. The other legal source lines are `**Source:** idea:{slug}` and `**Source:** none`. Required sections are Summary, Approach, Tasks, and Open Questions. Inside the plan, each task is a `### Task N:` heading with a `**Verifies:**` line of the form `feature-slug#ac:ac-slug`. Rule `P-001` in [plan_rules.go](https://github.com/specscore/specscore-cli/blob/v0.55.1/pkg/lint/plan_rules.go) reports an acceptance-criterion heading that no task covers and that is not listed under `## Deferred AC Coverage`. Rule `P-002` reports a `**Verifies:**` value that does not resolve to one of those headings. Idea-sourced plans and plans with `**Source:** none` are exempt from `P-001`.

The plan below follows that published shape for the checkout feature, including `format:` and `status:` frontmatter. It was not in the 2 November lint run. A feature that a plan touches must include a `## Plans` table with columns Plan, Status, Author, and Approved. The checked feature file has no Plans section because that tree has no plan.

The [task specification](https://specscore.md/task-specification) also defines a task as its own directory and `README.md` under the plan. The title is `# Task: {Title}`. Required fields are `**Status:**`, `**Depends on:**` (the literal `none` when there is no dependency), and `**Model:**` (`small`, `medium`, `large`, or `inherit`). A directory that contains child task directories is a plan, not a task. The task file below uses those fields for the first checkout task. It was not in the 2 November lint run. The footer URL for a task document is `https://specscore.md/task-specification`.

### Plan shape from the plan specification, filled in for checkout

```markdown
---
format: https://specscore.md/plan-specification
status: Draft
---

# Plan: Show checkout validation errors

**Status:** Draft
**Source Feature:** checkout
**Date:** 2026-11-05
**Owner:** @example
**Supersedes:** —

## Summary

This plan decomposes the checkout feature into the work that shows a field error and rejects an email that is not a valid address.

## Approach

Both tasks verify the same acceptance criterion, which bundles the two requirements. Nothing is deferred, so this plan has no Deferred AC Coverage section.

## Tasks

### Task 1: Show a validation error beside the invalid field

**Verifies:** checkout#ac:invalid-submission

When the shopper submits the checkout form with invalid data, show a validation error next to the invalid field.

### Task 2: Reject an email that is not a valid address

**Verifies:** checkout#ac:invalid-submission

If the submitted email is not a valid address, reject the form.

## Open Questions

None at this time.

---
*This document follows the https://specscore.md/plan-specification*
```

### Task document shape from the task specification

```markdown
---
format: https://specscore.md/task-specification
status: queued
---

# Task: Show a validation error beside the invalid field

**Status:** queued
**Depends on:** none
**Model:** medium

## Acceptance Criteria

- Submitting the checkout form with invalid data shows a validation error next to the invalid field.

## Open Questions

None at this time.

---
*This document follows the https://specscore.md/task-specification*
```

The feature file answers what the checkout form must do. The plan answers how that work is split, and each inline task names the criterion it verifies. The task document is the leaf a person or an agent picks up. Keep the criterion id stable. `checkout#ac:invalid-submission` is the string both the feature and the plan use.

## Lint the template in CI

`specscore spec lint` validates the spec tree for structural convention violations. A clean run prints `0 violations found` and exits 0. A run that finds violations prints one line per finding and exits 1. That exit code fails a CI job. Invalid arguments exit 2. A missing `specscore.yaml` exits 3. [dogfood.yml](https://github.com/specscore/specscore/blob/main/.github/workflows/dogfood.yml) installs the CLI with `SPECSCORE_VERSION` set to `v0.39.1` and then runs `specscore spec lint` on pull requests and on pushes to main. The workflow excerpt, the failure report, and the rule catalog are in [lint specs in CI](https://specscore.md/articles/lint-specs-in-ci/).

The format licence is [CC BY 4.0](https://github.com/specscore/specscore/blob/main/LICENSE) in [specscore/specscore](https://github.com/specscore/specscore). The CLI licence is [Apache-2.0](https://github.com/specscore/specscore-cli/blob/main/LICENSE) in [specscore/specscore-cli](https://github.com/specscore/specscore-cli).

Other spec-driven tools publish different checks. The sentences below use only what those projects’ own pages say. The [tools roundup](https://specscore.md/spec-driven-development/tools/) records the same pages as read on 30 October 2026, except the Spec Kit documentation home, which prints 28 September 2026.

[OpenSpec](https://github.com/Fission-AI/OpenSpec) documents `openspec validate` in its [CLI reference](https://openspec.dev/docs/cli). That command checks OpenSpec’s change and spec structure and exits non-zero when validation fails. It does not check a SpecScore `### AC:` heading or a SpecScore index.

The [Task Master](https://github.com/eyaltoledano/claude-task-master) README describes parsing a PRD into tasks with `task-master parse-prd`. It does not describe a linter for that PRD. A PRD can still be the input you rewrite into the feature file on this page. `specscore spec lint` is what then checks the feature file.

[GitHub Spec Kit](https://github.github.io/spec-kit/) describes an agent workflow whose phases write Markdown artifacts. That documentation home does not describe a command that lints a SpecScore feature README in CI. The comparison of those tools is the [tools roundup](https://specscore.md/spec-driven-development/tools/).

## A spec template Claude Code can read

The files are Markdown, so an agent that can read a repository can read the template. Claude Code is the agent the [CLI Skills](https://specscore.md/ai/cli-skills/) page targets. That page documents `ai-plugin-specscore`, a thin Claude Code plugin that wraps the CLI. The plugin repository is [specscore/ai-plugin-specscore](https://github.com/specscore/ai-plugin-specscore). The page says the plugin surfaces `specscore spec lint`, `specscore feature`, `specscore task`, and `specscore feature change-status` as plugin commands. The install lines on that page are `/plugin marketplace add specscore/ai-marketplace` and `/plugin install cli-skills@specscore`.

The same page documents `specscore agent setup <agent-name>` for `claude`, `copilot`, `cursor`, `codex`, `antigravity.google`, `pi.dev`, or `opencode`, run inside a SpecScore-managed project. [SpecStudio Skills](https://specscore.md/ai/specstudio-skills/) is the guided workflow (`/ideate`, `/specify`, `/plan`, `/implement`) and is also a Claude Code plugin. The template on this page is the file those commands lint. The plugin does not replace the feature README.

## FAQ

### What is a PRD template in Markdown?

It is a product requirements document written as Markdown files with a fixed shape. In SpecScore that shape is a feature README: title, status, summary, problem, behavior with `#### REQ:` rules, acceptance criteria, and open questions. The checkout file on this page is one that `specscore spec lint` accepted.

### Where do REQ ids go in a feature spec template?

Under a topic heading inside `## Behavior`, as `#### REQ: {slug}`. The id is `{feature-path}#req:{slug}`. Acceptance criteria list those ids on `**Requirements:**`. A plan task lists the criterion id on `**Verifies:**`.

### What is the difference between an acceptance criterion and a scenario?

An acceptance criterion is an abstract condition. A scenario is a concrete Given/When/Then flow in `_tests/`. The [acceptance criteria specification](https://specscore.md/acceptance-criteria-specification) says the criterion must not prescribe the steps. The scenario file does.

### Does the linter grade the PRD prose?

No. `specscore spec lint` checks structure: headings, required sections, index rows, and references such as `P-001` and `P-002`. It does not decide whether the product is a good idea. [Lint specs in CI](https://specscore.md/articles/lint-specs-in-ci/) is the longer account of that command.

### Can Claude Code use this spec template?

Yes. The template is Markdown in the repository. The [CLI Skills](https://specscore.md/ai/cli-skills/) plugin surfaces `specscore spec lint` and the feature and task commands inside Claude Code. `specscore agent setup claude` writes an instruction file for that agent. The plugin does not invent a different template.

### Does a plan replace the feature spec?

No. The feature README is the source of the requirements and the acceptance criteria. The plan decomposes that feature into tasks, and each task points back with `**Verifies:**`. The [plan specification](https://specscore.md/plan-specification) and the [task specification](https://specscore.md/task-specification) are the two documents for that split.

## Sources

The checkout feature, features index, spec README, and specscore.yaml were accepted by specscore spec lint on 2 November 2026 with specscore 0.55.1 and with 0.39.1. The plan and task samples follow the published specifications and were not part of that run. Competitor pages are the ones linked below; the tools roundup records them as read on 30 October 2026, except the Spec Kit documentation home, which prints 28 September 2026.

- [Feature specification](https://specscore.md/feature-specification)
- [specscore/specscore — feature specification](https://github.com/specscore/specscore/blob/main/spec/features/feature/README.md)
- [specscore/specscore — requirement specification](https://github.com/specscore/specscore/blob/main/spec/features/requirement/README.md)
- [Acceptance criteria specification](https://specscore.md/acceptance-criteria-specification)
- [specscore/specscore — acceptance criteria specification](https://github.com/specscore/specscore/blob/main/spec/features/acceptance-criteria/README.md)
- [specscore/specscore — scenario specification](https://github.com/specscore/specscore/blob/main/spec/features/scenario/README.md)
- [Plan specification](https://specscore.md/plan-specification)
- [specscore/specscore — plan specification](https://github.com/specscore/specscore/blob/main/spec/features/plan/README.md)
- [Task specification](https://specscore.md/task-specification)
- [specscore/specscore — task specification](https://github.com/specscore/specscore/blob/main/spec/features/task/README.md)
- [specscore/specscore — artifact frontmatter convention](https://github.com/specscore/specscore/blob/main/spec/features/artifact-frontmatter-convention/README.md)
- [specscore/specscore](https://github.com/specscore/specscore)
- [specscore/specscore — CC BY 4.0 licence](https://github.com/specscore/specscore/blob/main/LICENSE)
- [specscore/specscore-cli](https://github.com/specscore/specscore-cli)
- [specscore-cli — Apache-2.0 licence](https://github.com/specscore/specscore-cli/blob/main/LICENSE)
- [specscore/specscore — dogfood.yml (CLI v0.39.1)](https://github.com/specscore/specscore/blob/main/.github/workflows/dogfood.yml)
- [specscore-cli v0.55.1 — ac-heading-format](https://github.com/specscore/specscore-cli/blob/v0.55.1/pkg/lint/ac_heading.go)
- [specscore-cli v0.55.1 — plan rules P-001 and P-002](https://github.com/specscore/specscore-cli/blob/v0.55.1/pkg/lint/plan_rules.go)
- [Lint specs in CI with a spec linter](https://specscore.md/articles/lint-specs-in-ci/)
- [How to write acceptance criteria AI agents can verify](https://specscore.md/articles/acceptance-criteria/)
- [EARS requirements syntax explained, with examples](https://specscore.md/articles/ears-requirements/)
- [CLI Skills — SpecScore CLI inside Claude Code](https://specscore.md/ai/cli-skills/)
- [SpecStudio Skills](https://specscore.md/ai/specstudio-skills/)
- [specscore/ai-plugin-specscore](https://github.com/specscore/ai-plugin-specscore)
- [What SpecScore validates](https://specscore.md/validators/)
- [Rehearse](https://specscore.md/rehearse)
- [OpenSpec CLI reference — openspec validate](https://openspec.dev/docs/cli)
- [Fission-AI/OpenSpec](https://github.com/Fission-AI/OpenSpec)
- [eyaltoledano/claude-task-master](https://github.com/eyaltoledano/claude-task-master)
- [GitHub Spec Kit documentation (page date 28 September 2026)](https://github.github.io/spec-kit/)
- [Spec-driven development tools](https://specscore.md/spec-driven-development/tools/)

## Related

- [Spec-driven development with Claude Code and Cursor](https://specscore.md/articles/claude-code-specs/)
- [Feature specification](https://specscore.md/feature-specification)
- [Acceptance criteria specification](https://specscore.md/acceptance-criteria-specification)
- [Plan specification](https://specscore.md/plan-specification)
- [Task specification](https://specscore.md/task-specification)
- [How to write acceptance criteria AI agents can verify](https://specscore.md/articles/acceptance-criteria/)
- [EARS requirements syntax explained, with examples](https://specscore.md/articles/ears-requirements/)
- [Lint specs in CI with a spec linter](https://specscore.md/articles/lint-specs-in-ci/)
- [Spec-driven development](https://specscore.md/spec-driven-development/)
- [Spec-driven development tools](https://specscore.md/spec-driven-development/tools/)
- [CLI Skills for Claude Code](https://specscore.md/ai/cli-skills/)
- [CLI](https://specscore.md/cli/)
