Skip to content

Conversation

@frankbria
Copy link
Owner

@frankbria frankbria commented Jan 29, 2026

Summary

Implements cf prd generate command for CLI-native PRD creation through interactive Socratic discovery.

  • Interactive question/answer flow with 5 required questions
  • Progress tracking with visual feedback
  • Pause/resume support via blocker system
  • Optional AI-powered follow-up questions
  • Automatic PRD generation from structured answers

Changes

File Description
codeframe/core/prd_discovery.py New headless discovery session manager
codeframe/cli/app.py Added prd generate command (+222 lines)
tests/core/test_prd_discovery.py 18 unit tests
tests/cli/test_prd_generate.py 11 CLI integration tests

Usage

# Start interactive discovery
cf prd generate

# Resume a paused session
cf prd generate --resume abc123

# Skip optional questions
cf prd generate --skip-optional

Special Commands During Discovery

Command Action
/pause Save progress and create blocker for later resume
/quit Exit without saving
/help Show available commands

Discovery Flow

  1. Problem - What problem does this solve?
  2. Users - Who are the primary users?
  3. Features - What are the core features?
  4. Constraints - Technical constraints?
  5. Tech Stack - Preferred technologies?

Each answer is validated (minimum length, no "n/a" patterns) and stored in a new discovery_sessions table.

Generated PRD Structure

# {Project Title}

## Overview
{From problem answers}

## User Stories
{Generated from users + features}

## Technical Requirements
{From tech_stack answers}

## Constraints
{From constraints answers}

## Core Features
{Extracted features list}

## Acceptance Criteria
{Generated checkboxes}

Test Plan

  • Unit tests for PrdDiscoverySession (18 tests)
  • CLI integration tests (11 tests)
  • All 1188 v2 tests passing
  • Ruff lint check passing

Related

Summary by CodeRabbit

  • New Features

    • Added a CLI command to run a guided PRD discovery flow with start/resume via blocker IDs, persistent sessions, and PRD preview on completion.
    • Headless AI-driven Socratic discovery session support with pause/resume, inline commands (/help, /pause, /skip, /quit), answer validation, and graceful interrupt/save behavior.
  • Tests

    • Comprehensive tests covering CLI flows, session lifecycle, pause/resume, validation, persistence, PRD generation, and error cases.

✏️ Tip: You can customize this high-level summary in your review settings.

Implements `cf prd generate` command for CLI-native PRD creation through
interactive Socratic discovery.

Features:
- Interactive question/answer flow with progress tracking
- 5 required questions covering problem, users, features, constraints, tech stack
- AI-powered follow-up questions when ANTHROPIC_API_KEY available
- Pause/resume support via blocker system
- Input validation (min length, invalid pattern detection)
- Automatic PRD generation from structured answers
- Resume incomplete sessions automatically

New files:
- codeframe/core/prd_discovery.py: Headless discovery session manager
- tests/core/test_prd_discovery.py: 18 unit tests
- tests/cli/test_prd_generate.py: 11 CLI integration tests

Special commands during discovery:
- /pause - Save progress and create blocker for later resume
- /skip - Skip optional questions
- /quit - Exit without saving
- /help - Show available commands

Part of Phase 1: CLI Completion (v2 Strategic Roadmap)
Addresses issue #307
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 29, 2026

Walkthrough

Adds an interactive cf prd generate CLI subcommand and a headless PRD discovery engine that runs a multi‑turn Socratic questioning flow, supports pause/resume via blockers, validates AI answers, persists discovery sessions in discovery_sessions, and generates/stores a PRD with preview output.

Changes

Cohort / File(s) Summary
CLI Command
codeframe/cli/app.py
Adds prd generate subcommand (--workspace/-w, --resume/-r) implementing workspace resolution, start/resume logic, interactive discovery loop, inline commands (/help, /pause, /skip, /quit), KeyboardInterrupt handling, event emission, and PRD preview.
Core Discovery Engine
codeframe/core/prd_discovery.py
New headless discovery module introducing PrdDiscoverySession, SessionState enum, ValidationError/IncompleteSessionError/NoApiKeyError, DB schema for discovery_sessions, AI-driven question generation & answer validation, coverage assessment, pause/resume via blocker IDs, session persistence, PRD extraction and storage, and get_active_session(workspace).
CLI Tests
tests/cli/test_prd_generate.py
New integration-style tests exercising cf prd generate flows: help, API key handling, start/resume, existing-PRD prompt, inline commands visibility, pause/save with blocker, invalid-resume handling, full PRD generation and preview, and AI validation behaviors (mocked LLM).
Core Discovery Tests
tests/core/test_prd_discovery.py
Comprehensive unit tests for session lifecycle, question retrieval and AI fallback, answer validation rules, progress reporting, pause/resume persistence, PRD generation structure, and DB-backed persistence/serialization.

Sequence Diagram

sequenceDiagram
    participant User as User
    participant CLI as CLI
    participant Session as PrdDiscoverySession
    participant DB as Discovery_DB
    participant LLM as LLM_Provider
    participant PRD as PRD_Store

    User->>CLI: cf prd generate --workspace <path> [--resume <id>]
    CLI->>Session: start_or_resume(session_id?)
    Session->>DB: _ensure_discovery_schema()
    Session->>DB: _save_session() [INITIAL]

    loop Interactive Discovery Loop
        Session->>Session: get_current_question()
        alt AI enabled
            Session->>LLM: generate_question(context)
            LLM-->>Session: question / follow-up
        else Static fallback
            Session-->>Session: return_canned_question()
        end
        Session-->>CLI: show question & progress
        CLI-->>User: prompt for answer
        User->>CLI: answer or /command
        alt /pause or /quit
            CLI->>Session: pause_discovery()
            Session->>DB: _save_session() [PAUSED + blocker]
            CLI-->>User: show blocker ID
        else normal answer
            CLI->>Session: submit_answer(response)
            Session->>Session: validate & update coverage
            Session->>DB: _save_session() [UPDATED]
            Session-->>CLI: next question or completion
        end
    end

    alt Completed
        CLI->>Session: generate_prd()
        Session->>PRD: store_prd(record)
        Session->>DB: _save_session() [COMPLETED]
        CLI-->>User: show PRD preview & next steps
    end
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 In a burrow of prompts I softly inquire,
Socratic carrots coax answers higher,
Questions hop and progress brightly grows,
Blockers saved, then onward the session goes,
A PRD blooms where thoughtful dialogue sows.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding interactive PRD generation via Socratic discovery, which is the core feature of this PR.
Linked Issues check ✅ Passed The PR implements all coding requirements from #307: CLI commands (prd generate, --resume), multi-turn Socratic questioning, pausing/resuming via blockers, database persistence, and structured PRD output with required sections.
Out of Scope Changes check ✅ Passed All changes are directly scoped to #307 requirements: prd_discovery.py implements session logic, app.py adds the CLI command, and tests validate functionality. No extraneous changes detected.
Docstring Coverage ✅ Passed Docstring coverage is 93.33% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/prd-generate

Comment @coderabbitai help to get the list of available commands and usage tips.

@macroscopeapp
Copy link
Contributor

macroscopeapp bot commented Jan 29, 2026

Add interactive PRD discovery and generation to CLI via codeframe/cli/app.py:prd_app.generate

Introduce PrdDiscoverySession with persistent state, AI-driven Q&A, coverage tracking, pause/resume via blockers, and PRD generation, and wire it into the prd generate CLI in app.py; implement session lifecycle, validation, next-question flow, schema persistence, and PRD storage in prd_discovery.py; add targeted tests for CLI and session behavior.

📍Where to Start

Start at the CLI handler prd_app.generate in app.py, then follow into session logic in PrdDiscoverySession.start_discovery and PrdDiscoverySession.submit_answer in prd_discovery.py.


Macroscope summarized bbdd8c1.

@claude
Copy link

claude bot commented Jan 29, 2026

PR Review: Interactive PRD Generation via Socratic Discovery

This is a well-implemented feature that aligns excellently with the v2 architecture principles. The implementation is clean, headless, and follows the Golden Path methodology. Here's my detailed review:


Strengths

Architecture Alignment

  • Perfectly headless: prd_discovery.py has zero FastAPI/HTTP dependencies ✓
  • Core-first design: Business logic properly isolated in codeframe/core/
  • CLI integration: Clean separation between CLI presentation and core logic ✓
  • Reuses existing components: Leverages DiscoveryQuestionFramework and AnswerCapture

Code Quality

  • Comprehensive testing: 18 unit tests + 11 CLI integration tests = excellent coverage
  • State persistence: Proper SQLite storage with schema management via _ensure_discovery_schema()
  • Error handling: Custom exceptions (ValidationError, IncompleteSessionError) with clear error messages
  • Session management: Well-designed state machine (IDLE → DISCOVERING → PAUSED/COMPLETED)

User Experience

  • Progress tracking: Visual progress bar with percentage completion
  • Pause/resume: Blocker-based session persistence
  • Input validation: Minimum length + invalid pattern detection
  • Help system: In-line /help, /pause, /skip, /quit commands
  • AI enhancement: Optional AI-powered follow-up questions when API key available

🔍 Areas for Improvement

1. Database Migration Safety

Issue: _ensure_discovery_schema() creates table without migration tracking

# prd_discovery.py:850
def _ensure_discovery_schema(workspace: Workspace) -> None:
    cursor.execute("""
        CREATE TABLE IF NOT EXISTS discovery_sessions (...)
    """)

Recommendation: Consider adding a migration system or version tracking to handle future schema changes gracefully. For now, this is acceptable as CREATE IF NOT EXISTS is idempotent, but document this decision.

2. LLM Provider Error Handling

Observation: Silent fallback when LLM initialization fails (line 95-100)

except Exception as e:
    logger.warning(f"Failed to initialize LLM provider: {e}")
    self._llm_provider = None

Recommendation: This is good defensive programming, but consider informing the user when falling back to static questions in the CLI output for transparency.

3. PRD Title Extraction Logic

Potential Issue: _extract_title() (line 691-702) takes first sentence or 50 chars, which may truncate awkwardly

if "." in text[:100]:
    return text.split(".")[0].strip()[:60]
return text[:50].strip() + "..."

Recommendation: Consider using the LLM to extract/generate a concise title from the problem description, or prompt user for an explicit title in the discovery flow.

4. Test Coverage Gap

Minor: No explicit test for concurrent session creation

While unlikely in CLI usage, get_active_session() could theoretically return wrong session if multiple users/processes create sessions simultaneously.

Recommendation: Add workspace-level locking or document single-user assumption.

5. Type Annotation Consistency

Minor: Line 80 uses Any for _llm_provider

_llm_provider: Any = field(default=None, init=False)

Recommendation: Use Optional[AnthropicProvider] or create a protocol for type safety.


🛡️ Security Considerations

No SQL injection: Uses parameterized queries throughout
API key handling: Properly uses environment variable fallback
Input sanitization: Validates user input before storage
⚠️ Blocker question storage: Session ID stored in blocker question text (line 600). Consider using structured metadata field instead for easier parsing.


📊 Performance Considerations

Database indexes: Proper indexes on workspace_id and state (lines 875-881)
JSON storage: Efficient serialization of answers
Lazy LLM initialization: Only creates provider when needed
Minimal database I/O: Saves session state only after each answer


🧪 Test Quality Assessment

Unit Tests (test_prd_discovery.py):

  • ✅ Covers happy paths (session lifecycle)
  • ✅ Tests error conditions (incomplete session, validation)
  • ✅ Mocks external dependencies (LLM provider)
  • ✅ Tests state transitions

CLI Integration Tests (test_prd_generate.py):

  • ✅ Tests user interactions via CliRunner
  • ✅ Tests special commands (/pause, /help, /quit)
  • ✅ Tests input validation
  • ✅ Tests PRD generation flow

Coverage appears comprehensive - likely 90%+ on new code.


📝 Documentation Quality

✅ Module docstring explains purpose and headless nature
✅ Class docstring documents attributes
✅ CLI command has detailed help text with examples
✅ Special commands documented in command docstring
⚠️ Missing: Architecture decision record (ADR) for blocker-based resume vs. explicit session management


🎯 Alignment with Phase 1 Goals

From docs/V2_STRATEGIC_ROADMAP.md:

This PR directly advances Phase 1 completion.


🚀 Recommendations for Merge

Must Fix Before Merge

None - Code is production-ready as-is.

Should Consider (Post-Merge)

  1. Add user notification when falling back to static questions (transparency)
  2. Consider LLM-generated titles for better UX
  3. Document single-user assumption for session management
  4. Add integration test for --skip-optional flag usage

Nice to Have (Future Enhancement)

  1. Support for custom question templates (aligns with [Phase 1] PRD template system for customizable output formats #316)
  2. Session export/import for collaboration
  3. Multi-language support for questions
  4. Analytics on common answer patterns

Overall Assessment

Code Quality: 9/10
Architecture Alignment: 10/10
Test Coverage: 9/10
Documentation: 8/10
User Experience: 9/10

Final Verdict: ✅ Approve with enthusiastic recommendation

This is exemplary v2 implementation. The code is clean, well-tested, follows all architectural principles, and provides genuine user value. The session-based approach with pause/resume is particularly elegant.

Great work! 🎉


📚 Related Documentation

  • Golden Path: docs/GOLDEN_PATH.md
  • V2 Roadmap: docs/V2_STRATEGIC_ROADMAP.md
  • CLI Wireframe: docs/CLI_WIREFRAME.md

Reviewed by: Claude Sonnet 4.5
Date: 2026-01-29

ValidationError: If answer is invalid
ValueError: If no current question
"""
answer_text = answer_text.strip()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Low

Consider adding consistent session/state guards. Require non-None session_id and state == DISCOVERING in submit_answer, a started session in pause_discovery, and prevent resume_discovery from reopening COMPLETED sessions. A shared helper would keep this consistent.

-        answer_text = answer_text.strip()
+        if self.session_id is None:
+            raise ValueError("No active session - call start_discovery() first")
+
+        answer_text = answer_text.strip()

🚀 Want me to fix this? Reply ex: "fix it for me".

Raises:
ValueError: If session not found
"""
conn = get_db_connection(self.workspace)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Low

Consider wrapping DB operations in try/finally (or a context manager) so connections always close on exceptions across all DB callers (e.g., load_session, _save_session, _ensure_discovery_schema, get_active_session).

🚀 Want me to fix this? Reply ex: "fix it for me".

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@codeframe/cli/app.py`:
- Around line 1246-1253: The /skip branch currently breaks out of the input loop
without advancing the session, so the same question is shown again; fix by
invoking a session-level skip or submitting a placeholder answer: either add a
skip_question() method on PrdDiscoverySession (implementing the behavior
suggested in the review: validate optional, record an entry with "skipped":
True, _save_session and return True) and call session.skip_question() from the
CLI when answer.lower() == "/skip", or call the existing
session.submit_answer(...) (or equivalent) with an empty/placeholder payload
that the session recognizes as skipped; ensure you use the unique symbols
session.skip_question (new) or session.submit_answer /
session.get_current_question to locate and update the code and handle the skip
result to continue to the next question.
🧹 Nitpick comments (1)
codeframe/core/prd_discovery.py (1)

374-406: Consider storing session_id in blocker metadata instead of parsing from question text.

The current approach parses Session ID: from the blocker's question text, which is fragile if the question format changes. If the blocker system supports metadata fields, that would be more robust.

However, this works correctly for the current implementation and the format is controlled by pause_discovery.

Comment on lines 1246 to 1253
if answer.lower() == "/skip":
if is_optional or skip_optional:
# Move to next question by submitting a placeholder
console.print("[dim]Skipping...[/dim]\n")
break
else:
console.print("[yellow]Cannot skip required questions[/yellow]")
continue
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

The /skip command doesn't actually skip the question.

When the user types /skip, the code breaks out of the inner answer loop without submitting anything. However, since no answer is recorded, session.get_current_question() will return the same question on the next iteration of the outer loop.

To properly skip optional questions, you need to either:

  1. Submit a placeholder answer that the session recognizes as "skipped"
  2. Add a skip_question() method to PrdDiscoverySession that advances to the next question without recording an answer
🔧 Possible fix: Add a skip_question method to PrdDiscoverySession

In codeframe/core/prd_discovery.py, add a method to skip optional questions:

def skip_question(self) -> bool:
    """Skip the current optional question.
    
    Returns:
        True if question was skipped, False if not optional
    """
    context = {qid: data.get("text", "") for qid, data in self._answers.items()}
    question = self._framework.get_next_question(context)
    
    if question is None:
        return False
    
    if question.get("importance") != "optional":
        return False
    
    # Record as skipped (empty marker)
    self._answers[question["id"]] = {
        "text": "",
        "question_text": question["text"],
        "category": question["category"],
        "timestamp": _utc_now().isoformat(),
        "skipped": True,
    }
    self._save_session()
    return True

Then in the CLI:

 if answer.lower() == "/skip":
     if is_optional or skip_optional:
-        # Move to next question by submitting a placeholder
-        console.print("[dim]Skipping...[/dim]\n")
-        break
+        if session.skip_question():
+            console.print("[dim]Skipping...[/dim]\n")
+            break
+        else:
+            console.print("[yellow]Cannot skip this question[/yellow]")
+            continue
     else:
         console.print("[yellow]Cannot skip required questions[/yellow]")
         continue
🤖 Prompt for AI Agents
In `@codeframe/cli/app.py` around lines 1246 - 1253, The /skip branch currently
breaks out of the input loop without advancing the session, so the same question
is shown again; fix by invoking a session-level skip or submitting a placeholder
answer: either add a skip_question() method on PrdDiscoverySession (implementing
the behavior suggested in the review: validate optional, record an entry with
"skipped": True, _save_session and return True) and call session.skip_question()
from the CLI when answer.lower() == "/skip", or call the existing
session.submit_answer(...) (or equivalent) with an empty/placeholder payload
that the session recognizes as skipped; ensure you use the unique symbols
session.skip_question (new) or session.submit_answer /
session.get_current_question to locate and update the code and handle the skip
result to continue to the next question.

- AI is now Plan A - no fallback to static questions
- Context-sensitive questions via AI generation
- AI validates answer adequacy (relevance, specificity, completeness)
- Coverage scoring system (problem, users, features, constraints, tech_stack)
- "Question tax" - AI only asks if answer meaningfully improves PRD
- Completion based on coverage threshold (avg 70, all categories 60+)
- Updated tests with comprehensive mocked LLM responses
@claude
Copy link

claude bot commented Jan 29, 2026

Follow-up Review Notes

I've reviewed this PR and my comprehensive review from earlier still stands. The implementation is excellent and ready to merge.

However, I want to highlight one item from CodeRabbit's review that deserves attention:

Documentation Discrepancy: /skip Command

Issue: The PR description mentions a /skip command in the "Special Commands During Discovery" table, but this is not actually implemented.

The actual implementation:

  1. Does NOT implement /skip in the CLI handler (lines 1139-1245 in app.py)
  2. Does NOT document /skip in the command docstring (lines 1119-1122)
  3. Still mentions /skip in the PR description

Recommendation: Update the PR description to remove the /skip command reference. The AI-driven discovery doesn't have a concept of "optional questions" - the AI determines when to stop based on coverage assessment, so skip doesn't make sense in this context.

This is purely a documentation issue - the code itself is correct.


Other Notes

All other items from my previous review and CodeRabbit's suggestions are minor improvements for future work, not blockers:

  1. Session ID parsing from blocker text (CodeRabbit's nitpick) - works fine, could be more robust with metadata
  2. Database migration tracking - acceptable for v1, document if needed later
  3. Type annotation for _llm_provider - minor improvement

Verdict: Ready to merge once PR description is updated to remove /skip reference.

Great work on this feature!

Comment on lines 267 to 273
# Ensure schema exists and save initial session
_ensure_discovery_schema(self.workspace)
self._save_session()

# Generate first question
self._current_question = self._generate_opening_question()

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Low

Consider moving _save_session() after _generate_opening_question() to avoid persisting an inconsistent session state if the LLM call fails.

Suggested change
# Ensure schema exists and save initial session
_ensure_discovery_schema(self.workspace)
self._save_session()
# Generate first question
self._current_question = self._generate_opening_question()
# Ensure schema exists
_ensure_discovery_schema(self.workspace)
# Generate first question before saving to ensure consistent state
self._current_question = self._generate_opening_question()
# Save session only after successful question generation
self._save_session()

🚀 Want me to fix this? Reply ex: "fix it for me".

try:
session = PrdDiscoverySession(workspace)
session.resume_discovery(resume)
except (ValueError, NoApiKeyError) as e:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 High

Session resume is fragile due to discovery DB schema handling. Suggest ensuring the discovery_sessions table exists without dropping data (use CREATE TABLE IF NOT EXISTS in _ensure_discovery_schema()), call it before get_active_session()/resume_discovery(), and optionally catch sqlite3.OperationalError during load/resume.

🚀 Want me to fix this? Reply ex: "fix it for me".

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@codeframe/core/prd_discovery.py`:
- Around line 700-703: The current code unconditionally drops the
discovery_sessions table via cursor.execute("DROP TABLE IF EXISTS
discovery_sessions"), which destroys saved sessions and breaks resume logic
(e.g., get_active_session); replace this destructive reset with a guarded
migration: remove the DROP TABLE call, implement a schema-migration path that
checks the current schema/version and issues ALTER TABLE or creates missing
columns/tables as needed, or add a guarded reset flag (e.g., force_reset
parameter) that only runs the DROP when explicitly true; update functions that
assume table presence (like get_active_session) to handle missing columns
gracefully and log the migration action via cursor.execute and schema version
checks instead of blindly dropping discovery_sessions.
- Around line 257-273: start_discovery currently calls _save_session before
generating and persisting the opening question, leaving current_question NULL if
the user exits early; move the persistence so that _current_question is set by
_generate_opening_question and then call _save_session (or call _save_session
again after setting _current_question) to ensure the session record stores the
opening question; update the start_discovery method to call
_generate_opening_question first (or call _save_session a second time) so
_current_question is persisted for resume logic.
- Around line 464-468: Update _coverage_is_sufficient to also enforce a
minimum-question requirement (5) before allowing discovery to be considered
complete: in the method _coverage_is_sufficient check the current
question/answer count (use self._questions_count if present, otherwise
len(self._questions or [])) and return False if that count is less than 5, then
keep the existing check of self._coverage.get("ready_for_prd", False); i.e.,
require both minimum questions and ready_for_prd to be true before returning
True.

@claude
Copy link

claude bot commented Jan 29, 2026

Updated Review: AI-Native PRD Discovery

I've reviewed the latest changes (commit eda4af4) that make discovery fully AI-native. This is an excellent evolution from the initial hybrid approach. Here's my assessment:


New Strengths in Latest Version

AI-Native Architecture

  • No fallback to static questions: AI drives the entire flow - this is much cleaner than the hybrid approach
  • Coverage-based completion: Smart scoring system (problem, users, features, constraints, tech_stack) with threshold checks
  • AI validates answers: The AI determines if answers are substantive enough - great UX
  • Context-sensitive questioning: Each question builds on previous answers

Improved Design

  • "Question tax" concept: AI only asks if the answer will meaningfully improve the PRD - prevents over-questioning
  • Dynamic progress: Coverage percentage (avg ≥70%, all categories ≥60%) instead of fixed question count
  • Better error handling: NoApiKeyError makes it clear that AI is required
  • Cleaner test mocks: Tests properly mock the full AI conversation flow

🔍 Issues from CodeRabbit's Review

1. ❌ CRITICAL: Destructive Schema Reset (line 700-703)

CodeRabbit correctly identified that the code contains:

cursor.execute("DROP TABLE IF EXISTS discovery_sessions")

Impact: This destroys all saved sessions and breaks resume functionality. This would be a production incident.

Required fix: Remove the DROP TABLE entirely. The CREATE TABLE IF NOT EXISTS is sufficient.

2. ⚠️ Medium: Missing opening question persistence

CodeRabbit notes that start_discovery saves the session before generating the opening question, leaving current_question NULL. If a user exits early, resume won't work properly.

Suggested fix: Call _save_session() again after setting _current_question.

3. ⚠️ Medium: Missing minimum question requirement

The coverage scoring could theoretically mark a session complete after 1-2 very detailed answers. A minimum question count (5) would ensure thorough discovery.

Suggested fix: Add to _coverage_is_sufficient:

def _coverage_is_sufficient(self) -> bool:
    if len(self._answers) < 5:  # Minimum questions
        return False
    return self._coverage.get("ready_for_prd", False)

📝 Documentation Issue

/skip Command Discrepancy

As I noted in my follow-up review, the PR description still mentions a /skip command, but:

  • It's not implemented in the CLI handler (lines 1119-1245)
  • It's not documented in the command docstring (lines 1119-1122)
  • It doesn't make sense for AI-driven discovery (the AI decides when to stop)

Required fix: Update the PR description to remove /skip references. The actual implementation only supports:

  • /pause - Save progress
  • /quit - Exit without saving
  • /help - Show commands

🛡️ Security & Performance

✅ All previous security concerns still addressed:

  • Parameterized SQL queries
  • API key via environment variable
  • Input sanitization via AI validation

✅ Performance is good:

  • Lazy LLM initialization
  • Coverage-based stopping (efficient)
  • JSON storage in SQLite

🎯 Merge Requirements

Must Fix Before Merge

  1. Remove DROP TABLE in schema management (line ~700) - BLOCKING BUG
  2. Update PR description to remove /skip command

Should Fix Before Merge

  1. Add minimum question count to _coverage_is_sufficient
  2. Save session after setting opening question in start_discovery

Post-Merge Improvements

  • Consider storing blocker metadata in structured field instead of parsing from text
  • Add ADR documenting AI-native architecture decision

Overall Assessment

Code Quality: 8/10 (down from 9/10 due to DROP TABLE bug)
Architecture: 10/10 (AI-native is the right call)
Test Coverage: 9/10
Documentation: 7/10 (needs PR description update)

Verdict: ⚠️ Approve with required fixes

The AI-native approach is excellent - much cleaner than the hybrid model. However, the DROP TABLE bug is blocking and must be fixed before merge. Once the destructive schema reset is removed and the PR description is corrected, this is ready to ship.

The architecture aligns perfectly with v2 principles (headless, CLI-first, core-first) and delivers genuine value for Phase 1 completion.


Reviewed by: Claude Sonnet 4.5
Date: 2026-01-29
Commits reviewed: 8f257b1, 42049d6, eda4af4

- Remove destructive DROP TABLE statement (was destroying saved sessions)
- Persist opening question after generation (enables early-exit resume)
- Remove /skip from available commands (not applicable to AI-driven discovery)

AI completion remains flexible - comprehensive answers can complete
discovery quickly without minimum question requirements.
@claude
Copy link

claude bot commented Jan 29, 2026

✅ Final Review - All Issues Addressed (commit 2169955)

I've reviewed the latest commit that addresses all feedback from my previous reviews and CodeRabbit's analysis. This PR is now ready to merge.


🎯 Changes in Latest Commit (2169955)

The commit successfully resolves all blocking issues:

  1. ✅ FIXED: Removed destructive DROP TABLE

    • Previously had DROP TABLE IF EXISTS discovery_sessions that would destroy saved sessions
    • Now only uses CREATE TABLE IF NOT EXISTS - correct approach
  2. ✅ FIXED: Opening question persistence

    • Now saves session after generating opening question
    • Enables proper resume even if user exits immediately after start
  3. ✅ FIXED: Documentation consistency

    • Removed /skip from PR description (was never implemented)
    • Command docstring correctly documents only /pause, /quit, /help

📋 Architecture Assessment

✅ v2 Principles (All Met)

  • Headless core: Zero FastAPI/HTTP dependencies in prd_discovery.py
  • CLI-first: Works without server - pure Golden Path
  • Core isolation: Business logic properly separated from presentation
  • Event emission: Proper PRD_ADDED event when complete

✅ Code Quality

  • Test coverage: 29 tests (18 unit + 11 CLI integration) - comprehensive
  • AI-native design: LLM drives entire flow (question generation, validation, coverage assessment)
  • Error handling: Custom exceptions with clear messages
  • State management: Clean transitions via SessionState enum

✅ Database Design

  • Proper schema: CREATE TABLE IF NOT EXISTS with indexes on workspace_id, state
  • JSON storage: Efficiently stores Q&A history and coverage data
  • Foreign keys: Links to workspace and blockers tables

🔍 Minor Observations (Non-Blocking)

These are suggestions for future enhancement, not merge requirements:

  1. Session ID parsing from blocker text (line 820-825)

    • Works correctly but could be more robust with structured metadata field
    • Current regex parsing is adequate for MVP
  2. No minimum question count

    • Coverage-based completion allows finishing quickly if answers are comprehensive
    • This is intentional per AI-native design - flexibility is appropriate
  3. Type annotation (line 479)

    • Uses Any for _llm_provider
    • Could use Optional[AnthropicProvider] for stricter typing

🎉 Highlights

This PR exemplifies excellent v2 implementation:

  • True AI-native: No fallback to static questions - LLM drives everything
  • Coverage scoring: Smart completion based on semantic assessment, not arbitrary question count
  • Question tax concept: AI only asks if answer will meaningfully improve PRD
  • Pause/resume via blockers: Elegant reuse of existing blocker system
  • Comprehensive testing: Both unit and integration tests with proper mocking

✨ Final Verdict

Status: ✅ APPROVED - Ready to Merge

Code Quality: 9/10
Architecture: 10/10
Test Coverage: 9/10
Documentation: 9/10

This feature directly advances Phase 1: CLI Completion from the v2 Strategic Roadmap and closes issue #307. The AI-driven approach is the right architectural decision and aligns perfectly with headless, CLI-first principles.

Excellent work! 🚀


Reviewed by: Claude Sonnet 4.5
Commits reviewed: 8f257b1, 42049d6, eda4af4, 2169955
Date: 2026-01-29

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@codeframe/core/prd_discovery.py`:
- Around line 766-773: The current block silently returns None when
ANTHROPIC_API_KEY is missing which hides configuration errors; update the logic
around os.getenv("ANTHROPIC_API_KEY") so that instead of returning None you log
a clear warning (use the module logger or processLogger) and raise a descriptive
exception (e.g., RuntimeError or ValueError) indicating the missing
ANTHROPIC_API_KEY so callers and tests can distinguish "session not present"
from "session could not be loaded"; reference PrdDiscoverySession and the
subsequent session.load_session(row[0]) call when implementing this change.
🧹 Nitpick comments (2)
codeframe/core/prd_discovery.py (2)

427-439: Consider extracting JSON parsing into a reusable helper.

The markdown code block parsing logic (lines 431-434) is duplicated in _validate_answer and _update_coverage. While the fallback handling makes this safe, extracting it into a helper would improve maintainability.

♻️ Suggested helper extraction
def _parse_json_response(content: str) -> Optional[dict[str, Any]]:
    """Parse JSON from LLM response, handling markdown code blocks."""
    content = content.strip()
    if content.startswith("```"):
        parts = content.split("```")
        if len(parts) >= 2:
            content = parts[1]
            if content.startswith("json"):
                content = content[4:]
    try:
        return json.loads(content.strip())
    except json.JSONDecodeError:
        return None

558-590: Fragile string parsing for session resume.

The resume logic relies on parsing the blocker's question text to extract the session ID (lines 575-580) and uses substring matching to identify discovery blockers (line 571). This is fragile:

  1. Any blocker containing "discovery" would pass the check (false positives)
  2. The Session ID: format must exactly match what pause_discovery writes

Consider storing the session ID in a structured field or using a more robust marker.

♻️ Alternative: Use blocker metadata or a dedicated field

If the blocker system supports metadata, store session info there:

# In pause_discovery:
blocker = blockers.create(
    self.workspace,
    question=f"Discovery session paused: {reason}",
    task_id=None,
    metadata={"type": "discovery", "session_id": self.session_id}
)

# In resume_discovery:
if blocker.metadata.get("type") != "discovery":
    raise ValueError("Blocker is not a discovery session blocker")
session_id = blocker.metadata.get("session_id")

If metadata isn't available, at minimum use a more specific marker string (e.g., [DISCOVERY_SESSION:uuid]) that's less likely to collide.

frankbria and others added 2 commits January 29, 2026 14:24
Co-authored-by: macroscopeapp[bot] <170038800+macroscopeapp[bot]@users.noreply.github.com>
…ssion

When ANTHROPIC_API_KEY is missing but a session exists, now logs a
warning and raises NoApiKeyError instead of returning None. This allows
callers to distinguish between "no session exists" and "session could
not be loaded due to missing API key".
@claude
Copy link

claude bot commented Jan 29, 2026

Final Consolidated Review - PR #317

Based on reviewing all commits and previous feedback iterations, here's my final assessment:


Overall Status: APPROVED - Ready to Merge

This PR successfully implements AI-native PRD discovery through the cf prd generate command. The implementation exemplifies v2 architectural principles and directly advances Phase 1: CLI Completion.


🎯 What Changed Across Iterations

Initial Implementation (commits 8f257b1 - 42049d6)

  • Hybrid AI + static fallback approach
  • Fixed question count (5 required questions)
  • /skip command mentioned but not implemented

Evolution to AI-Native (commit eda4af4)

  • Fully AI-driven: No static question fallback
  • Coverage-based completion: Dynamic progress based on semantic assessment
  • Question tax: AI only asks if answer adds value to PRD
  • Removed confusing /skip references from documentation

Bug Fixes (commit 2169955)

  • CRITICAL FIX: Removed destructive DROP TABLE that would delete saved sessions
  • Saved session after opening question generation (enables early exit resume)
  • Cleaned up documentation consistency

Latest (commit bbdd8c1)

  • Improved error handling with explicit NoApiKeyError

Architecture Compliance

Perfect adherence to v2 principles from CLAUDE.md:

Requirement Status Evidence
Headless core prd_discovery.py has zero FastAPI/HTTP imports
CLI-first Works without server, pure Golden Path
Core isolation Business logic in core/, presentation in cli/
State persistence SQLite storage with proper schema management
Event emission Emits PRD_ADDED event on completion

🧪 Test Coverage: Excellent

  • 29 total tests (18 unit + 11 CLI integration)
  • Comprehensive coverage of:
    • Session lifecycle (start → pause → resume → complete)
    • AI question generation and validation
    • Coverage assessment logic
    • Error conditions and edge cases
    • CLI user interactions with special commands
  • Proper mocking of LLM provider for deterministic tests

🏆 Key Strengths

  1. AI-Native Design: The decision to make this fully AI-driven (no static fallback) is architecturally sound

    • More flexible than fixed question lists
    • Better user experience (conversational vs. form-filling)
    • Aligns with product vision
  2. Coverage-Based Completion: Semantic assessment of 5 categories with thresholds

    • Prevents trivial PRDs (requires sufficient depth)
    • Prevents over-questioning (stops when coverage adequate)
    • Transparent progress tracking for users
  3. Pause/Resume via Blockers: Elegant reuse of existing blocker system

    • Consistent with existing patterns
    • Human-in-the-loop when user needs to research answers
    • Clean state persistence
  4. Error Handling: Comprehensive and user-friendly

    • NoApiKeyError when LLM unavailable
    • ValidationError for invalid inputs
    • IncompleteSessionError for premature PRD generation

📊 Code Quality Metrics

Metric Score Notes
Architecture 10/10 Textbook headless, CLI-first implementation
Test Coverage 9/10 Comprehensive unit + integration tests
Documentation 9/10 Clear docstrings, good command help
Error Handling 9/10 Proper exceptions, informative messages
Type Safety 8/10 Good annotations, minor room for improvement

🔍 Minor Items for Future Enhancement (Non-Blocking)

These are not merge requirements, just observations for future work:

  1. Type Annotation: _llm_provider: Any could be Optional[AnthropicProvider]
  2. Session ID Parsing: Regex parsing from blocker text works, but structured metadata would be more robust
  3. Title Generation: Currently extracts from problem description - could use LLM for better titles
  4. Migration Tracking: CREATE TABLE IF NOT EXISTS is adequate now, but consider version tracking for future schema changes

🚀 Impact Assessment

Closes: #307 (Interactive PRD discovery)
Advances: Phase 1 - CLI Completion (v2 Strategic Roadmap)
Enables: Full Golden Path workflow (PRD → Tasks → Execution)
User Value: Significantly lowers friction for project initialization


Final Recommendation

LGTM - Ready to Merge 🎉

This PR represents high-quality implementation that:

  • Follows all architectural guidelines from CLAUDE.md
  • Has no blocking issues or security concerns
  • Provides genuine user value
  • Is well-tested and documented
  • Advances strategic roadmap objectives

The AI-native approach is the right architectural choice for this feature. Great work!


Reviewed by: Claude Sonnet 4.5
Review date: 2026-01-29
Commits reviewed: 8f257b1, 42049d6, eda4af4, 2169955, bbdd8c1

@claude
Copy link

claude bot commented Jan 29, 2026

✅ Final Confirmation - PR Ready to Merge

I have completed a comprehensive review of all commits in this PR. All previously identified issues have been successfully addressed.

Summary of Resolved Issues

  1. ✅ FIXED: Removed destructive DROP TABLE (Critical)

    • The dangerous DROP TABLE IF EXISTS discovery_sessions has been removed
    • Now uses safe CREATE TABLE IF NOT EXISTS pattern
    • Session persistence and resume functionality protected
  2. ✅ FIXED: Opening question persistence (Medium Priority)

    • Session now saves after generating opening question
    • Resume works correctly even if user exits immediately
  3. ✅ FIXED: Documentation accuracy (Medium Priority)

    • Removed non-existent /skip command from PR description
    • Documentation now accurately reflects implemented features

Architecture Assessment ✅

v2 Compliance - Perfect:

  • ✅ Headless core (zero FastAPI/HTTP dependencies)
  • ✅ CLI-first (no server required)
  • ✅ Proper event emission (PRD_ADDED)
  • ✅ State persistence via SQLite
  • ✅ Clean separation: core logic vs CLI presentation

Code Quality - Excellent:

  • ✅ 29 comprehensive tests (18 unit + 11 CLI integration)
  • ✅ AI-native design (LLM drives entire flow)
  • ✅ Smart coverage-based completion (not arbitrary question count)
  • ✅ Proper error handling with custom exceptions
  • ✅ Clean state machine via SessionState enum

Database Design - Solid:

  • ✅ Idempotent schema creation
  • ✅ Proper indexes on workspace_id and state
  • ✅ JSON storage for flexible Q&A history
  • ✅ Foreign key relationships maintained

Remaining Observations (Non-Blocking)

These are suggestions for future enhancement, not merge requirements:

  1. Session ID parsing from blocker text (lines 558-590)

    • Works correctly but could be more robust with structured metadata
    • Current regex parsing is adequate for MVP
  2. Type annotation for _llm_provider (line 479)

    • Uses Any type - could use Optional[AnthropicProvider] for stricter typing
    • Not a blocker

Highlights 🎉

This PR exemplifies excellent v2 implementation:

  • True AI-native: No static fallbacks - LLM drives everything
  • Coverage scoring: Semantic assessment (not arbitrary counts)
  • Question tax concept: AI only asks if answer improves PRD
  • Elegant pause/resume: Reuses existing blocker system
  • Comprehensive testing: Full unit + integration coverage with proper mocking

Final Verdict

Status: ✅ APPROVED - READY TO MERGE

Ratings:

  • Code Quality: 9/10
  • Architecture Alignment: 10/10
  • Test Coverage: 9/10
  • Documentation: 9/10

This feature directly advances Phase 1: CLI Completion from the V2 Strategic Roadmap and properly closes issue #307.

Excellent work! 🚀


Reviewed by: Claude Sonnet 4.5
Commits reviewed: 8f257b1, 42049d6, eda4af4, 2169955
Date: 2026-01-29

Comment on lines +1176 to +1177
session = active
console.print("[green]✓[/green] Resuming previous session")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Low

When auto-resuming an active session at line 1176, consider calling session.state = SessionState.DISCOVERING (and session._save_session()) to match the behavior of resume_discovery(). Currently the PAUSED state persists to the database.

-                        session = active
-                        console.print("[green]✓[/green] Resuming previous session")
+                        session = active
+                        session.state = SessionState.DISCOVERING
+                        session._save_session()
+                        console.print("[green]✓[/green] Resuming previous session")

🚀 Want me to fix this? Reply ex: "fix it for me".

@frankbria frankbria merged commit 33429ab into main Jan 29, 2026
14 checks passed
@frankbria frankbria deleted the feature/prd-generate branch January 29, 2026 21:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Phase 1] cf prd generate - Interactive AI PRD creation (Socratic Discovery)

2 participants