PRD — Project Planning & PRD Generation
SkillAI & modelsCreate an execution-ready PRD for a project. Creates prd.json + README.md with full HQ context awareness. Runtime-agnostic — executes identically in Claude Code and Codex. Lightweight by default — uses batched questions and adapts interview depth to brainstorm context if available. For deep research subagents + 3-tier 15-question interview, use /deep-plan instead.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the PRD — Project Planning & PRD Generation skill
What this skill tells your AI
The instructions your AI receives, as published by indigoai-us/hq-core in .claude/skills/prd/SKILL.md and read by ahel’s review.
Create execution-ready PRDs with full HQ context awareness. Lightweight flow — batched questions, fast capture, no research subagents. For deep planning on large or strategically important PRDs, use /deep-plan instead. For adversarial spec review of an already-generated PRD, use /review-plan.
Important: Do NOT implement. Just create the PRD.
Step 0: Company Anchor (resolver, not first word)
Resolve the company with the shared resolver — never by hand, and never from the first word alone:
bash core/scripts/resolve-company.sh --prompt "{the user's full input}"
It returns {"company":"<slug>","source":"session|prompt|none"} and resolves in this order:
session— the company already bound for this session (workspace/sessions/<id>/meta.yaml, written by/startwork). This is authoritative. The user already told HQ where they are, so no prompt heuristic may override it.prompt— a manifest slug appearing as a whole token anywhere in the input, not just at position 0. Longest slug wins; an exact length tie breaks on earliest occurrence.none— nothing resolved.
If the resolver is unavailable (older HQ install), fall back to the previous behavior: match the first word against companies/manifest.yaml top-level keys.
If company is non-empty:
- Set
{co}= the resolved slug for the entire flow. If the slug was the leading word of the input, strip it — the remaining text is the project description. If it appeared mid-sentence, leave the input intact - Announce: "Anchored on {co}" (add "— from this session's
/startwork" whensourceissession) - Load policies (frontmatter-only) — For each file in
companies/{co}/policies/(skipexample-policy.md,README.md, and any_digest.mdleftover), runbash core/scripts/read-policy-frontmatter.sh {file}. Noteenforcement: hardtitles. For hard-enforcement policies only, additionally read the## Rulesection with a targeted range. Policy digests (**/policies/_digest.md) are retired — SessionStart now injects matching policies viainject-policy-on-trigger; do not look for or prefer a digest file. Apply hard rules as constraints throughout the PRD - Scope qmd searches — If company has
qmd_collectionsin manifest, use-c {collection}for allqmdcalls - Pre-load repos — Extract
{co}.repos[]from manifest. Present as repo options in Batch 3 Q10 - Scope workers — Filter to company workers (
companies/{co}/workers/) + public workers (workers/public/) - Scope projects — Only search
companies/{co}/projects/for existing project collision check
If source is none — do not silently assume personal scope. Ask the user which company this belongs to, or whether it is personal/HQ work, before creating any project files. Silently filing company work under personal/projects/ hides it from the owning company permanently. The full input text is the project description either way.
Step 1: Get Project Description
If user provided input, use as starting point. If empty, ask the user: "Describe what you want to build or accomplish." Wait for response.
Step 2: Scan HQ Context
Before asking questions, explore HQ. Resolve mode from Step 0 + input:
- company mode — a company slug was anchored in Step 0
- repo mode — no company anchor but a target repo is mentioned or resolvable from input
- personal/HQ mode — neither of the above (personal projects, HQ infrastructure work)
If {co} is anchored, scope all searches to that company.
Companies & Context (only if mode in (company, repo)):
- Read
agents-companies.md(roles, priorities, three-tier roster) — needed to route cross-company PRDs - Read
companies/manifest.yaml(companies already listed there — never Glob for company discovery) - Skip both if already anchored in Step 0: Step 0 already loaded manifest and matched the company. Re-reading is pure waste
- Skip entirely for personal/HQ mode: no company routing needed, no repo to map
Workers (only if mode in (company, repo) AND the description plausibly needs a worker — otherwise skip):
- Read
core/workers/registry.yaml(workers already indexed there — never Glob for worker discovery). Skip if the description is clearly code/infra work not matching a worker skill - If anchored: filter to company workers (
companies/{co}/workers/) + public workers (workers/public/) - Skip entirely for personal/HQ mode
Existing Projects:
- If anchored:
qmd search "prd.json" --json -n 20 -c {co}(scoped) or searchcompanies/{co}/projects/directly - If not anchored:
qmd search "prd.json" --json -n 20— existing projects across all companies and personal
Knowledge (use single qmd hybrid query, not Grep, not vsearch+search pair):
- If anchored + company has
qmd_collections:qmd query "<description keywords>" -c {collection} --json -n 10 - If not anchored:
qmd query "<description keywords>" --json -n 10— hybrid BM25 + vector + re-ranking for related knowledge, prior work, workers
Company Policies (anchored only):
- Already loaded in Step 0 (frontmatter-only). Do NOT re-read here. Note constraints from that scan
Repo Policies (if repo resolved):
- If target repo identified, list files in
{repoPath}/.claude/policies/(if dir exists; skipREADME.md/_digest.md), then for each runbash core/scripts/read-policy-frontmatter.sh {file}. Do not prefer a digest file (retired). For hard-enforcement policies, additionally read the## Rulesection
Target Repo (if repo specified or discovered):
- If anchored: company repos already pre-loaded from manifest. Present as options
- If target repo has a qmd collection (e.g.
my-app):qmd query "<description keywords>" -c {collection} --json -n 10— hybrid search for related code, patterns, existing implementations - Present: "Found related code: {list of relevant files}"
Present:
Scanned HQ:
- Mode: {company | repo | personal/HQ}
- Company: {co} (anchored) | TBD | n/a
- Workers: {relevant list or "skipped"}
- Existing projects: {list or "none matching"}
- Relevant knowledge: {if any}
- Policies: {count loaded, or "none"}
- Category: [company-specific | cross-company | personal | HQ infrastructure]
Step 2.5: Infrastructure Pre-Check
Before generating the PRD, verify infrastructure exists for the target company/repo:
-
Company: If project targets a company, read
companies/manifest.yaml. If company hasknowledge: null, flag: "Company {co} has no knowledge repo. Create one? [Y/n]" — if yes, create embedded repo atcompanies/{co}/knowledge/withgit init, and update manifest.yaml. -
Repo: If
repoPathspecified and doesn't exist locally, flag: "Repo not found at {path}. Clone it or create new?" Add tomanifest.yamlif missing. -
qmd collection: If company has
qmd_collections: []in manifest, flag and offer to create collection.
Fix any gaps before proceeding.
Step 3: Get + Validate Project Name
Ask the user for project slug (or infer from description). Then:
- If
{co}already set by Step 0: use it directly (skip company detection) If NOT set: ask the user. Do not infer a tenant from the description — Step 0's resolver already had the session bind and the full prompt to work with, so an inference here is a guess, and a wrong guess files the work where its company will never find it - Check if
companies/{co}/projects/{name}/exists (also check rootprojects/{name}/for personal/HQ)- If exists: ask the user "Project exists. Continue editing or choose different name?"
- Validate slug format (lowercase, hyphens only)
Step 3.5: Brainstorm Detection
Now that {co} and {slug} are resolved, check if a brainstorm file exists:
companies/{co}/projects/{slug}/brainstorm.md
If found:
- Read it. Extract YAML frontmatter (
status,source_idea_id) - If
status: "promoted"— warn the user: "This brainstorm was already promoted to a PRD. Open existing prd.json instead?" - Pre-load brainstorm content into interview context for Step 4:
- Batch 1 (Problem/Success): pre-fill from brainstorm's
## Context,## Recommendation. Present as confirmations ("Based on brainstorm: {X}. Confirm or modify?") instead of open-ended questions - Batch 2 (Users/Current State): pre-fill audience and current solution from brainstorm context if mentioned
- Batch 3 (Scope/Constraints): pre-fill from
## What We Don't Know+ any constraints mentioned. Surface unknowns as explicit questions to resolve. Pre-fill non-goals from brainstorm's rejected approaches - Batch 4 (Data/Architecture): pre-fill from brainstorm's recommended approach's tech choices, data model mentions
- Batch 5 (Integrations): pre-fill from brainstorm's identified external services
- Batch 6 (Quality/Shipping): pre-fill from brainstorm's identified workers, repos
- Batch 7 (E2E): unchanged — brainstorm doesn't cover testing specifics
- Batch 1 (Problem/Success): pre-fill from brainstorm's
- Effect: interview batches collapse to confirmations rather than open-ended questions. User answers faster, stories are better anchored to the evaluated approach
If not found: proceed normally (no change to existing behavior).
Step 3.6: Open Session Journal
Spec: core/knowledge/public/hq-core/journal-spec.md. Open a session journal at the project_dir so research, decisions, and dead ends survive context compaction:
.claude/skills/_shared/journal.sh open prd "{project_dir}"
Where {project_dir} = companies/{co}/projects/{slug}/ or projects/{slug}/ for personal/HQ. The helper:
- Creates
{project_dir}/journal/{ISO8601}-prd.mdwith frontmatter (status: active,skill: prd) - Writes a session-scoped pointer under
.claude/state/active-journal.d/so this session's autocapture hook + later steps append to this file - Stays open across
/handoffboundaries — only/handoffand/checkpointclose it
The autocapture PostToolUse hook appends ## Auto-capture lines for any Agent / WebFetch / WebSearch / AskUserQuestion calls. Step 4 (interview decisions) and Step 8.5 (resolved/deferred questions) append curated entries via the same helper.
Skip if: journal helper unavailable (fail-soft).
Step 4: Discovery Interview
Ask questions in batches. Users respond with shorthand: "1a A, 1b: build a dashboard, 1c B"
Each question has lettered options for fast answers + free text override. Present one batch at a time, wait for response, then present next batch.
Before Batch 4: Classify project type from description + Batch 1-3 answers:
- Code project (has repoPath, or code/app/API/feature keywords) — ask all batches
- Content/knowledge/report — skip Batches 4, 5; skip 6g/6h. Note: "(Batch 4 skipped — non-code project)"
- Personal/HQ tooling — skip 5b, 5c, 6g, 6h
Dynamic Question Enrichment
Use the context gathered in Step 2 (company policies, repo policies, manifest, repo scan) to enrich questions with specific details rather than asking generic versions. This makes questions faster to answer and surfaces constraints the user might forget.
From company policies (companies/{co}/policies/):
- Policy mentions feature flags / rollout — pre-fill 5c with the required approach, present as confirmation
- Policy mentions PII / GDPR / compliance — always surface 5b regardless of keywords, note the policy
- Policy mentions brand voice / design system — pre-fill 2c option C with the specific system name
- Policy mentions specific deploy procedures — add context to 6a (quality gates)
- Any
enforcement: hardpolicy that constrains architecture, auth, or integrations — surface as a constraint in the relevant batch header (e.g. "Note: company policy requires Clerk auth for all new features")
From repo scan (target repo's CLAUDE.md, package.json, existing patterns):
- Repo uses specific auth (Clerk, NextAuth, Supabase Auth) — pre-fill 4b option A with: "Uses existing auth ({system}) — no changes needed"
- Repo uses specific ORM/DB (Prisma, pgClient, Supabase) — add hint to 4a: "This repo uses {ORM}. Describe entities in those terms"
- Repo has analytics/tracking (PostHog, Segment, Mixpanel, GA) — pre-fill 6g option B with the system name
- Repo has monitoring (Sentry, Datadog, CloudWatch) — pre-fill 6h option B/D with the service name
- Repo has existing test commands — pre-fill 6a with detected commands
- Repo has existing design system / component library — mention in 2c option C
From manifest (companies/manifest.yaml):
- Company has
services: [stripe, ...]— if project might involve payments, surface in 5a as a hint - Company has
vercel_team— enrich 5c with "deploys via Vercel to {team}" - Company has existing integrations — list them as option B context in 5a
Presentation: Weave enrichments into the question text naturally. Don't add a separate "detected context" dump — make each question smarter:
// Generic (bad):
4b. Auth / permissions model?
A. Uses existing auth — no changes needed
// Enriched (good):
4b. Auth / permissions model? (repo uses Clerk via @clerk/nextjs)
A. Uses existing Clerk auth — no changes needed
If a policy or repo context fully answers a question, present it as a confirmation rather than an open question:
5c. Rollout strategy? → Company policy requires feature flags for all new features.
Confirming: B. Feature flag (env var) [Y/n]
Batch 1 — Problem & Success 1a. Core problem or goal? 1b. What does success look like? (measurable metric or verifiable state) 1c. Who benefits? (list all beneficiaries)
Batch 2 — Users & Current State 2a. Who are the primary users? A. Internal / admin only B. External customers / end users C. Both internal and external D. Developer tooling / no direct end user (free text to specify roles and technical level, e.g. "Geoff — CEO, non-technical")
2b. What exists today? (current solution, even if it's a spreadsheet or nothing) A. Nothing — greenfield B. Existing feature being replaced or upgraded C. Manual process being automated D. Third-party tool being replaced (free text to describe what's being replaced and why it's insufficient)
2c. Are there reference designs, mockups, or brand constraints? (skip if non-UI) A. Figma file exists (provide file/node ID) B. Visual reference / screenshot (describe or link) C. Follow existing design system exactly (name which one) D. No design constraints — AI chooses E. Not a UI project (skip) Conditional: auto-skip with E for pure backend/CLI/data projects
Batch 3 — Scope & Constraints 3a. What's in scope for MVP? 3b. Hard constraints (time, tech, budget)? 3c. Dependencies on other projects? 3d. What is explicitly NOT in scope? (non-goals — things users might ask for but we won't build) (free text list, or "none")
Batch 4 — Data & Architecture (conditional: code projects only) Trigger: project has repoPath or description contains DB/schema/API/model keywords. Auto-skip for content/knowledge/reports/social.
4a. Key data entities? (tables, columns, domain objects this project touches)
(free text, e.g. "new depletions table, adds sku_id FK to line_items" — or "no DB changes")
4b. Auth / permissions model? A. Uses existing auth — no changes needed B. New role or permission level needed (describe) C. New auth provider or login method D. No auth (public or internal tool)
4c. Architecture approach? A. Follow existing patterns in the repo exactly B. New pattern needed (describe) C. No opinion — let workers decide
4d. Performance requirements? (conditional: only if real-time/scale/latency/throughput keywords in description) A. Standard — no special requirements B. Latency target: [specify, e.g. "< 2s page load"] C. Throughput target: [specify, e.g. "1000 req/s"] D. Mobile / low-bandwidth optimization needed Default: A
Batch 5 — Integrations & Security (conditional: projects with external service interaction) Trigger: description contains API/webhook/OAuth/third-party/Stripe/Slack/integration keywords. Auto-skip for fully internal projects.
5a. External integrations or third-party APIs? A. None — fully self-contained B. Existing integrations (already wired up, just using them) C. New integration needed — list: which service, what data flows, are credentials already set up?
5b. Sensitive data or security considerations? (conditional: only if user/payment/PII/customer keywords) A. No PII or sensitive data B. PII handled (email, name, payment info) — existing compliance approach applies C. New compliance requirement (HIPAA, GDPR, etc.) D. Rate limiting or abuse protection needed E. User-generated content with moderation needs
5c. Rollout strategy? (conditional: only for production-deployed projects with real users) A. Ship to all users immediately B. Feature flag (specify: env var, LaunchDarkly, user segment) C. Staged rollout (% of users or specific cohort) D. Internal only first, then broader rollout Default: A
Batch 6 — Quality & Shipping
6a. Quality gates? (detect repo from scan, suggest commands)
A. pnpm typecheck && pnpm lint
B. npm run typecheck && npm run lint
C. None (no automated checks)
D. Other: [specify]
6b. Based on scan: "Should this use {relevant workers}?"
6c. Does this need a new worker or skill?
6d. Repo path? (e.g. repos/private/{name}, or "none" if non-code)
6e. Branch name? (default: feature/{project-name})
6f. Base branch? (default: main, or staging for {your-repo}, etc.) — Pure Ralph creates feature branch from this
6g. Analytics / event tracking needed? (conditional: deployable UI projects only) A. No — not a user-facing feature B. Yes — use existing tracking system (name it) C. Yes — new tracking events needed (list key events, e.g. "depletion.filter.applied") D. Not sure — include tracking stub only Default: A
6h. How do we know it's working in production? (conditional: production-deployed projects only) A. Manual testing only B. Existing monitoring covers it (no changes needed) C. New health check or monitoring alert needed (describe) D. Success metric visible in existing dashboard (name it) Default: B for existing repos, A for greenfield
Batch 7 — E2E Testing (recommended for deployable projects) For each user story targeting a deployable repo, specify E2E tests:
7a. What E2E tests should verify each story works? - For UI: "Page loads", "User can complete [action]", "Form shows validation errors" - For API: "Endpoint returns expected response", "Error cases handled" - For CLI: "Command runs successfully", "Opens correct URL" - For integration: "Full flow from [A] to [B] works" - Leave empty for non-deployable projects (knowledge, content, data)
Append interview decisions to journal
After the interview batches complete:
.claude/skills/_shared/journal.sh append "{project_dir}" decisions "Interview decisions: project type — {classification}; scope — {what's in / what's out}; notable answers — {2-3 bullets}"
Live Path Watch hook
Before generating the PRD, detect whether this project plausibly replaces, hardens, or builds alongside an existing live production surface. Purpose: prevent silent regressions on routes that already serve real users.
Trigger the hook when ANY of the following match:
- Project description contains a full URL (
https://...) or a known production hostname (checkcompanies/{co}/manifest.yamldns_zonesand any existing project'smetadata.replacementFor.liveUrls) repoPathmatches a repo that has prior PRDs declaringmetadata.replacementFor(grepcompanies/{co}/projects/*/prd.jsonforreplacementFor)- Description matches replacement/hardening language:
rebuild,replace,harden,v[0-9]+,migration,rewrite,safeguard,regression,silent,prevent+ live noun
On match, ask via AskUserQuestion:
question: "This PRD looks like it touches a live surface. Declare it so heartbeats and canaries can protect it from silent regression?"header:"Live Path Watch"options:label: "Yes — declare live URL(s)"— follow up with a free-text prompt for the URL list (one per line), then setmetadata.replacementFor = { liveUrls, description, detectedFrom: "hook" }and addlivePathWatchto any story whoseacceptanceCriteriamention the matched URLslabel: "No — not a live-surface project"— record the dismissal inmetadata.openQuestionsas"LivePathWatch hook fired but was dismissed: {reason}"(free text)label: "User already answered"— skip (user populatedreplacementForearlier in interview)
If user picks "Yes": also add a canary E2E test to the highest-priority story: "curl -sS <liveUrl> returns 200 and contains none of {forbiddenTokens}".
Policy core/policies/hq-live-path-watch-on-replacement-prds.md (hard enforcement) blocks PRD generation when the hook matches but the user neither declared replacementFor nor explicitly dismissed. The hook MUST run before Step 5.
Step 5: Generate PRD
Create companies/{co}/projects/{name}/ folder with two files. Use root projects/{name}/ only for personal/HQ projects.
Primary: companies/{co}/projects/{name}/prd.json
This is the source of truth. /run-project and /execute-task consume this file.
{
"name": "{project-slug}",
"description": "{1-sentence goal}",
"branchName": "feature/{name}",
"userStories": [
{
"id": "US-001",
"title": "{Story title}",
"description": "{As a [user], I want [feature] so that [benefit]}",
"acceptanceCriteria": ["{Specific verifiable criterion}"],
"e2eTests": [],
"priority": 1,
"passes": false,
"files": [],
"labels": [],
"dependsOn": [],
"notes": "",
"model_hint": "",
"worker_preference": [],
"livePathWatch": []
}
],
"metadata": {
"createdAt": "{ISO8601}",
"goal": "{Overall project goal}",
"successCriteria": "{Measurable outcome}",
"qualityGates": ["{commands from Batch 6a}"],
"repoPath": "{repos/private/repo-name or empty}",
"baseBranch": "{main or staging or master}",
"relatedWorkers": ["{worker-ids from scan}"],
"knowledge": ["{relevant knowledge paths}"],
"audiences": ["{from Batch 2a — user roles + technical level}"],
"currentSolution": "{from Batch 2b — what exists today}",
"designRef": "{from Batch 2c — Figma ID, reference, or empty}",
"nonGoals": ["{from Batch 3d — explicit out-of-scope items}"],
"dataModel": "{from Batch 4a — key entities/tables or empty}",
"authModel": "{from Batch 4b — auth approach or empty}",
"architectureNotes": "{from Batch 4c — approach or empty}",
"performanceRequirements": "{from Batch 4d — targets or empty}",
"integrations": ["{from Batch 5a — service name, type, credentialsReady}"],
"securityNotes": "{from Batch 5b — PII/compliance notes or empty}",
"rolloutStrategy": "{from Batch 5c — ship strategy or empty}",
"analyticsEvents": ["{from Batch 6g — event names or empty}"],
"monitoringNotes": "{from Batch 6h — prod monitoring plan or empty}",
"openQuestions": ["{remaining unresolved questions — Step 8.5 resolves these before Step 9}"],
"decisions": [],
"replacementFor": null
}
}
decisions[] schema: Appended by Step 8.5 as {question, answer, decidedAt, decidedBy}. Optional — absent means empty. Additive and backwards-compatible; existing PRDs without the field are unaffected.
Shortened here. Read the whole file on GitHub.
Signals
- GitHub stars
- 84
- Forks
- 15
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
prd-indigoai-us- Source
- github.com/indigoai-us/hq-core