Add Tech Stack and Monetization sections to OpenPRD (0.3) (#144)
Some checks are pending
CI / build (push) Waiting to run
test / test (push) Waiting to run

OpenPRD 0.2 fixed eight body sections, none of which asked what the thing is
built on or how it earns. The stack got chosen in the first implementation PR
instead of at review, and a PRD could be filled out completely without anyone
writing down who pays. PRD 0006 had already grown a hand-rolled
`## Business model` section, which is the gap showing.

0.3 adds two required sections between `UX Notes` and `Success Metrics`:

  - Tech Stack — languages, frameworks, datastores, third-party services, and
    anything the work must not depend on. It makes the requirements costable.
  - Monetization — the revenue model: who pays, for what, how much, and when.
    `_None._` stays a valid answer, but it now has to be said out loud.

Adding required sections would normally invalidate every document already
written, so a document is now held to the section list its own `openprd:` key
fixes. A 0.2 document keeps conforming with eight sections, forever; a 0.3
document needs ten. Adoption is per document, and `logicsrc prd validate
--expect-version 0.3` (new flag, wiring up the validator option that already
existed) reports the stragglers as OP-L-VERSION.

The front-matter schema is untouched — both additions are body sections.

Conformance bundle proves both directions: invalid/missing-monetization.md
fails with OP-C-SECTION-MISSING, and valid/legacy-0-2.md passes unedited.

This repo's own PRDs 0001-0006 stay at 0.2 as standing evidence that the
compatibility rule holds. PRD 0007 records the decision at 0.3.


Claude-Session: https://claude.ai/code/session_017XRNNm6pK6nPi7rJ6bJNHu

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Anthony Ettinger 2026-09-06 16:50:11 -07:00 committed by GitHub
parent ca0283caa9
commit 91834179b7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
36 changed files with 679 additions and 80 deletions

View file

@ -148,7 +148,7 @@ export function registerPrdCommands(program: Command): void {
writeIndex(resolve(options.dir));
console.log(`Created ${result.path}`);
console.log(`Assigned id ${result.id}. Index updated.`);
console.log(`\nNext: fill in the eight sections, then logicsrc prd validate ${options.dir}`);
console.log(`\nNext: fill in the ten sections, then logicsrc prd validate ${options.dir}`);
} catch (error) {
fail((error as Error).message, PRD_EXIT.usage);
}
@ -188,11 +188,19 @@ export function registerPrdCommands(program: Command): void {
.option("--strict", "treat lint warnings as errors")
.option("--format <format>", "text, json, yaml, or markdown", "text")
.option("--id <ref>", "validate a single PRD instead of the collection")
.description("Check conformance: filename, front-matter, id match, and the eight sections.")
.option(
"--expect-version <version>",
"flag PRDs that do not declare this openprd version (lint; --strict makes it an error)"
)
.description("Check conformance: filename, front-matter, id match, and the standard sections.")
.action((dir: string, options) => {
// Each document is still validated against the section list its own
// openprd version fixes; this only asks whether the collection is uniform.
const expectedVersion = options.expectVersion as string | undefined;
if (options.id) {
const { doc } = mustFind(dir, options.id);
const report = reportFor(doc, { strict: options.strict === true });
const report = reportFor(doc, { strict: options.strict === true, expectedVersion });
console.log(renderReport(report, options.format as ReportFormat));
if (!report.ok) process.exit(PRD_EXIT.invalid);
return;
@ -201,6 +209,7 @@ export function registerPrdCommands(program: Command): void {
const collection = open(dir);
const report = validatePrdCollection(collection, {
strict: options.strict === true,
expectedVersion,
expectedIndex: renderIndex(collection)
});
console.log(renderReport(report, options.format as ReportFormat));