feat: add mosaic prdy command for PRD creation and validation

Adds `mosaic prdy {init|update|validate}` subcommand:
- init: launches yolo Claude session with PRD-focused system prompt
- update: launches session to modify existing docs/PRD.md
- validate: bash-only completeness checker (15 checks against PRD guide)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jason Woltje
2026-02-23 11:04:35 -06:00
parent c1f4830bf5
commit c9bf578396
5 changed files with 642 additions and 0 deletions

View File

@@ -51,6 +51,12 @@ Management:
release-upgrade [...] Upgrade installed Mosaic release
project-upgrade [...] Clean up stale SOUL.md/CLAUDE.md in a project
PRD:
prdy <subcommand> PRD creation and validation
init Create docs/PRD.md via Claude session
update Update existing PRD via Claude session
validate Check PRD completeness (bash-only)
Coordinator (r0):
coord <subcommand> Manual coordinator tools
init Initialize a new mission
@@ -478,6 +484,44 @@ _check_resumable_session() {
fi
}
run_prdy() {
check_mosaic_home
local subcmd="${1:-help}"
shift || true
local tool_dir="$MOSAIC_HOME/tools/prdy"
case "$subcmd" in
init)
exec bash "$tool_dir/prdy-init.sh" "$@"
;;
update)
exec bash "$tool_dir/prdy-update.sh" "$@"
;;
validate|check)
exec bash "$tool_dir/prdy-validate.sh" "$@"
;;
help|*)
cat <<PRDY_USAGE
mosaic prdy — PRD creation and validation tools
Commands:
init [--project <path>] [--name <feature>] Create docs/PRD.md via guided Claude session
update [--project <path>] Update existing docs/PRD.md via Claude session
validate [--project <path>] Check PRD completeness against Mosaic guide (bash-only)
Examples:
mosaic prdy init --name "User Authentication"
mosaic prdy update
mosaic prdy validate
Output location: docs/PRD.md (per Mosaic PRD guide)
PRDY_USAGE
;;
esac
}
run_bootstrap() {
check_mosaic_home
exec "$MOSAIC_HOME/bin/mosaic-bootstrap-repo" "$@"
@@ -550,6 +594,7 @@ case "$command" in
sync) run_sync "$@" ;;
seq) run_seq "$@" ;;
bootstrap) run_bootstrap "$@" ;;
prdy) run_prdy "$@" ;;
coord) run_coord "$@" ;;
upgrade) run_upgrade "$@" ;;
release-upgrade) run_release_upgrade "$@" ;;

265
tools/prdy/_lib.sh Normal file
View File

@@ -0,0 +1,265 @@
#!/usr/bin/env bash
#
# _lib.sh — Shared functions for mosaic prdy tools
#
# Usage: source ~/.config/mosaic/tools/prdy/_lib.sh
#
# Provides PRD detection, section validation, and system prompt generation
# for interactive PRD creation/update sessions.
MOSAIC_HOME="${MOSAIC_HOME:-$HOME/.config/mosaic}"
PRD_CANONICAL="docs/PRD.md"
PRD_JSON_ALT="docs/PRD.json"
# ─── Color support ───────────────────────────────────────────────────────────
if [[ -t 1 ]]; then
C_GREEN='\033[0;32m'
C_RED='\033[0;31m'
C_YELLOW='\033[0;33m'
C_CYAN='\033[0;36m'
C_BOLD='\033[1m'
C_DIM='\033[2m'
C_RESET='\033[0m'
else
C_GREEN='' C_RED='' C_YELLOW='' C_CYAN='' C_BOLD='' C_DIM='' C_RESET=''
fi
ok() { echo -e " ${C_GREEN}${C_RESET} $1"; }
warn() { echo -e " ${C_YELLOW}${C_RESET} $1" >&2; }
fail() { echo -e " ${C_RED}${C_RESET} $1" >&2; }
info() { echo -e " ${C_CYAN}${C_RESET} $1"; }
step() { echo -e "\n${C_BOLD}$1${C_RESET}"; }
# ─── Dependency checks ──────────────────────────────────────────────────────
_require_cmd() {
local cmd="$1"
if ! command -v "$cmd" &>/dev/null; then
fail "'$cmd' is required but not installed"
return 1
fi
}
# ─── PRD detection ───────────────────────────────────────────────────────────
# Find the PRD file in a project directory.
# Returns the path (relative to project root) or empty string.
find_prd() {
local project="${1:-.}"
if [[ -f "$project/$PRD_CANONICAL" ]]; then
echo "$project/$PRD_CANONICAL"
elif [[ -f "$project/$PRD_JSON_ALT" ]]; then
echo "$project/$PRD_JSON_ALT"
fi
}
# ─── Section validation manifest ─────────────────────────────────────────────
# 10 required sections per ~/.config/mosaic/guides/PRD.md
# Each entry: "label|grep_pattern" (extended regex, case-insensitive via grep -iE)
PRDY_REQUIRED_SECTIONS=(
"Problem Statement|^#{2,3} .*(problem statement|objective)"
"Scope / Non-Goals|^#{2,3} .*(scope|non.goal|out of scope|in.scope)"
"User Stories / Requirements|^#{2,3} .*(user stor|stakeholder|user.*requirement)"
"Functional Requirements|^#{2,3} .*functional requirement"
"Non-Functional Requirements|^#{2,3} .*non.functional"
"Acceptance Criteria|^#{2,3} .*acceptance criteria|\*\*acceptance criteria\*\*|- \[ \]"
"Technical Considerations|^#{2,3} .*(technical consideration|constraint|dependenc)"
"Risks / Open Questions|^#{2,3} .*(risk|open question)"
"Success Metrics / Testing|^#{2,3} .*(success metric|test|verification)"
"Milestones / Delivery|^#{2,3} .*(milestone|delivery|scope version)"
)
# ─── System prompt builder ───────────────────────────────────────────────────
# Build the specialized system prompt for PRD sessions.
# Usage: build_prdy_system_prompt <mode>
# mode: "init" or "update"
build_prdy_system_prompt() {
local mode="${1:-init}"
local guide_file="$MOSAIC_HOME/guides/PRD.md"
local template_file="$MOSAIC_HOME/templates/docs/PRD.md.template"
cat <<'PROMPT_HEADER'
# Mosaic PRD Agent — Behavioral Contract
You are a specialized PRD (Product Requirements Document) agent. Your sole purpose is to help the user create or update a comprehensive PRD document.
## Mode Declaration (Hard Gate)
PROMPT_HEADER
if [[ "$mode" == "init" ]]; then
cat <<'INIT_MODE'
Your first response MUST start with: "Now initiating PRD Creation mode..."
You are creating a NEW PRD. The output file is `docs/PRD.md`.
## Workflow
1. Read the project directory to understand context (README, package.json, existing docs, source structure)
2. Ask the user 3-5 clarifying questions with lettered options (A/B/C/D) so they can answer "1A, 2C, 3B"
3. Focus questions on: problem/goal, target users, scope boundaries, milestone structure, success criteria
4. After answers (or if the description is sufficiently complete), generate the full PRD
5. Write to `docs/PRD.md` (create `docs/` directory if it doesn't exist)
6. After writing, tell the user: "PRD written to docs/PRD.md. Run `mosaic prdy validate` to verify completeness."
INIT_MODE
else
cat <<'UPDATE_MODE'
Your first response MUST start with: "Now initiating PRD Update mode..."
You are UPDATING an existing PRD. Read `docs/PRD.md` (or `docs/PRD.json`) first.
## Workflow
1. Read the existing PRD file completely
2. Summarize the current state to the user (title, status, milestone count, open questions)
3. Ask the user what changes or additions are needed
4. Make targeted modifications — do NOT rewrite sections that don't need changes
5. Preserve existing user stories, FRs, and acceptance criteria unless explicitly asked to change them
6. After writing, tell the user: "PRD updated. Run `mosaic prdy validate` to verify completeness."
UPDATE_MODE
fi
cat <<'CONSTRAINTS'
## Hard Constraints
MUST:
- Save output to `docs/PRD.md` only
- Include ALL 10 required sections from the Mosaic PRD guide (included below)
- Number functional requirements as FR-1, FR-2, ... in sequence
- Group user stories under named Milestones (e.g., "Milestone 0.0.4 — Foundation")
- Format user stories as US-NNN with Description and Acceptance Criteria checkboxes
- Mark all guessed decisions with `ASSUMPTION:` and rationale
- Include a Metadata block (Owner, Date, Status, Mission ID, Scope Version)
- Write for junior developers and AI agents — explicit, unambiguous, no jargon
- Include "Typecheck and lint pass" in acceptance criteria for code stories
- Include "Verify in browser using dev-browser skill" for UI stories
MUST NOT:
- Write any implementation code
- Modify any files other than `docs/PRD.md`
- Skip clarifying questions when the feature description is ambiguous
- Begin implementation of any requirements
- Invent requirements silently — all guesses must be marked with ASSUMPTION
CONSTRAINTS
cat <<'STRUCTURE'
## Required PRD Structure (Gold Standard)
Follow this exact structure. Every section is required.
```
# PRD: {Feature/Project Name}
## Metadata
- **Owner:** {name}
- **Date:** {yyyy-mm-dd}
- **Status:** draft|planning|approved|in-progress|completed
- **Mission ID:** {kebab-case-id-yyyymmdd}
- **Scope Version:** {e.g., 0.0.4 → 0.0.5 → 0.1.0}
## Introduction
Narrative overview: what this is, the context it lives in, what exists before this work.
## Problem Statement
Numbered list of specific pain points being solved.
## Goals
Bullet list of measurable objectives.
## Milestones
Named milestones (e.g., "Milestone 0.0.4 — Design System Foundation").
Each milestone has a one-paragraph description of its theme.
## User Stories (grouped under milestones)
### Milestone X.Y.Z — {Theme Name}
#### US-001: {Title}
**Description:** As a {user}, I want {feature} so that {benefit}.
**Acceptance Criteria:**
- [ ] Specific verifiable criterion
- [ ] Another criterion
- [ ] Typecheck and lint pass
- [ ] [UI stories only] Verify in browser using dev-browser skill
---
## Functional Requirements
Numbered FR-1 through FR-N. Group by subsystem if applicable.
Each: "FR-N: {subject} must {behavior}"
## Non-Goals (Out of Scope)
Numbered list of explicit exclusions with brief rationale.
## Design Considerations
- Design references (mockups, existing design systems)
- Key visual/UX elements
- Component hierarchy
## Technical Considerations
### Dependencies
Libraries, packages, external services required.
### Build & CI
Build pipeline, CI gates, quality checks.
### Deployment
Target infrastructure, deployment method, image tagging strategy.
### Risks
Technical risks that could affect delivery.
## Success Metrics
Numbered list of measurable success conditions.
## Open Questions
Numbered list. For unresolved items, add:
(ASSUMPTION: {best-guess decision} — {rationale})
```
STRUCTURE
cat <<'QUESTIONS'
## Clarifying Question Format
When asking clarifying questions, use numbered questions with lettered options:
```
1. What is the primary goal?
A. Option one
B. Option two
C. Option three
D. Other: [please specify]
2. What is the target scope?
A. Minimal viable
B. Full-featured
C. Backend only
D. Frontend only
```
Tell the user they can answer with shorthand like "1A, 2C, 3B" for quick iteration.
QUESTIONS
# Include the live PRD guide
if [[ -f "$guide_file" ]]; then
printf '\n## Mosaic PRD Guide (Authoritative Rules)\n\n'
cat "$guide_file"
fi
# Include the template as reference
if [[ -f "$template_file" ]]; then
printf '\n## PRD Template Reference\n\n```markdown\n'
cat "$template_file"
printf '\n```\n'
fi
}

87
tools/prdy/prdy-init.sh Normal file
View File

@@ -0,0 +1,87 @@
#!/usr/bin/env bash
set -euo pipefail
#
# prdy-init.sh — Create a new PRD via guided Claude session
#
# Usage:
# prdy-init.sh [--project <path>] [--name <feature>]
#
# Launches a dedicated Claude Code session in yolo mode with a specialized
# system prompt that guides the user through PRD creation. The output is
# written to docs/PRD.md.
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/_lib.sh"
# ─── Parse arguments ─────────────────────────────────────────────────────────
PROJECT="."
NAME=""
while [[ $# -gt 0 ]]; do
case "$1" in
--project) PROJECT="$2"; shift 2 ;;
--name) NAME="$2"; shift 2 ;;
-h|--help)
cat <<'USAGE'
prdy-init.sh — Create a new PRD via guided Claude session
Usage: prdy-init.sh [--project <path>] [--name <feature>]
Options:
--project <path> Project directory (default: CWD)
--name <feature> Feature or project name (optional, Claude will ask if omitted)
Launches Claude Code in yolo mode with a PRD-focused system prompt.
The agent will ask clarifying questions, then write docs/PRD.md.
Examples:
mosaic prdy init
mosaic prdy init --name "User Authentication"
mosaic prdy init --project ~/src/my-app --name "Dashboard Redesign"
USAGE
exit 0
;;
*) echo "Unknown option: $1" >&2; exit 1 ;;
esac
done
# Expand tilde if passed literally (e.g., --project ~/src/foo)
PROJECT="${PROJECT/#\~/$HOME}"
# ─── Preflight checks ───────────────────────────────────────────────────────
_require_cmd "claude"
# Check for existing PRD
EXISTING="$(find_prd "$PROJECT")"
if [[ -n "$EXISTING" ]]; then
fail "PRD already exists: $EXISTING"
echo -e " Use ${C_CYAN}mosaic prdy update${C_RESET} to modify the existing PRD."
exit 1
fi
# Ensure docs/ directory exists
mkdir -p "$PROJECT/docs"
# ─── Build system prompt ─────────────────────────────────────────────────────
step "Launching PRD creation session"
SYSTEM_PROMPT="$(build_prdy_system_prompt "init")"
# Build kickoff message
if [[ -n "$NAME" ]]; then
KICKOFF="Create docs/PRD.md for the feature: ${NAME}. Read the project context first, then ask clarifying questions before writing the PRD."
else
KICKOFF="Create docs/PRD.md for this project. Read the project context first, then ask the user what they want to build. Ask clarifying questions before writing the PRD."
fi
# ─── Launch Claude ───────────────────────────────────────────────────────────
info "Output target: $PROJECT/$PRD_CANONICAL"
info "Mode: PRD Creation (yolo)"
echo ""
cd "$PROJECT"
exec claude --dangerously-skip-permissions --append-system-prompt "$SYSTEM_PROMPT" "$KICKOFF"

75
tools/prdy/prdy-update.sh Normal file
View File

@@ -0,0 +1,75 @@
#!/usr/bin/env bash
set -euo pipefail
#
# prdy-update.sh — Update an existing PRD via guided Claude session
#
# Usage:
# prdy-update.sh [--project <path>]
#
# Launches a dedicated Claude Code session in yolo mode with a specialized
# system prompt that reads the existing PRD and guides targeted modifications.
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/_lib.sh"
# ─── Parse arguments ─────────────────────────────────────────────────────────
PROJECT="."
while [[ $# -gt 0 ]]; do
case "$1" in
--project) PROJECT="$2"; shift 2 ;;
-h|--help)
cat <<'USAGE'
prdy-update.sh — Update an existing PRD via guided Claude session
Usage: prdy-update.sh [--project <path>]
Options:
--project <path> Project directory (default: CWD)
Launches Claude Code in yolo mode with a PRD-update system prompt.
The agent will read the existing docs/PRD.md, summarize its state,
and ask what changes are needed.
Examples:
mosaic prdy update
mosaic prdy update --project ~/src/my-app
USAGE
exit 0
;;
*) echo "Unknown option: $1" >&2; exit 1 ;;
esac
done
# Expand tilde if passed literally (e.g., --project ~/src/foo)
PROJECT="${PROJECT/#\~/$HOME}"
# ─── Preflight checks ───────────────────────────────────────────────────────
_require_cmd "claude"
# Require existing PRD
EXISTING="$(find_prd "$PROJECT")"
if [[ -z "$EXISTING" ]]; then
fail "No PRD found in $PROJECT/docs/"
echo -e " Run ${C_CYAN}mosaic prdy init${C_RESET} to create one first."
exit 1
fi
# ─── Build system prompt ─────────────────────────────────────────────────────
step "Launching PRD update session"
SYSTEM_PROMPT="$(build_prdy_system_prompt "update")"
KICKOFF="Read the existing PRD at ${EXISTING}, summarize its current state, then ask what changes or additions are needed."
# ─── Launch Claude ───────────────────────────────────────────────────────────
info "Updating: $EXISTING"
info "Mode: PRD Update (yolo)"
echo ""
cd "$PROJECT"
exec claude --dangerously-skip-permissions --append-system-prompt "$SYSTEM_PROMPT" "$KICKOFF"

170
tools/prdy/prdy-validate.sh Normal file
View File

@@ -0,0 +1,170 @@
#!/usr/bin/env bash
set -euo pipefail
#
# prdy-validate.sh — Check PRD completeness against Mosaic guide requirements
#
# Usage:
# prdy-validate.sh [--project <path>]
#
# Performs static analysis of docs/PRD.md to verify it meets the minimum
# content requirements defined in the Mosaic PRD guide.
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/_lib.sh"
# ─── Parse arguments ─────────────────────────────────────────────────────────
PROJECT="."
while [[ $# -gt 0 ]]; do
case "$1" in
--project) PROJECT="$2"; shift 2 ;;
-h|--help)
cat <<'USAGE'
prdy-validate.sh — Check PRD completeness against Mosaic guide
Usage: prdy-validate.sh [--project <path>]
Options:
--project <path> Project directory (default: CWD)
Checks:
- docs/PRD.md exists
- All 10 required sections present
- Metadata block (Owner, Date, Status)
- Functional requirements (FR-N) count
- User stories (US-NNN) count
- Acceptance criteria checklist count
- ASSUMPTION markers (informational)
Exit codes:
0 All required checks pass
1 One or more required checks failed
USAGE
exit 0
;;
*) echo "Unknown option: $1" >&2; exit 1 ;;
esac
done
# Expand tilde if passed literally (e.g., --project ~/src/foo)
PROJECT="${PROJECT/#\~/$HOME}"
# ─── Find PRD ────────────────────────────────────────────────────────────────
step "Validating PRD"
PRD_PATH="$(find_prd "$PROJECT")"
PASS=0
FAIL_COUNT=0
WARN_COUNT=0
check_pass() {
ok "$1"
PASS=$((PASS + 1))
}
check_fail() {
fail "$1"
FAIL_COUNT=$((FAIL_COUNT + 1))
}
check_warn() {
warn "$1"
WARN_COUNT=$((WARN_COUNT + 1))
}
if [[ -z "$PRD_PATH" ]]; then
check_fail "No PRD found. Expected $PROJECT/$PRD_CANONICAL or $PROJECT/$PRD_JSON_ALT"
echo ""
echo -e "${C_RED}PRD validation failed.${C_RESET} Run ${C_CYAN}mosaic prdy init${C_RESET} to create one."
exit 1
fi
check_pass "PRD found: $PRD_PATH"
# JSON PRDs get a limited check
if [[ "$PRD_PATH" == *.json ]]; then
info "JSON PRD detected — section checks skipped (markdown-only)"
echo ""
echo -e "${C_GREEN}PRD file exists.${C_RESET} JSON validation is limited."
exit 0
fi
PRD_CONTENT="$(cat "$PRD_PATH")"
# ─── Section checks ─────────────────────────────────────────────────────────
for entry in "${PRDY_REQUIRED_SECTIONS[@]}"; do
label="${entry%%|*}"
pattern="${entry#*|}"
if echo "$PRD_CONTENT" | grep -qiE "$pattern"; then
check_pass "$label section present"
else
check_fail "$label section MISSING"
fi
done
# ─── Metadata checks ────────────────────────────────────────────────────────
META_PASS=true
for field in "Owner" "Date" "Status"; do
if ! echo "$PRD_CONTENT" | grep -qiE "^- \*\*${field}:\*\*|^- ${field}:"; then
META_PASS=false
fi
done
if $META_PASS; then
check_pass "Metadata block present (Owner, Date, Status)"
else
check_fail "Metadata block incomplete (need Owner, Date, Status)"
fi
# ─── Content counts ─────────────────────────────────────────────────────────
FR_COUNT=$(echo "$PRD_CONTENT" | grep -cE '^\- FR-[0-9]+:|^FR-[0-9]+:' || true)
US_COUNT=$(echo "$PRD_CONTENT" | grep -cE '^#{1,4} US-[0-9]+' || true)
AC_COUNT=$(echo "$PRD_CONTENT" | grep -cE '^\s*- \[ \]' || true)
ASSUMPTION_COUNT=$(echo "$PRD_CONTENT" | grep -c 'ASSUMPTION:' || true)
if [[ "$FR_COUNT" -gt 0 ]]; then
check_pass "Functional requirements: $FR_COUNT FR items"
else
check_warn "No FR-N items found (expected numbered functional requirements)"
fi
if [[ "$US_COUNT" -gt 0 ]]; then
check_pass "User stories: $US_COUNT US items"
else
check_warn "No US-NNN items found (expected user stories)"
fi
if [[ "$AC_COUNT" -gt 0 ]]; then
check_pass "Acceptance criteria: $AC_COUNT checklist items"
else
check_warn "No acceptance criteria checkboxes found"
fi
if [[ "$ASSUMPTION_COUNT" -gt 0 ]]; then
info "ASSUMPTION markers: $ASSUMPTION_COUNT (informational)"
fi
# ─── Summary ─────────────────────────────────────────────────────────────────
TOTAL=$((PASS + FAIL_COUNT))
echo ""
if [[ "$FAIL_COUNT" -eq 0 ]]; then
echo -e "${C_GREEN}PRD validation passed.${C_RESET} ${PASS}/${TOTAL} checks OK."
if [[ "$WARN_COUNT" -gt 0 ]]; then
echo -e "${C_YELLOW}${WARN_COUNT} warning(s)${C_RESET} — review recommended."
fi
exit 0
else
echo -e "${C_RED}PRD validation failed.${C_RESET} ${FAIL_COUNT}/${TOTAL} checks failed."
if [[ "$WARN_COUNT" -gt 0 ]]; then
echo -e "${C_YELLOW}${WARN_COUNT} warning(s)${C_RESET}"
fi
exit 1
fi