From st4ck-lite
Author a Product Requirements Document from an existing codebase, code export, or unpacked low-code project — by reading source rather than asking the user. Use when the user wants a PRD generated from imported elements, exported builders (Bubble, Webflow, Retool), screen recordings, or any "code-first" reverse-engineering of intent. Self-contained — bundles its foundational PRD-authoring rules so it works with or without a server connection.
How this skill is triggered — by the user, by Claude, or both
Slash command
/st4ck-lite:prd-from-sourceThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
**Announce at start:** "I'm using the prd-from-source skill — authoring a PRD by reading the codebase rather than asking the user."
Announce at start: "I'm using the prd-from-source skill — authoring a PRD by reading the codebase rather than asking the user."
A PRD authoring skill grounded in the spec-driven development consensus that emerged 2024–2026 (GitHub Spec Kit, AWS Kiro, Reversa, OpenSpec, AGENTS.md). PRDs authored with this skill are:
Do not use when the user is designing a new feature from scratch — for that, use a requirements/discovery skill, not this one.
These rules apply to any PRD, source-grounded or otherwise. They are the substrate this skill operates against; everything below builds on them.
Every PRD node must pass this test: could a developer who has never seen this application implement exactly this feature from your description alone — with no access to source code, no product owner to ask, no designer to consult?
If they would need to guess anything, you haven't written enough. Every omitted detail is a question they cannot answer. Every vague description is a feature they will build wrong.
The PRD is a hierarchy. Target depth is 4–5 levels:
root → module → screen / entity / user_flow / backend_flow / business_rule / integration
→ component / field / logic / validation / endpoint / error_state / element / button
| Parent type | Required children |
|---|---|
| Screen | One component per distinct UI section (header, form, table, sidebar, modal). One element per interactive element with non-obvious behavior. |
| Entity | One field per non-trivial field (or small group of closely related fields) — type, constraints, defaults, validation. Skip boilerplate (id, created_at, updated_at, deleted_at). |
| User flow | One logic per major step (action, system response, decision point). One error_state per distinct failure path. |
| Backend flow | One logic per processing stage. One validation per input guard. One endpoint if the flow exposes an API. |
| Business rule | One validation per distinct condition. One error_state per exception. |
| Integration | One endpoint per call direction (inbound / outbound). |
root, overview, module, subsystemscreen, section, user_flow, backend_flow, entity, business_rule, integration, processcomponent, element, field, button, logic, validation, error_state, endpointcalls_endpoint, uses_entity, enforces_rule, triggers_flow, depends_on, related_to, validates_with, redirects_to
Cross-link screens to entities they display, flows to rules they enforce, endpoints to their flows.
Write as a product document. Describe what the software does, not how it's built:
useAdvisor() hook checks isAdvisor === true and renders AdvisorBanner"Rules:
A PRD is only as accurate as the code it describes:
Before considering a PRD complete:
A PRD without an anchor produces garbled assumptions from raw code reading. Run these four checks before opening the first source file. They take 5 minutes total and save hours of misinterpretation downstream.
If the project is connected to st4ck (i.e., the orchestrator has access to mcp__st4ck-pm__* or mcp__st4ck-dev__* tools and the project has a briefing):
get_project_users() # lists project_users / user types with roles, permissions, descriptions
get_project_briefing() # one-liner about the app + recent versions
If get_project_users returns a non-empty taxonomy, use that as the role anchor for the whole PRD. Every user_role_ids: slug, every state-machine role binding, every privacy rule cites these roles by name. Don't reinvent role IDs from the code's option-set values; reconcile both.
If get_project_users returns empty OR no st4ck connection exists, proceed to 0.2.
Before role taxonomy, get the higher-frame answer: what kind of app is this, who is it for, how does it differ from a generic SaaS? These five questions decide the rigor target for the whole PRD — what to test exhaustively vs. what to leave informal.
Why these five matter:
| Answer pattern | What the PRD can skip or downplay |
|---|---|
| Business-specific + single tenant + single language | i18n testing, translation completeness, SLA documentation for users, public-sign-up flows, multi-tenant security tests as "attacker defense" (still test isolation — but accepted-as-design rather than treated-as-threat). Edge cases that "would never happen with these specific users" can be marked accepted. |
| SaaS + multi-tenant + multi-language | All of the above MATTER. Cross-tenant isolation is defense-against-strangers. Translation completeness gates release. Edge cases are paying customers. |
For business-specific apps, edge-case findings that "wouldn't happen with these specific users" are legitimately closeable as accepted operational behavior — the user-base is known and self-correcting. For SaaS, the same finding is a real bug.
After 0.2's context, ask:
Existing artifacts are usually richer than the code:
Ask the user explicitly: "Do you have any other documentation you'd like to use as input for this PRD pass?" Be specific about the categories above — users often forget they have these.
When the user provides extra docs, treat them as hints, not source of truth (code still wins per Iron Rule #1). But hints from a real PRD or help page often answer questions that are ambiguous in raw code.
Don't ping the user nine times. Send all of 0.2 + 0.3 + 0.4 in a single message — it's a 60-second answer for them, and the orchestrator's whole rigor framing comes from these. The single biggest Phase 0 anti-pattern is making the user feel like a long discussion is starting. It isn't — it's a quick anchor.
A short anchor block written to the PRD root _index.md BEFORE any modules are authored:
Pass 1 (mechanical scaffold) and Pass 2 (curated intent) follow. Without Phase 0, both passes are guessing.
A product question the running code answers is not a question — it is a fact waiting to be read. The default move for an apparent clarification is to investigate, in this order:
.meta.json, AST dump, raw export blob) for operators or attributes the human-readable summary may have stripped (list operators like add/remove, condition values that reference internal codes, etc.).*_get_schema, *_describe_table, *_query).[NEEDS CLARIFICATION] — and only for genuinely-unanswerable-from-code things (untranslated copy, design intent for an empty state, business decisions on un-built features).When the source shows that something is never called, never set, never reached, state it plainly. Don't soften "this is dead code" to "this might be unused" or "this needs verification". The grep result is the verification. A confident finding can be reviewed and corrected by the orchestrator or user; a hedged finding cannot be acted on.
Specific phrasings that belong in the PRD when the code supports them:
| What you found | How to write it |
|---|---|
| Field exists in schema but no code reads it | "Dead field. Not read by any workflow or screen condition. Treat as historical; do not write new logic against it." |
| Workflow exists but no caller invokes it | "Orphan workflow. No caller found in pages, reusables, or other workflows. Either vestigial or invoked externally; tests should NOT assume it runs." |
| Status value exists in option set but no workflow assigns it | "Unreachable status. The option set defines this value but no code path assigns it. Aspirational placeholder OR dead label." |
| Role / permission branch exists in routing but goes nowhere | "Dead route. A user reaching this branch is stranded. Either intentional (the role has no UI) or a regression — confirm with stakeholder." |
| Permission split between two roles is absent in code | "No separation. Roles X and Y have identical permissions on this surface, by design or by oversight. Tests must not assert one can do something the other cannot." |
A PRD that hedges every dead-code finding to "needs verification" is useless to the orchestrator and the user — the next session will redo the same investigation. A PRD that states findings plainly creates a record the user can review and either confirm or correct.
The orchestrator's review pass on its own findings is always available. A confident-but-wrong finding is reviewable. A hedged finding is permanently ambiguous. Prefer the former.
Three confidence markers, inspired by Reversa:
[CONFIRMED: <src>] — claim is directly observable in the cited source. Default for everything you write.[INFERRED: <src>] — claim is a reasonable read of the source but involves judgment (e.g., interpreting an option-set's intended meaning from its usage in workflows when the option set itself is opaque).[GAP] — the source is silent or ambiguous on this point. Used sparingly and always with a concrete question for the next pass.Source paths go in the file's frontmatter source: list. Inline citations within prose are allowed as footnote-style [src: <path>] when a specific claim warrants it.
If your environment has persistent memory (prior conversation notes, auto-memory records, project briefings):
When dispatching a subagent (Explore, Plan, research) to read code:
A good subagent dispatch prompt always includes:
For each claim you make, cite the specific file path under the source root where you read it. If you cannot cite a file for a claim, mark the claim as
[INFERRED]or[GAP]. Do not blend confirmed and inferred claims as if they were the same.
This is the single biggest mitigation against subagent hallucinations.
Walk the source and create one PRD node per first-class artifact, with a 2–3 sentence overview each:
Fast, complete, produces a flat re-encoding of structure. Low test signal on its own — but it gives you the skeleton.
Walk the same artifacts again and add the layer the source does not encode:
user_role_ids) on every node where role matters.Pass 2 is where the PRD becomes useful for test authoring.
Author as Markdown under <project>/<path>/docs/prd/ (project-conventional location). One MD file per node. A future importer can walk the tree and call DB writes.
docs/prd/
├── _index.md # root
├── 00_shared/ # cross-module reusables + shared concepts
│ ├── _index.md
│ ├── components/ # menus, sidebars, popups
│ ├── state_machines/ # status option sets, lifecycle flags
│ ├── integrations/ # external services
│ └── entities/ # entities referenced from multiple modules
├── 01_<module>/
│ ├── _index.md
│ ├── entities/<entity>/_index.md # entity head
│ │ └── <field>.md # field children where business-meaningful
│ ├── screens/<screen>/_index.md
│ │ └── <component>.md # component children
│ ├── user_flows/<flow>.md
│ ├── backend_flows/<flow>.md
│ └── business_rules/<rule>.md
Rule: a folder represents a parent node; its _index.md is the overview; sibling files (or sub-folders) are the children. Decomposed nodes get a folder; leaf nodes are a single .md.
When the user says "build a PRD module-by-module", choose ONE of the following per shared artifact:
| Artifact type | Treatment | Example |
|---|---|---|
| Physical reusables (same component rendered in multiple modules) | Author ONCE in 00_shared/, cross-link from each module that uses it | A site header used by both the Admin Home and the Member Home |
| Concepts that cross modules (a flow whose narrative differs by perspective) | DUPLICATE in each module, with cross-links to the other modules' perspectives | A multi-party transaction described from the Buyer's view, the Seller's view, and the Operator's view |
A PRD is intent by audience, not an architectural blueprint. The "duplicate with cross-link" pattern preserves each audience's narrative while keeping consistency via the links.
Every PRD MD file starts with YAML frontmatter:
---
node_type: <root|module|screen|entity|field|user_flow|backend_flow|business_rule|component|element|integration|...>
title: <human-readable title>
summary: <one line — used as the overview when this node is referenced from a parent>
user_role_ids: [admin, editor] # slugs from the project's role taxonomy; optional
source: # provenance — paths into the original codebase/export
- "data_types/some_entity/"
- "backend_workflows/update_x/"
cross_links: # links to other PRD nodes (paths relative to docs/prd/)
- target: 01_module/entities/some_entity
type: enforces_rule
delta: ADDED # optional, for brownfield diff passes (ADDED/MODIFIED/REMOVED/UNCHANGED)
---
source:.db_value strings are correct nowhere.Each user_flow and business_rule should carry a stable ID in frontmatter — pattern FLOW-<MODULE>-<NN> or RULE-<MODULE>-<NN>. Test cases can then cite these IDs cleanly. (Optional but valuable; adopt early if downstream test tooling expects it.)
Every node should be readable by all three audiences:
| Audience | What they need | How the node delivers |
|---|---|---|
| Non-technical stakeholder | What the system does, in plain English / native UI language | Body prose; UI labels with translation glosses; behavior described in observable terms |
| QA engineer | Test preconditions, success states, error paths, what to assert | "Test implications" section on every leaf; state machines with explicit transitions and side effects |
| Developer | Source provenance for ground-truth verification; decomposition deep enough to anchor tests on specific UI surfaces | source: frontmatter; tree depth 3–5 levels; cross-links for traceability |
The completeness check for any leaf node: could a stranger (no access to source code, no product owner to ask, no designer to consult) implement exactly this piece from this node alone? If they'd need to guess anything, the node is incomplete.
Industry equivalent terms: "Rebuild Test" (the older internal phrasing), "completeness check" (Spec Kit), "self-sufficiency test".
Many low-code exports follow a similar shape: a .md body for humans + a .meta.json (or similar) sidecar for the raw builder data. Always check both. Some critical facts live only in the sidecar:
add / remove / set) are often in JSON but stripped from MD bodies.db_value, internal IDs) may be obfuscated in MD but readable in JSON.When a sidecar exists, treat the MD as "the index" and the JSON as "the truth". If the two disagree, the JSON wins.
| Symptom | What's actually going on | What to do |
|---|---|---|
| Schema-extraction document has fewer entities than the source folder | Extraction was a partial pass; don't trust counts | Walk the source folders directly |
Option-set db_value shown as ____ / _____ / etc. | Builder obfuscated the value during export | Don't decode it. The PRD describes user-observable behavior, not DB values. If a workflow sets a status to "the underscore value that displays as 'Sent to processor' in the user's locale", document it as "the workflow sets status to Sent" — the display label is what matters. See the Internal-code anti-pattern below. |
| MD says "Field Changes: list-field = value" | List operator (add/remove/set) is in the JSON | Read .meta.json for the action key. List operators DO matter for behavior. |
Workflow with Ignores Privacy: yes | System-level actor, runs without user role context | Document the privacy bypass explicitly in the PRD |
| Reusable element appears under multiple names in different file lists | The export wraps each reusable instance with a wrapper element that has its own display name | Verify which actual reusable is mounted by reading the instance file's Reusable Element: line |
A PRD describes what the user does and what observably changes. It does NOT describe the database, the field key, the option-set db_value, the workflow's internal name, or any other engineering identifier. These rules apply even when the orchestrator can resolve them:
| Tempted to write | What the PRD should say instead |
|---|---|
"sets status_option_order_status to option:order_status:____________" | "sets the order status to Submitted" |
"the search filters by type_option_user_types equals option:user_types:____0" | "the search filters for Customer-type companies" |
"fires when is_temp_record_boolean equals false" | "fires for real (non-temporary) records" |
"calls change_pass_text via Bubble's UpdateCredentials action" | "updates the user's stored password" |
The temptation to spend effort decoding ____ strings or naming internal operators is wasted effort — the PRD's reader (PO, QA, dev) cares about observable behavior. If a finding cannot be expressed without leaking a code value, the finding hasn't been understood yet.
The only places engineering identifiers are valid in this skill's output:
source: frontmatter list — provenance citations.Status field reads as Submitted in the UI"; the field name appears once, as an anchor, not as repeated jargon).[src: path] citations on disputed claims.Writing for the PRD's audience means writing about the product, not the platform's internals.
Per the AGENTS.md convention now stewarded by the Linux Foundation, a project that has a PRD should also have a project-root AGENTS.md. But AGENTS.md and the PRD have non-overlapping purposes, and confusing them creates drift hazards:
| Belongs in AGENTS.md | Belongs in the PRD |
|---|---|
| Where files live in the repo | What the product does |
| Build / test / run commands | Entities, flows, business rules |
| Code conventions, naming, style | State machines |
| Always / Ask first / Never operational tiers | Security findings, dead code, known issues |
| Which MCP tools / skills are wired up | Stakeholder questions |
| A pointer to the PRD root | Cross-tenant isolation rules |
Rule: if a piece of content describes the running product, it belongs in the PRD — not AGENTS.md. If a piece of content describes how to work in this repo as an agent, it belongs in AGENTS.md.
The reason this matters: AGENTS.md has no update mechanism tied to product changes. If a workflow's behavior changes, the PRD update is part of the change; AGENTS.md sits next to the repo root and tends to rot. The fix is to never let AGENTS.md own product knowledge in the first place. Make it small, operational, and have it link to the PRD for everything else.
The PRD-from-source pass is a natural moment to emit or refresh AGENTS.md, BUT:
_index.md and KNOWN_GAPS.md are the agent's destination for product knowledge — AGENTS.md just points there.A good AGENTS.md after a PRD-from-source pass is ~50–100 lines. If it's longer, it's probably bleeding PRD content into a file that doesn't have an update mechanism.
If the project exposes MCP tools that read the running database / API:
*_get_schema, *_list_records, *_describe_table, *_query — preferred over re-deriving schema from an export.This rule exists because export → PRD is a translation, and translations drop information. Live data is the closest thing to the source of truth.
From the upstream methodology: calls_endpoint, uses_entity, enforces_rule, triggers_flow, depends_on, related_to, validates_with, redirects_to.
Cross-link screens to entities they display, flows to rules they enforce, entities to the rules that gate them.
| Parent | Required children |
|---|---|
| Screen | One component per UI section; one element per non-obvious interactive element. |
| Entity | One field per business-meaningful field (skip boilerplate id/timestamps). |
| User flow | One logic per major step; one error_state per failure path. Or capture in body sections with clear step numbering for shorter flows. |
| Backend flow | One logic per processing stage; one validation per guard; one endpoint if it exposes an API. Or describe in body when ≤ 10 actions. |
| Business rule | One validation per condition; one error_state per exception. Or compact in body for simple rules. |
| Integration | One endpoint per call direction (inbound / outbound). |
Before declaring a module complete:
[NEEDS CLARIFICATION] for things the code answers.source: paths point at files that exist.db_value is ____________". Spending effort to disambiguate underscore-count strings is wasted work; the display label is what the PRD cares about. (See "The internal-code anti-pattern" above.)get_project_users if connected; otherwise ask the user for the role taxonomy + app anchor. Ask about other documentation. Write the anchor block to the PRD root.00_shared/).prd-review skill for the four-phase review pipeline.AGENTS.md — operational steering only (see the AGENTS.md section).In the spec-driven-development consensus, four artifacts have distinct purposes — this skill produces the first:
A PRD-from-source pass on a long-running system may also produce ADRs for decisions visible in code (e.g., "the platform deliberately runs the out-of-stock recompute on every line edit rather than batched at close — see ADR-001"). When you find a decision worth promoting to an ADR, surface it as a candidate, don't bury it inside a node.
This skill is grounded in the spec-driven-development consensus as of 2026. Influential sources:
/specify → /plan → /tasks → /implement pipeline; [NEEDS CLARIFICATION] convention.Guides completion of development work by verifying tests, detecting environment, and presenting structured options for merge, PR, or cleanup.
Enforces test-driven development: write failing test first, then minimal code to pass. Use when implementing features or bugfixes.
Guides creation and editing of skills using test-driven development with pressure scenarios and subagents to verify agent compliance.
npx claudepluginhub edo-ceder/st4ck-lite --plugin st4ck-lite