Skip to content

Commit 6f89ccf

Browse files
ralyodioclaude
andcommitted
feat(openprd): revise standard to DIP-style numbered proposals (0.2)
Reshape OpenPRD from a private single-file (prd/<slug>/prd.md, gitignored) into a published, numbered proposal collection like BIP/EIP/DIP: prd/NNNN-slug.md + 0000-template.md + a README index, committed to the repo, with a lifecycle (Draft → Review → Accepted → Final; Rejected/Withdrawn/Superseded). Tools (e.g. moshcode /prd) consume this to publish PRDs into whatever repo the user is working in. - docs/openprd.md — rewritten: numbering, lifecycle, directory layout, conformance. - docs/openprd/0000-template.md — the canonical template. - packages/schemas/schemas/openprd-prd.schema.json — 4-digit id, status enum, authors, discussion/implementation, supersedes/superseded-by. - fixture updated to 0.2. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 506c001 commit 6f89ccf

4 files changed

Lines changed: 142 additions & 78 deletions

File tree

docs/openprd.md

Lines changed: 54 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,70 @@
11
# OpenPRD
22

3-
OpenPRD is a lightweight, open standard for **product requirements documents** authored by humans or AI agents. It is maintained by Profullstack, Inc. as part of the LogicSRC open-standards surface.
3+
OpenPRD is a lightweight, open standard for **product requirements documents** authored by humans or AI agents, maintained by Profullstack, Inc. as part of the LogicSRC open-standards surface.
44

5-
Where [OpenSpec](./openspec-comparison.md) models a *change* as a multi-file bundle (proposal + design + specs + tasks + deltas), OpenPRD deliberately models a *product decision* as **one Markdown file**. It answers "what are we building and why", not "how the change is structured for implementation". The single-file shape is the point: it is the low-ceremony front door that a `prd` CLI command can produce in one step.
5+
It borrows the shape of a BIP/EIP/DIP process: a repo keeps a **numbered, committed collection** of PRDs under `prd/`, each one a single Markdown file with a fixed set of sections and a lifecycle. Where [OpenSpec](./openspec-comparison.md) models a *change* as a multi-file bundle, OpenPRD models a *product decision* as **one numbered file** you can read a year from now to recover the *why*.
66

7-
## Privacy
7+
Tools such as the moshcode CLI consume this standard to publish PRDs into whatever repo you're working in.
88

9-
**PRD documents are private by convention.** Only this standard is published. Generated PRDs live under a repo-local `prd/` directory that SHOULD be listed in `.gitignore`. Tools that write OpenPRD documents MUST NOT publish them anywhere by default.
9+
## When to write one
1010

11-
## File layout
11+
Write a PRD when a change introduces or reshapes a product capability — a new feature, surface, or user-facing behavior whose requirements deserve to be agreed *before* code lands. Small, obvious changes just get a PR. If you're unsure, write a short one; three paragraphs is fine.
12+
13+
## Directory layout
1214

1315
```txt
1416
prd/
15-
<slug>/
16-
prd.md # one OpenPRD document (front-matter manifest + body)
17+
README.md # index of PRDs (generated/maintained by tooling)
18+
0000-template.md # the OpenPRD template — copy to start a new PRD
19+
0001-<slug>.md # numbered PRDs, one file each
20+
0002-<slug>.md
1721
```
1822

19-
- `<slug>` is a kebab-case identifier, unique within the repo, and equal to the manifest `id`.
20-
- A repo MAY contain many PRDs; each is a self-contained directory so attachments (mockups, notes) can sit beside `prd.md`.
23+
- PRDs are **committed to the repo** (public within that repo) — like `dips/`, not gitignored.
24+
- One file per PRD: `prd/<id>-<slug>.md`, where `<id>` is the four-digit number and `<slug>` is a kebab-case summary of the title.
25+
26+
## Numbering
27+
28+
Four-digit, zero-padded, monotonically increasing, no gaps: `0001`, `0002`, `0003`. `0000` is reserved for the template. Assign the next free number when the PRD is created — don't reserve in advance.
29+
30+
## Lifecycle
31+
32+
```txt
33+
Draft → Review → Accepted → Final
34+
↘ Rejected
35+
↘ Withdrawn
36+
↘ Superseded by NNNN
37+
```
38+
39+
- **Draft** — author is still iterating.
40+
- **Review** — open for discussion (typically on the PR that introduces the PRD).
41+
- **Accepted** — requirements agreed; implementation may begin.
42+
- **Final** — implementation shipped; the PRD is now historical record. Don't edit a Final PRD except for typos — open a follow-up that supersedes it.
43+
- **Rejected / Withdrawn / Superseded** — kept on disk; the *why* is part of the record.
44+
45+
Status lives in the front-matter and is the source of truth.
2146

2247
## Manifest (front-matter)
2348

24-
Every `prd.md` opens with a YAML front-matter block validated by
49+
Every PRD opens with a YAML front-matter block validated by
2550
[`openprd-prd.schema.json`](../packages/schemas/schemas/openprd-prd.schema.json):
2651

2752
```yaml
2853
---
29-
openprd: "0.1" # standard version (required)
30-
id: park-service-expansion # kebab-case slug == directory name (required)
31-
title: Parked-domain service expansion # (required)
32-
status: draft # draft | review | active | shipped | archived (required)
33-
owner: did:key:… # optional DID/handle of the accountable owner
34-
repo: moshcoder/moshcoding # optional target repo (owner/name)
35-
created: 2026-07-12 # optional ISO date
36-
updated: 2026-07-12 # optional ISO date
37-
tags: [growth, monetization] # optional labels
38-
supersedes: [old-slug] # optional ids this PRD replaces
54+
openprd: "0.2" # standard version (required)
55+
id: "0001" # 4-digit number == filename prefix (required)
56+
title: Expand the parked-domain service # imperative title (required)
57+
status: Draft # Draft|Review|Accepted|Final|Rejected|Withdrawn|Superseded (required)
58+
authors: # at least one
59+
- anthony@profullstack.com
60+
repo: moshcoder/moshcoding # optional target repo (owner/name)
61+
created: 2026-07-12 # optional ISO date
62+
updated: 2026-07-12 # optional ISO date
63+
discussion: # optional URL to the PR/issue/thread
64+
implementation: # optional URL to the impl PR/tracking issue
65+
tags: [growth] # optional labels
66+
supersedes: # optional 4-digit id this PRD replaces
67+
superseded-by: # optional 4-digit id that replaces this PRD
3968
---
4069
```
4170

@@ -52,53 +81,17 @@ The body is Markdown with a fixed, ordered set of `##` sections. All are require
5281
7. `## Success Metrics` — how the goals will be measured.
5382
8. `## Risks & Open Questions` — known risks and decisions still owed.
5483

55-
### Minimal example
56-
57-
```markdown
58-
---
59-
openprd: "0.1"
60-
id: launch-flip
61-
title: Coming-soon → live launch flip
62-
status: draft
63-
---
64-
65-
## Problem
66-
Parked domains have no one-click path from coming-soon to a live site.
67-
68-
## Goals
69-
Owners flip a domain live and notify its waitlist in a single action.
70-
71-
## Non-Goals
72-
_Building the live site itself._
73-
74-
## Users
75-
Domain owners running parked pages on the service.
76-
77-
## Requirements
78-
- R1 [P0] A per-domain "go live" action publishes/redirects the domain.
79-
- R2 [P0] Flipping live emails that domain's waitlist.
80-
- R3 [P1] The action is reversible within a grace window.
81-
82-
## UX Notes
83-
One button on the domain's admin row; confirm dialog shows the waitlist size.
84-
85-
## Success Metrics
86-
Time-to-live per domain; waitlist → visit conversion after launch.
87-
88-
## Risks & Open Questions
89-
- Email deliverability on bulk launch sends.
90-
- Should redirects preserve `?dn=` analytics?
91-
```
84+
See [`0000-template.md`](./openprd/0000-template.md) for the copy-paste template.
9285

9386
## Relationship to LogicSRC
9487

95-
OpenPRD is intentionally decoupled from the rest of LogicSRC: a PRD is just a file and needs no service to exist. When coordination is wanted, a PRD's `Requirements` map cleanly onto LogicSRC `task` documents (each `R#` → one task), and the PRD `owner`/`repo` reuse LogicSRC identity and repo conventions. That bridge is optional and lives in tooling, not in this standard.
88+
OpenPRD is intentionally decoupled from the rest of LogicSRC: a PRD is just a file and needs no service to exist. When coordination is wanted, a PRD's `Requirements` map cleanly onto LogicSRC `task` documents (each `R#` → one task), and `owner`/`repo` reuse LogicSRC identity and repo conventions. That bridge is optional and lives in tooling, not in this standard.
9689

9790
## Conformance
9891

99-
A document conforms to OpenPRD `0.1` when:
92+
A document conforms to OpenPRD `0.2` when:
10093

101-
- it lives at `prd/<slug>/prd.md`,
94+
- it lives at `prd/<id>-<slug>.md` with a four-digit `<id>`,
10295
- its front-matter validates against `openprd-prd.schema.json`,
103-
- `id` equals `<slug>`, and
96+
- `id` equals the filename's numeric prefix, and
10497
- all eight body sections are present in order.

docs/openprd/0000-template.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
---
2+
openprd: "0.2"
3+
id: "0000"
4+
title: "Short imperative title — start with a verb if possible"
5+
status: Draft
6+
authors:
7+
- you@example.com
8+
created: 2026-01-01
9+
updated: 2026-01-01
10+
repo:
11+
discussion:
12+
implementation:
13+
tags:
14+
supersedes:
15+
superseded-by:
16+
---
17+
18+
## Problem
19+
20+
The user/business problem, and why it matters now. Cite the ask, the incident,
21+
or the constraint — not aesthetics.
22+
23+
## Goals
24+
25+
What success looks like, as outcomes (not features).
26+
27+
## Non-Goals
28+
29+
Explicitly out of scope, to bound the work.
30+
31+
## Users
32+
33+
Who this is for; personas or segments.
34+
35+
## Requirements
36+
37+
- R1 [P0] First required capability.
38+
- R2 [P1] Next capability.
39+
40+
## UX Notes
41+
42+
Flows, states, and constraints that shape the experience.
43+
44+
## Success Metrics
45+
46+
How the goals will be measured.
47+
48+
## Risks & Open Questions
49+
50+
- Known risk or decision still owed.
Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
openprd: "0.1"
2-
id: park-service-expansion
3-
title: Parked-domain service expansion
4-
status: draft
5-
owner: moshcoder.coinpay
1+
openprd: "0.2"
2+
id: "0001"
3+
title: Expand the parked-domain service
4+
status: Draft
5+
authors:
6+
- anthony@profullstack.com
67
repo: moshcoder/moshcoding
78
created: 2026-07-12
9+
updated: 2026-07-12
810
tags:
911
- growth
1012
- monetization

packages/schemas/schemas/openprd-prd.schema.json

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,41 @@
22
"$schema": "https://json-schema.org/draft/2020-12/schema",
33
"$id": "https://schemas.logicsrc.com/openprd-prd.schema.json",
44
"title": "OpenPRD Product Requirements Document",
5-
"description": "The front-matter manifest of an OpenPRD document. OpenPRD is a deliberately lightweight, single-file PRD standard: one prd/<slug>/prd.md per product decision, authored by a human or an AI agent. The document body is Markdown with a fixed set of sections; this schema governs only the YAML front-matter. PRD documents are private by convention (gitignored) — only the OpenPRD standard itself is published.",
5+
"description": "The front-matter manifest of an OpenPRD document. OpenPRD is a lightweight, DIP-style proposal standard: a repo publishes a numbered collection of PRDs under prd/ (prd/NNNN-slug.md), with a 0000-template.md and a README index, committed to the repo like a BIP/EIP/DIP process. This schema governs the YAML front-matter; the body is Markdown with a fixed set of sections.",
66
"type": "object",
77
"required": ["openprd", "id", "title", "status"],
88
"additionalProperties": false,
99
"properties": {
1010
"openprd": {
1111
"type": "string",
1212
"pattern": "^\\d+\\.\\d+(\\.\\d+)?$",
13-
"description": "OpenPRD standard version this document conforms to, e.g. '0.1'."
13+
"description": "OpenPRD standard version this document conforms to, e.g. '0.2'."
1414
},
1515
"id": {
1616
"type": "string",
17-
"pattern": "^[a-z0-9][a-z0-9-]*$",
18-
"description": "Kebab-case slug, unique within the repo. Also the directory name: prd/<id>/prd.md."
17+
"pattern": "^\\d{4}$",
18+
"description": "Four-digit zero-padded number, monotonically increasing with no gaps. Matches the filename prefix: prd/<id>-<slug>.md."
1919
},
2020
"title": {
2121
"type": "string",
2222
"minLength": 1,
23-
"description": "Human-readable product/feature title."
23+
"description": "Short imperative title — start with a verb where possible."
2424
},
2525
"status": {
2626
"type": "string",
27-
"enum": ["draft", "review", "active", "shipped", "archived"],
28-
"description": "Lifecycle stage of the PRD."
27+
"enum": ["Draft", "Review", "Accepted", "Final", "Rejected", "Withdrawn", "Superseded"],
28+
"description": "Lifecycle stage. Draft → Review → Accepted → Final; or Rejected/Withdrawn/Superseded."
29+
},
30+
"authors": {
31+
"type": "array",
32+
"items": { "type": "string" },
33+
"minItems": 1,
34+
"uniqueItems": true,
35+
"description": "Author identities — email, handle, or DID."
2936
},
3037
"owner": {
3138
"type": "string",
32-
"description": "Optional DID or handle of the accountable owner, e.g. a LogicSRC agent or account DID."
39+
"description": "Optional DID or handle of the accountable owner (e.g. a LogicSRC account/agent DID)."
3340
},
3441
"repo": {
3542
"type": "string",
@@ -45,17 +52,29 @@
4552
"format": "date",
4653
"description": "ISO date (YYYY-MM-DD) of the last substantive edit."
4754
},
55+
"discussion": {
56+
"type": "string",
57+
"description": "Optional URL to the PR/issue/thread where this PRD is discussed."
58+
},
59+
"implementation": {
60+
"type": "string",
61+
"description": "Optional URL/reference to the implementation PR or tracking issue."
62+
},
4863
"tags": {
4964
"type": "array",
5065
"items": { "type": "string" },
5166
"uniqueItems": true,
5267
"description": "Optional freeform labels for grouping PRDs."
5368
},
5469
"supersedes": {
55-
"type": "array",
56-
"items": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]*$" },
57-
"uniqueItems": true,
58-
"description": "Optional ids of earlier PRDs this one replaces."
70+
"type": "string",
71+
"pattern": "^\\d{4}$",
72+
"description": "Optional id of an earlier PRD this one replaces."
73+
},
74+
"superseded-by": {
75+
"type": "string",
76+
"pattern": "^\\d{4}$",
77+
"description": "Optional id of a later PRD that replaces this one."
5978
}
6079
}
6180
}

0 commit comments

Comments
 (0)