Skip to content

Commit 296775e

Browse files
ralyodioclaude
andauthored
feat(openprd): implement the OpenPRD standard — engine, CLI, conformance bundle (#100)
OpenPRD has existed as a document (docs/openprd.md), a front-matter schema, a template, and this repo's prd/ collection. Nothing enforced it. This adds the reference implementation. @logicsrc/openprd - parser: front-matter + the eight `##` sections + numbered requirements. `###` stays content so a long Requirements section can be organized, and headings or R#-shaped lines inside code fences are ignored - validation splits the standard's four conformance rules (filename, front-matter schema, id-matches-prefix, eight sections in order) from lint (empty section, missing priority tag, numbering gaps, duplicate R#, date order, one-sided supersession, stale index). Conformance failures are errors; --strict promotes the rest. Stable codes, file, line, hint - collection rules the per-file view cannot see: unique ids, monotonic numbering with no gaps, 0000 reserved for the template, cross-references that resolve - lifecycle enforced rather than advisory: Draft cannot jump to Final, terminal statuses do not resume, Superseded must name its replacement - deterministic index generation, so `prd index` is idempotent and CI can diff it - front-matter rewriting that leaves the body byte-identical - the optional LogicSRC task bridge the standard describes: each R# becomes one logicsrc.task, validated against logicsrc-task.schema.json before it is emitted; creator DID derived from the author email CLI: logicsrc prd init|new|list|show|validate|lint|index|status|next|tasks| export. Exit codes stable for CI (0 ok, 1 invalid, 2 usage, 3 not found). Conformance bundle: packages/schemas/fixtures/openprd/ — 6 documents that must validate and 12 that must fail, each naming the error code it must produce. Several rules depend on the filename, so every fixture records the name it is validated as. Docs: an Implementation section in docs/openprd.md (CLI, validation model, task bridge, conformance bundle), the spec added to the site's docs surface, nav and sitemap entries, and a README section. Verification: 76 new tests; full monorepo build and all 451 workspace tests pass. The suite dogfoods this repo — prd/ validates with zero errors and zero warnings, the embedded template is byte-identical to docs/openprd/0000- template.md, and all 210 requirements in PRD 0001 map to schema-valid tasks. prd/README.md is regenerated by the tool it now ships. Refs: docs/openprd.md Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 58c942c commit 296775e

45 files changed

Lines changed: 3605 additions & 5 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ apps/
1515
packages/
1616
cli logicsrc OpenSpec CLI
1717
openontology OpenOntology reference engine (entities, claims, queries, change sets)
18+
openprd OpenPRD reference implementation (numbered PRDs, lifecycle, task bridge)
1819
logicsrc-mcp @profullstack/logicsrc-mcp standards MCP server
1920
sdk SDK contract types and helpers
2021
tui terminal UI
@@ -52,6 +53,24 @@ npm --workspace @profullstack/logicsrc-mcp run build
5253
node packages/logicsrc-mcp/dist/index.js
5354
```
5455

56+
## OpenPRD
57+
58+
[OpenPRD](docs/openprd.md) is a lightweight standard for product requirements documents: a repo
59+
keeps a numbered, committed collection under `prd/`, one Markdown file each, with front-matter, a
60+
fixed set of eight sections, and a lifecycle. `@logicsrc/openprd` implements it.
61+
62+
```bash
63+
npm --workspace @logicsrc/cli run dev -- prd new "Expand the parked-domain service"
64+
npm --workspace @logicsrc/cli run dev -- prd validate ./prd --strict
65+
npm --workspace @logicsrc/cli run dev -- prd status 0001 Review
66+
npm --workspace @logicsrc/cli run dev -- prd tasks 0001 --priority P0
67+
```
68+
69+
Conformance failures (filename, front-matter, id match, the eight sections in order) are errors;
70+
lint findings are warnings that `--strict` promotes. The lifecycle is enforced — `Draft` cannot
71+
jump to `Final`, and `Superseded` must name its replacement. `prd tasks` is the optional bridge:
72+
each `R#` becomes one schema-valid `logicsrc.task`.
73+
5574
## OpenOntology
5675

5776
[LogicSRC OpenOntology](docs/openontology.md) is an open contract for durable, source-backed domain

apps/logicsrc-web/src/app/sitemap.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const STATIC_ROUTES: Array<{
1717
{ path: "/", changeFrequency: "weekly", priority: 1.0 },
1818
{ path: "/docs", changeFrequency: "weekly", priority: 0.9 },
1919
{ path: "/openontology", changeFrequency: "weekly", priority: 0.9 },
20+
{ path: "/docs/openprd", changeFrequency: "weekly", priority: 0.8 },
2021
{ path: "/openspec", changeFrequency: "weekly", priority: 0.8 },
2122
{ path: "/agent-swarm", changeFrequency: "weekly", priority: 0.8 },
2223
{ path: "/agentbyte", changeFrequency: "weekly", priority: 0.8 },

apps/logicsrc-web/src/components/site-shell.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const NAV: Array<{ href: string; label: string; external?: boolean }> = [
99
{ href: "/agentbyte", label: "AgentByte" },
1010
{ href: "/credential-sharing", label: "Credentials" },
1111
{ href: "/openontology", label: "OpenOntology" },
12+
{ href: "/docs/openprd", label: "OpenPRD" },
1213
{ href: "/#cli", label: "CLI" },
1314
{ href: "/docs", label: "Docs" },
1415
{ href: "/blog", label: "Blog" },

apps/logicsrc-web/src/lib/docs.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const DOCS_DIR = resolve(process.cwd(), "../../docs");
88
// Curated, public-facing reference docs. Internal notes (roadmap, positioning,
99
// arcade) are intentionally excluded.
1010
export const DOC_SLUGS = [
11+
"openprd",
1112
"openontology",
1213
"openontology-governance",
1314
"openontology-interoperability",

apps/logicsrc-web/src/lib/page-markup.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ export function renderPageMarkup(): string {
126126
<a href="/agentbyte">AgentByte</a>
127127
<a href="/credential-sharing">Credentials</a>
128128
<a href="/openontology">OpenOntology</a>
129+
<a href="/docs/openprd">OpenPRD</a>
129130
<a href="#cli">CLI</a>
130131
<a href="/docs">Docs</a>
131132
<a href="/blog">Blog</a>

docs/openprd.md

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ OpenPRD is a lightweight, open standard for **product requirements documents** a
44

55
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-
Tools such as the moshcode CLI consume this standard to publish PRDs into whatever repo you're working in.
7+
Tools such as the moshcode CLI consume this standard to publish PRDs into whatever repo you're working in. LogicSRC ships its own reference implementation — see [Implementation](#implementation).
88

99
## When to write one
1010

@@ -87,6 +87,54 @@ See [`0000-template.md`](./openprd/0000-template.md) for the copy-paste template
8787

8888
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.
8989

90+
## Implementation
91+
92+
`@logicsrc/openprd` is the reference implementation, exposed through the LogicSRC CLI. A PRD is
93+
still just a file: nothing below is required for a document to conform.
94+
95+
```bash
96+
logicsrc prd init # create prd/ with the template and an index
97+
logicsrc prd new "Expand the service" # next free number, filled front-matter, eight stub sections
98+
logicsrc prd list # id, title, status, tags, requirement count
99+
logicsrc prd show 0001 # front-matter, sections, and parsed requirements
100+
logicsrc prd validate --strict # conformance + lint, exit 1 on error
101+
logicsrc prd index --write # regenerate prd/README.md from what is on disk
102+
logicsrc prd status 0001 Review # lifecycle move, refusing illegal transitions
103+
logicsrc prd tasks 0001 # the optional LogicSRC task bridge
104+
```
105+
106+
Validation separates the four conformance rules below from lint. Conformance failures are errors;
107+
everything else — an empty section, a requirement with no priority tag, numbering that skips, a
108+
stale index, a one-sided supersession link — is a warning or a note, and `--strict` promotes them.
109+
Findings carry stable codes (`OP-C-SECTION-ORDER`, `OP-L-REQ-DUPLICATE`, …), the file, the line,
110+
and a remediation hint. Exit codes: `0` ok, `1` invalid, `2` usage, `3` not found.
111+
112+
The lifecycle is enforced rather than advisory: `Draft` cannot jump to `Final`, terminal statuses
113+
do not resume, and moving to `Superseded` requires naming the PRD that replaces it.
114+
115+
Requirement numbering, id uniqueness, and "no gaps" are checked across the whole collection, not
116+
just per file — a repo with `0001` and `0003` and no `0002` fails.
117+
118+
### Task bridge
119+
120+
The optional mapping described above lives in tooling:
121+
122+
```bash
123+
logicsrc prd tasks 0001 --priority P0 --format ndjson
124+
```
125+
126+
Each `R#` becomes one `logicsrc.task` document, validated against `logicsrc-task.schema.json`
127+
before it is emitted. The board defaults to `/prd/<id>`, `repo` carries over to `github_repo`, and
128+
the creator DID is derived from the first author (`anthony@profullstack.com`
129+
`anthony.profullstack`) unless `--creator` says otherwise.
130+
131+
### Conformance bundle
132+
133+
`packages/schemas/fixtures/openprd/` holds fixtures a third-party implementation can run:
134+
`conformance.json` lists documents that must validate and documents that must fail, each with the
135+
error code it must produce. Because several rules depend on the filename, each fixture records the
136+
name it must be validated as.
137+
90138
## Conformance
91139

92140
A document conforms to OpenPRD `0.2` when:

package-lock.json

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@
1212
"apps/*"
1313
],
1414
"scripts": {
15-
"build": "npm --workspace @logicsrc/schemas run build && npm --workspace @logicsrc/validators run build && npm --workspace @logicsrc/sdk run build && npm --workspace @logicsrc/agentad run build && npm --workspace @logicsrc/ans run build && npm --workspace @logicsrc/plugin-core run build && npm --workspace @logicsrc/agentstack run build && npm --workspace @logicsrc/agentswarm run build && npm --workspace @logicsrc/account-core run build && npm --workspace @logicsrc/plugin-coinpay run build && npm --workspace @logicsrc/plugin-ugig run build && npm --workspace @logicsrc/plugin-sh1pt run build && npm --workspace @logicsrc/plugin-c0mpute run build && npm --workspace @logicsrc/plugin-feed-discovery run build && npm --workspace @logicsrc/plugin-social-accounts run build && npm --workspace @logicsrc/plugin-email-accounts run build && npm --workspace @logicsrc/plugin-agentgit run build && npm --workspace @logicsrc/plugin-agentmail run build && npm --workspace @logicsrc/plugin-credential-sharing run build && npm --workspace @logicsrc/openontology run build && npm --workspace @logicsrc/tui run build && npm --workspace @logicsrc/cli run build && npm --workspace @profullstack/logicsrc-mcp run build && npm --workspace @logicsrc/commandboard-api run build && npm --workspace @logicsrc/commandboard-web run build && npm --workspace @logicsrc/web run build",
15+
"build": "npm --workspace @logicsrc/schemas run build && npm --workspace @logicsrc/validators run build && npm --workspace @logicsrc/sdk run build && npm --workspace @logicsrc/agentad run build && npm --workspace @logicsrc/ans run build && npm --workspace @logicsrc/plugin-core run build && npm --workspace @logicsrc/agentstack run build && npm --workspace @logicsrc/agentswarm run build && npm --workspace @logicsrc/account-core run build && npm --workspace @logicsrc/plugin-coinpay run build && npm --workspace @logicsrc/plugin-ugig run build && npm --workspace @logicsrc/plugin-sh1pt run build && npm --workspace @logicsrc/plugin-c0mpute run build && npm --workspace @logicsrc/plugin-feed-discovery run build && npm --workspace @logicsrc/plugin-social-accounts run build && npm --workspace @logicsrc/plugin-email-accounts run build && npm --workspace @logicsrc/plugin-agentgit run build && npm --workspace @logicsrc/plugin-agentmail run build && npm --workspace @logicsrc/plugin-credential-sharing run build && npm --workspace @logicsrc/openontology run build && npm --workspace @logicsrc/openprd run build && npm --workspace @logicsrc/tui run build && npm --workspace @logicsrc/cli run build && npm --workspace @profullstack/logicsrc-mcp run build && npm --workspace @logicsrc/commandboard-api run build && npm --workspace @logicsrc/commandboard-web run build && npm --workspace @logicsrc/web run build",
1616
"start": "npm --workspace @logicsrc/web run start",
1717
"test": "npm run test --workspaces --if-present",
1818
"check": "npm run build && npm run test",
1919
"schemas:validate": "npm --workspace @logicsrc/validators run validate:fixtures",
2020
"test:contract": "npm --workspace @logicsrc/commandboard-api run test:contract && npm --workspace @logicsrc/web run test:contract",
2121
"test:e2e": "npm --workspace @logicsrc/commandboard-web run test:e2e && npm --workspace @logicsrc/web run test:e2e",
22-
"build:cli": "npm --workspace @logicsrc/schemas run build && npm --workspace @logicsrc/validators run build && npm --workspace @logicsrc/plugin-core run build && npm --workspace @logicsrc/account-core run build && npm --workspace @logicsrc/plugin-coinpay run build && npm --workspace @logicsrc/plugin-ugig run build && npm --workspace @logicsrc/plugin-feed-discovery run build && npm --workspace @logicsrc/plugin-social-accounts run build && npm --workspace @logicsrc/plugin-email-accounts run build && npm --workspace @logicsrc/plugin-credential-sharing run build && npm --workspace @logicsrc/openontology run build && npm --workspace @logicsrc/tui run build && npm --workspace @logicsrc/cli run build"
22+
"build:cli": "npm --workspace @logicsrc/schemas run build && npm --workspace @logicsrc/validators run build && npm --workspace @logicsrc/plugin-core run build && npm --workspace @logicsrc/account-core run build && npm --workspace @logicsrc/plugin-coinpay run build && npm --workspace @logicsrc/plugin-ugig run build && npm --workspace @logicsrc/plugin-feed-discovery run build && npm --workspace @logicsrc/plugin-social-accounts run build && npm --workspace @logicsrc/plugin-email-accounts run build && npm --workspace @logicsrc/plugin-credential-sharing run build && npm --workspace @logicsrc/openontology run build && npm --workspace @logicsrc/openprd run build && npm --workspace @logicsrc/tui run build && npm --workspace @logicsrc/cli run build"
2323
},
2424
"devDependencies": {
2525
"@types/node": "^24.10.1",

packages/cli/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"dependencies": {
1717
"@logicsrc/account-core": "file:../account-core",
1818
"@logicsrc/openontology": "file:../openontology",
19+
"@logicsrc/openprd": "file:../openprd",
1920
"@logicsrc/plugin-coinpay": "file:../../plugins/coinpay",
2021
"@logicsrc/plugin-core": "file:../plugin-core",
2122
"@logicsrc/plugin-credential-sharing": "file:../../plugins/credential-sharing",

packages/cli/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import { print, type OutputFormat } from "./format.js";
2828
import { parsePositiveInteger } from "./numeric-options.js";
2929
import { exportOpenSpecSummary, importOpenSpec, writeOpenSpecChange } from "./openspec.js";
3030
import { registerOntologyCommands } from "./ontology.js";
31+
import { registerPrdCommands } from "./prd.js";
3132
import { defaultPluginRegistry } from "./registry.js";
3233

3334
process.stdout.on("error", (error: NodeJS.ErrnoException) => {
@@ -831,6 +832,7 @@ async function runYoloArcade(game: string, repo?: string) {
831832
}
832833

833834
registerOntologyCommands(program);
835+
registerPrdCommands(program);
834836

835837
program.parseAsync(process.argv).catch((error: unknown) => {
836838
console.error(error instanceof Error ? error.message : String(error));

0 commit comments

Comments
 (0)