diff --git a/docs/openprd.md b/docs/openprd.md index efc7fd9..2f114be 100644 --- a/docs/openprd.md +++ b/docs/openprd.md @@ -1,41 +1,70 @@ # OpenPRD -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. +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. -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. +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*. -## Privacy +Tools such as the moshcode CLI consume this standard to publish PRDs into whatever repo you're working in. -**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. +## When to write one -## File layout +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. + +## Directory layout ```txt prd/ - / - prd.md # one OpenPRD document (front-matter manifest + body) + README.md # index of PRDs (generated/maintained by tooling) + 0000-template.md # the OpenPRD template — copy to start a new PRD + 0001-.md # numbered PRDs, one file each + 0002-.md ``` -- `` is a kebab-case identifier, unique within the repo, and equal to the manifest `id`. -- A repo MAY contain many PRDs; each is a self-contained directory so attachments (mockups, notes) can sit beside `prd.md`. +- PRDs are **committed to the repo** (public within that repo) — like `dips/`, not gitignored. +- One file per PRD: `prd/-.md`, where `` is the four-digit number and `` is a kebab-case summary of the title. + +## Numbering + +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. + +## Lifecycle + +```txt +Draft → Review → Accepted → Final + ↘ Rejected + ↘ Withdrawn + ↘ Superseded by NNNN +``` + +- **Draft** — author is still iterating. +- **Review** — open for discussion (typically on the PR that introduces the PRD). +- **Accepted** — requirements agreed; implementation may begin. +- **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. +- **Rejected / Withdrawn / Superseded** — kept on disk; the *why* is part of the record. + +Status lives in the front-matter and is the source of truth. ## Manifest (front-matter) -Every `prd.md` opens with a YAML front-matter block validated by +Every PRD opens with a YAML front-matter block validated by [`openprd-prd.schema.json`](../packages/schemas/schemas/openprd-prd.schema.json): ```yaml --- -openprd: "0.1" # standard version (required) -id: park-service-expansion # kebab-case slug == directory name (required) -title: Parked-domain service expansion # (required) -status: draft # draft | review | active | shipped | archived (required) -owner: did:key:… # optional DID/handle of the accountable owner -repo: moshcoder/moshcoding # optional target repo (owner/name) -created: 2026-07-12 # optional ISO date -updated: 2026-07-12 # optional ISO date -tags: [growth, monetization] # optional labels -supersedes: [old-slug] # optional ids this PRD replaces +openprd: "0.2" # standard version (required) +id: "0001" # 4-digit number == filename prefix (required) +title: Expand the parked-domain service # imperative title (required) +status: Draft # Draft|Review|Accepted|Final|Rejected|Withdrawn|Superseded (required) +authors: # at least one + - anthony@profullstack.com +repo: moshcoder/moshcoding # optional target repo (owner/name) +created: 2026-07-12 # optional ISO date +updated: 2026-07-12 # optional ISO date +discussion: # optional URL to the PR/issue/thread +implementation: # optional URL to the impl PR/tracking issue +tags: [growth] # optional labels +supersedes: # optional 4-digit id this PRD replaces +superseded-by: # optional 4-digit id that replaces this PRD --- ``` @@ -52,53 +81,17 @@ The body is Markdown with a fixed, ordered set of `##` sections. All are require 7. `## Success Metrics` — how the goals will be measured. 8. `## Risks & Open Questions` — known risks and decisions still owed. -### Minimal example - -```markdown ---- -openprd: "0.1" -id: launch-flip -title: Coming-soon → live launch flip -status: draft ---- - -## Problem -Parked domains have no one-click path from coming-soon to a live site. - -## Goals -Owners flip a domain live and notify its waitlist in a single action. - -## Non-Goals -_Building the live site itself._ - -## Users -Domain owners running parked pages on the service. - -## Requirements -- R1 [P0] A per-domain "go live" action publishes/redirects the domain. -- R2 [P0] Flipping live emails that domain's waitlist. -- R3 [P1] The action is reversible within a grace window. - -## UX Notes -One button on the domain's admin row; confirm dialog shows the waitlist size. - -## Success Metrics -Time-to-live per domain; waitlist → visit conversion after launch. - -## Risks & Open Questions -- Email deliverability on bulk launch sends. -- Should redirects preserve `?dn=` analytics? -``` +See [`0000-template.md`](./openprd/0000-template.md) for the copy-paste template. ## Relationship to LogicSRC -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. +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. ## Conformance -A document conforms to OpenPRD `0.1` when: +A document conforms to OpenPRD `0.2` when: -- it lives at `prd//prd.md`, +- it lives at `prd/-.md` with a four-digit ``, - its front-matter validates against `openprd-prd.schema.json`, -- `id` equals ``, and +- `id` equals the filename's numeric prefix, and - all eight body sections are present in order. diff --git a/docs/openprd/0000-template.md b/docs/openprd/0000-template.md new file mode 100644 index 0000000..85a4b19 --- /dev/null +++ b/docs/openprd/0000-template.md @@ -0,0 +1,50 @@ +--- +openprd: "0.2" +id: "0000" +title: "Short imperative title — start with a verb if possible" +status: Draft +authors: + - you@example.com +created: 2026-01-01 +updated: 2026-01-01 +repo: +discussion: +implementation: +tags: +supersedes: +superseded-by: +--- + +## Problem + +The user/business problem, and why it matters now. Cite the ask, the incident, +or the constraint — not aesthetics. + +## Goals + +What success looks like, as outcomes (not features). + +## Non-Goals + +Explicitly out of scope, to bound the work. + +## Users + +Who this is for; personas or segments. + +## Requirements + +- R1 [P0] First required capability. +- R2 [P1] Next capability. + +## UX Notes + +Flows, states, and constraints that shape the experience. + +## Success Metrics + +How the goals will be measured. + +## Risks & Open Questions + +- Known risk or decision still owed. diff --git a/packages/schemas/fixtures/openprd-prd.yaml b/packages/schemas/fixtures/openprd-prd.yaml index c1957a3..1bc7454 100644 --- a/packages/schemas/fixtures/openprd-prd.yaml +++ b/packages/schemas/fixtures/openprd-prd.yaml @@ -1,10 +1,12 @@ -openprd: "0.1" -id: park-service-expansion -title: Parked-domain service expansion -status: draft -owner: moshcoder.coinpay +openprd: "0.2" +id: "0001" +title: Expand the parked-domain service +status: Draft +authors: + - anthony@profullstack.com repo: moshcoder/moshcoding created: 2026-07-12 +updated: 2026-07-12 tags: - growth - monetization diff --git a/packages/schemas/schemas/openprd-prd.schema.json b/packages/schemas/schemas/openprd-prd.schema.json index 7a775fa..39f8cc6 100644 --- a/packages/schemas/schemas/openprd-prd.schema.json +++ b/packages/schemas/schemas/openprd-prd.schema.json @@ -2,7 +2,7 @@ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://schemas.logicsrc.com/openprd-prd.schema.json", "title": "OpenPRD Product Requirements Document", - "description": "The front-matter manifest of an OpenPRD document. OpenPRD is a deliberately lightweight, single-file PRD standard: one prd//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.", + "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.", "type": "object", "required": ["openprd", "id", "title", "status"], "additionalProperties": false, @@ -10,26 +10,33 @@ "openprd": { "type": "string", "pattern": "^\\d+\\.\\d+(\\.\\d+)?$", - "description": "OpenPRD standard version this document conforms to, e.g. '0.1'." + "description": "OpenPRD standard version this document conforms to, e.g. '0.2'." }, "id": { "type": "string", - "pattern": "^[a-z0-9][a-z0-9-]*$", - "description": "Kebab-case slug, unique within the repo. Also the directory name: prd//prd.md." + "pattern": "^\\d{4}$", + "description": "Four-digit zero-padded number, monotonically increasing with no gaps. Matches the filename prefix: prd/-.md." }, "title": { "type": "string", "minLength": 1, - "description": "Human-readable product/feature title." + "description": "Short imperative title — start with a verb where possible." }, "status": { "type": "string", - "enum": ["draft", "review", "active", "shipped", "archived"], - "description": "Lifecycle stage of the PRD." + "enum": ["Draft", "Review", "Accepted", "Final", "Rejected", "Withdrawn", "Superseded"], + "description": "Lifecycle stage. Draft → Review → Accepted → Final; or Rejected/Withdrawn/Superseded." + }, + "authors": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1, + "uniqueItems": true, + "description": "Author identities — email, handle, or DID." }, "owner": { "type": "string", - "description": "Optional DID or handle of the accountable owner, e.g. a LogicSRC agent or account DID." + "description": "Optional DID or handle of the accountable owner (e.g. a LogicSRC account/agent DID)." }, "repo": { "type": "string", @@ -45,6 +52,14 @@ "format": "date", "description": "ISO date (YYYY-MM-DD) of the last substantive edit." }, + "discussion": { + "type": "string", + "description": "Optional URL to the PR/issue/thread where this PRD is discussed." + }, + "implementation": { + "type": "string", + "description": "Optional URL/reference to the implementation PR or tracking issue." + }, "tags": { "type": "array", "items": { "type": "string" }, @@ -52,10 +67,14 @@ "description": "Optional freeform labels for grouping PRDs." }, "supersedes": { - "type": "array", - "items": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]*$" }, - "uniqueItems": true, - "description": "Optional ids of earlier PRDs this one replaces." + "type": "string", + "pattern": "^\\d{4}$", + "description": "Optional id of an earlier PRD this one replaces." + }, + "superseded-by": { + "type": "string", + "pattern": "^\\d{4}$", + "description": "Optional id of a later PRD that replaces this one." } } }