35 KiB
description, argument-hint, allowed-tools, model
| description | argument-hint | allowed-tools | model |
|---|---|---|---|
| Review story and create PR with all committed tasks | [STORY-ID or PATH] | Read, Bash, Task | claude-haiku-4-5-20251001 |
Story Review Command
<command_purpose> Review entire user story implementation and create single PR if all tasks are approved. </command_purpose>
Introduction
Senior Story Review Architect with expertise in user story validation, acceptance criteria verification, and pull request automation
Prerequisites
- Git repository with story start tag (e.g., `story/US-3.4-start`) - All tasks completed and tagged (e.g., `task/TASK-1.1-committed`) - GitHub CLI (`gh`) installed and authenticated - Story directory structure: `./project-management/US-STORY/US-X.Y-name/` - Valid US-story.md file with all task references - Clean working directory (no uncommitted changes)Input Variables
<story_file>$ARGUMENTS</story_file>
<base_branch> Default: "main" Can be overridden with: --base develop </base_branch>
<draft_mode> Default: "false" Set to "true" with: --draft true </draft_mode>
Memory Graph Usage (Auto)
As you review a story, persist durable outcomes discovered in files and commit summaries:
- Use
mcp__memory__search_nodes→create_entities/add_observations→create_relationsto record owners, endpoints, repo links, and key decisions (dated). The UserPromptSubmit and PostToolUse hooks auto-hint when these signals are detected. See.claude/skills/memory-graph/.
Main Tasks
<critical_requirements> KEY REQUIREMENTS:
- Each completed US (user story) = 1 PR (not per task)
- If review FAILS → Generate detailed REPORT file
- Review against project standards AND enterprise guidelines
- Use reviewer-story agent via Task tool
- Parse agent JSON output programmatically
- APPROVED → Auto-create PR with comprehensive body
- CHANGES_REQUIRED → Generate US-X.Y-REVIEW-REPORT.md with fix guidance </critical_requirements>
Step 1: Load and Validate Story File
<critical_requirement> MUST validate story file exists and contains all required sections before proceeding. </critical_requirement>
<validation_tasks>
- Check USER-STORY.md exists at provided path
- Verify file contains required sections:
-
User Story
-
Acceptance Criteria
-
Technical Requirements
-
Tasks
-
- Parse all task references (TASK-X.Y format)
- Collect story metadata (ID, title, description) </validation_tasks>
Load Story File
# Parse input - can be story ID (US-X.Y) or full path
story_input="$ARGUMENTS"
# Check if input is story ID format (US-X.Y)
if [[ "$story_input" =~ ^US-[0-9]+\.[0-9]+$ ]]; then
# Find story directory
story_dir=$(find ./project-management/US-STORY -name "${story_input}-*" -type d 2>/dev/null | head -1)
if [[ -z "$story_dir" ]]; then
echo "❌ Error: Story ${story_input} not found"
echo ""
echo "Available stories:"
ls -1d ./project-management/US-STORY/US-*/ 2>/dev/null || echo " (no stories found)"
echo ""
echo "Usage: /lazy story-review US-X.Y"
echo " or: /lazy story-review ./project-management/US-STORY/US-X.Y-name/US-story.md"
exit 1
fi
story_file="${story_dir}/US-story.md"
tasks_dir="${story_dir}/TASKS"
story_id=$(basename "$story_dir" | grep -oP '^US-\d+\.\d+')
else
# Assume it's a full path to US-story.md
story_file="$story_input"
# Validate story file exists
if [ ! -f "$story_file" ]; then
echo "❌ Error: Story file not found: $story_file"
echo ""
echo "Usage: /lazy story-review US-X.Y"
echo " or: /lazy story-review ./project-management/US-STORY/US-X.Y-name/US-story.md"
exit 1
fi
story_dir=$(dirname "$story_file")
tasks_dir="${story_dir}/TASKS"
story_id=$(basename "$story_dir" | grep -oP '^US-\d+\.\d+')
fi
# Validate tasks directory exists
if [ ! -d "$tasks_dir" ]; then
echo "❌ Error: Tasks directory not found: $tasks_dir"
echo "Story directory may be corrupt"
echo "Run /lazy create-feature to regenerate"
exit 1
fi
# Read story content
story_content=$(cat "$story_file")
story_title=$(grep -m1 "^# " "$story_file" | sed 's/^# //')
# Extract GitHub issue number from story file
story_github_issue=$(grep "GitHub Issue: #" "$story_file" | sed 's/.*#//' | head -1)
Step 2: Verify Story State with Git Tags
<critical_requirement> Use git tags to track story and task completion state. All tasks must be committed before review. </critical_requirement>
<state_verification> Story review uses git tags for state management:
Story Start Tag:
# Created by /lazy create-feature
git tag story/oauth2-start
Task Completion Tags:
# Created by /lazy task-exec after each task
git tag task/TASK-1.1-committed
git tag task/TASK-1.2-committed
git tag task/TASK-1.3-committed
Verification:
# Get all task tags
task_tags=$(git tag -l 'task/*-committed')
# Get story start tag
story_start=$(git tag -l 'story/*-start' | tail -1)
# Verify story start exists
if [ -z "$story_start" ]; then
echo "❌ Error: No story start tag found"
echo "Expected: story/{story-id}-start"
exit 1
fi
</state_verification>
Collect Task Tags
<task_collection>
- Get all task files from TASKS directory
- Get all task tags:
git tag -l 'task/*-committed' - Parse task IDs from tags (extract TASK-X.Y)
- Verify all tasks are committed
- Extract GitHub issue numbers from task files
- Block review if any task is incomplete </task_collection>
# Collect all task files
task_files=$(ls ${tasks_dir}/TASK-*.md 2>/dev/null)
if [[ -z "$task_files" ]]; then
echo "❌ Error: No task files found in ${tasks_dir}"
echo "Story directory may be corrupt"
exit 1
fi
# Collect committed and pending tasks
committed_tasks=()
pending_tasks=()
task_github_issues=()
for task_file in $task_files; do
task_id=$(basename "$task_file" .md) # e.g., TASK-1.1
# Check if task is committed (git tag)
if git tag | grep -q "task/${task_id}-committed"; then
committed_tasks+=("$task_id")
# Extract GitHub issue number if present
github_issue=$(grep "GitHub Issue: #" "$task_file" | sed 's/.*#//' | head -1)
if [[ -n "$github_issue" ]]; then
task_github_issues+=("$task_id:$github_issue")
fi
else
pending_tasks+=("$task_id")
fi
done
# Verify all tasks are committed
if [[ ${#pending_tasks[@]} -gt 0 ]]; then
echo "❌ Error: Not all tasks are committed"
echo ""
echo "Pending tasks:"
for task in "${pending_tasks[@]}"; do
echo " - $task"
done
echo ""
echo "Next steps:"
echo " 1. Complete missing tasks: /lazy task-exec <TASK-ID>"
echo " 2. Re-run story review: /lazy story-review ${story_id}"
exit 1
fi
echo "✅ All ${#committed_tasks[@]} tasks are committed"
Step 3: Collect All Commits Since Story Start
<commit_collection> Get all commits between story start and current HEAD to include in PR. </commit_collection>
# Get commits since story start
commits=$(git log "$story_start"..HEAD --oneline)
commit_count=$(echo "$commits" | wc -l)
# Verify there are commits
if [ $commit_count -eq 0 ]; then
echo "❌ Error: No commits found since story start"
echo "Story start: $story_start"
exit 1
fi
echo "📊 Found $commit_count commits since $story_start"
Step 4: Collect Task Implementations
<implementation_collection> For each completed task, collect:
- Task file content from TASKS directory
- Implementation files (from git diff)
- Test results (if available)
- GitHub issue links </implementation_collection>
# For each task, collect implementation details
all_tasks_summary=""
for task_file in $task_files; do
task_id=$(basename "$task_file" .md)
task_title=$(grep -m1 "^# " "$task_file" | sed 's/^# //')
task_gh_issue=$(grep "GitHub Issue: #" "$task_file" | sed 's/.*#//' | head -1)
# Get files changed in task commits (approximate by commit messages)
task_commits=$(git log "$story_start"..HEAD --oneline --grep="$task_id")
commit_count=$(echo "$task_commits" | wc -l)
# Collect for review
all_tasks_summary="${all_tasks_summary}\n${task_id}: ${task_title}"
if [[ -n "$task_gh_issue" ]]; then
all_tasks_summary="${all_tasks_summary} (GH Issue #${task_gh_issue})"
fi
all_tasks_summary="${all_tasks_summary}\n Commits: ${commit_count}"
done
echo -e "📋 Task Summary:${all_tasks_summary}"
Step 5: Run Test Suite (if tests exist)
<test_execution> Run project tests if test runner is available. </test_execution>
# Detect test framework and run tests
test_results=""
if [ -f "pytest.ini" ] || [ -f "pyproject.toml" ]; then
echo "🧪 Running pytest..."
test_results=$(pytest --tb=short 2>&1 || true)
elif [ -f "package.json" ]; then
if grep -q '"test"' package.json; then
echo "🧪 Running npm test..."
test_results=$(npm test 2>&1 || true)
fi
fi
Step 6: Load Enterprise Standards
<standards_loading> Load project and enterprise standards for compliance checking. </standards_loading>
# Collect all applicable standards
standards_content=""
# 1. Load CLAUDE.md (project standards)
if [ -f "CLAUDE.md" ]; then
echo "📋 Loading project standards from CLAUDE.md..."
standards_content="${standards_content}\n## Project Standards (CLAUDE.md)\n\n"
standards_content="${standards_content}$(cat CLAUDE.md)"
fi
# 2. Load README.md (architecture decisions)
if [ -f "README.md" ]; then
echo "📋 Loading architecture decisions from README.md..."
standards_content="${standards_content}\n## Architecture Decisions (README.md)\n\n"
standards_content="${standards_content}$(cat README.md)"
fi
# 3. Load CONTRIBUTING.md (code standards)
if [ -f ".github/CONTRIBUTING.md" ]; then
echo "📋 Loading code standards from .github/CONTRIBUTING.md..."
standards_content="${standards_content}\n## Code Standards (CONTRIBUTING.md)\n\n"
standards_content="${standards_content}$(cat .github/CONTRIBUTING.md)"
elif [ -f "CONTRIBUTING.md" ]; then
echo "📋 Loading code standards from CONTRIBUTING.md..."
standards_content="${standards_content}\n## Code Standards (CONTRIBUTING.md)\n\n"
standards_content="${standards_content}$(cat CONTRIBUTING.md)"
fi
# 4. Load custom enterprise guidelines (if configured)
enterprise_standards_path="${LAZY_DEV_ENTERPRISE_STANDARDS:-}"
if [ -n "$enterprise_standards_path" ] && [ -f "$enterprise_standards_path" ]; then
echo "📋 Loading enterprise standards from ${enterprise_standards_path}..."
standards_content="${standards_content}\n## Enterprise Guidelines\n\n"
standards_content="${standards_content}$(cat "$enterprise_standards_path")"
fi
# If no standards found, use defaults
if [ -z "$standards_content" ]; then
echo "⚠️ No standards files found - using LAZY-DEV defaults"
standards_content="## Default Standards\n\n- Test coverage >80%\n- Type hints required\n- Documentation required for public APIs\n- OWASP Top 10 security compliance"
fi
echo "✅ Standards loaded successfully"
Step 7: Invoke Story Review Agent
<critical_requirement> Invoke the Story Review Agent via Task tool with complete context including enterprise standards. </critical_requirement>
<agent_invocation> The agent receives all story context, implementation details, and compliance standards. Agent output format is JSON for programmatic processing. </agent_invocation>
# Prepare context for agent
echo "🤖 Invoking Story Review Agent..."
# Read full story content
story_content_full=$(cat "$story_file")
# Get all task file contents
tasks_content=""
for task_file in $task_files; do
task_id=$(basename "$task_file" .md)
tasks_content="${tasks_content}\n### ${task_id}\n\n$(cat "$task_file")\n"
done
# Get git diff stats
files_changed=$(git diff --stat "$story_start"..HEAD)
files_changed_list=$(git diff --name-only "$story_start"..HEAD)
# Get test coverage if available
coverage_result=""
if command -v pytest &> /dev/null; then
coverage_result=$(pytest --cov --cov-report=term-missing 2>&1 || true)
fi
# Store agent context in temporary file for Task tool
cat > /tmp/story_review_context.md <<EOF
You are reviewing Story: ${story_id}
Story Title: ${story_title}
Story File: ${story_file}
Tasks Directory: ${tasks_dir}
Branch: $(git branch --show-current)
## Story Content
${story_content_full}
## All Tasks
${tasks_content}
## Commits (${commit_count} total)
${commits}
## Files Changed ($(echo "$files_changed_list" | wc -l) files)
${files_changed}
## Test Results
${test_results}
${coverage_result}
## Project Standards
${standards_content}
## Review Instructions
You MUST review against:
1. All acceptance criteria in the story file
2. Project standards from CLAUDE.md
3. Enterprise guidelines (if provided)
4. OWASP Top 10 security standards
5. Test coverage requirements (>80%)
6. Integration quality between all tasks
Return JSON output as specified in reviewer-story.md agent template.
EOF
echo "📄 Context prepared: /tmp/story_review_context.md"
Invoke reviewer-story agent now:
Use the Task tool to invoke .claude/agents/reviewer-story.md with the following variable substitutions:
story_id: ${story_id}story_file: ${story_file}tasks_dir: ${tasks_dir}branch_name: $(git branch --show-current)standards: ${standards_content}
The agent will analyze all context and return JSON output with status field of either "APPROVED" or "REQUEST_CHANGES".
Step 8: Process Review Results
<review_processing> Parse JSON output from reviewer-story agent and take appropriate action. </review_processing>
# Agent returns JSON - parse the status field
agent_status=$(echo "$agent_output" | jq -r '.status' 2>/dev/null || echo "UNKNOWN")
if [ "$agent_status" = "APPROVED" ]; then
echo "✅ Story review APPROVED"
echo ""
# Extract summary from agent output
agent_summary=$(echo "$agent_output" | jq -r '.summary' 2>/dev/null || echo "All checks passed")
echo "📋 Summary: ${agent_summary}"
echo ""
# Proceed to Step 9 (PR creation)
elif [ "$agent_status" = "REQUEST_CHANGES" ]; then
echo "❌ Story review FAILED - Changes Required"
echo ""
# Generate detailed review report
report_file="${story_dir}/${story_id}-review-report.md"
echo "📝 Generating review report: ${report_file}"
# Extract data from agent JSON output
agent_summary=$(echo "$agent_output" | jq -r '.summary' 2>/dev/null || echo "Review found issues")
# Count issues by severity
critical_count=$(echo "$agent_output" | jq '[.issues[] | select(.severity == "CRITICAL")] | length' 2>/dev/null || echo "0")
warning_count=$(echo "$agent_output" | jq '[.issues[] | select(.severity == "WARNING")] | length' 2>/dev/null || echo "0")
suggestion_count=$(echo "$agent_output" | jq '[.issues[] | select(.severity == "SUGGESTION")] | length' 2>/dev/null || echo "0")
total_issues=$((critical_count + warning_count + suggestion_count))
# Get task status summary
tasks_passed=$(echo "$agent_output" | jq '[.tasks_status[] | select(.status == "passed")] | length' 2>/dev/null || echo "0")
tasks_total=$(echo "$agent_output" | jq '.tasks_status | length' 2>/dev/null || echo "0")
# Generate comprehensive report
cat > "$report_file" <<REPORT_EOF
# Story Review Report: ${story_id}
**Status**: ❌ FAILED
**Reviewed**: $(date +"%Y-%m-%d %H:%M")
**Tasks**: ${tasks_passed}/${tasks_total} passed
## Summary
${total_issues} issues found preventing PR creation.
${agent_summary}
## Issues Found
$(echo "$agent_output" | jq -r '
if .issues and (.issues | length > 0) then
.issues | to_entries | map(
"### " + ((.key + 1) | tostring) + ". " +
(if .value.type then (.value.type | gsub("_"; " ") | ascii_upcase) else "Issue" end) +
" (" + (.value.file // "N/A") +
(if .value.line then ":" + (.value.line | tostring) else "" end) + ")\n" +
"- **Type**: " + (.value.type // "unknown") + "\n" +
"- **File**: " + (.value.file // "N/A") +
(if .value.line then ":" + (.value.line | tostring) else "" end) + "\n" +
"- **Issue**: " + .value.description + "\n" +
"- **Fix**: " + .value.fix + "\n"
) | join("\n")
else
"No specific issues documented."
end
')
## Tasks Status
$(echo "$agent_output" | jq -r '
if .tasks_status and (.tasks_status | length > 0) then
.tasks_status | map(
"- " + .task_id + ": " +
(if .status == "passed" then "✅ Passed"
elif .status == "failed" then "❌ Failed (" + (.issues_count | tostring) + " issues)"
elif .status == "warning" then "⚠️ Warning (" + (.issues_count | tostring) + " issues)"
else "⚠️ " + .status
end)
) | join("\n")
else
"- No task status available"
end
')
## Next Steps
Run: \`/lazy fix ${report_file}\`
Or manually fix and re-run: \`/lazy review @${story_file}\`
REPORT_EOF
echo "✅ Review report generated: ${report_file}"
echo ""
echo "Found:"
echo " - ${critical_count} CRITICAL issues"
echo " - ${warning_count} WARNING issues"
echo " - ${suggestion_count} SUGGESTIONS"
echo ""
echo "Next steps:"
echo " 1. Review report: cat ${report_file}"
echo " 2. Fix issues: /lazy fix ${report_file}"
echo " 3. Re-run review: /lazy review ${story_id}"
echo ""
# Exit with status 1 to indicate failure
exit 1
else
echo "❌ Error: Unknown review status from agent: ${agent_status}"
echo "Agent output:"
echo "$agent_output"
exit 1
fi
Step 9: Create Pull Request (If APPROVED)
<pr_creation> If review is approved, create a single PR containing all story commits with comprehensive summary. </pr_creation>
<pr_requirements>
- One PR per user story (not per task)
- Includes all commits since story start tag
- References all task GitHub issues
- Includes test results and quality metrics
- Auto-closes related GitHub issues </pr_requirements>
Prepare PR Body
# Generate comprehensive PR body
echo "📝 Generating PR body..."
# Extract test coverage percentage
test_coverage=$(echo "$coverage_result" | grep "^TOTAL" | awk '{print $NF}' || echo "N/A")
# Get acceptance criteria status
acceptance_criteria_list=$(cat "$story_file" | sed -n '/## Acceptance Criteria/,/##/p' | grep -E "^-.*" | sed 's/^- /✓ /')
# Extract agent summary
pr_summary=$(echo "$agent_output" | jq -r '.summary' 2>/dev/null || echo "Story implementation completed and reviewed")
cat > pr_body.md <<'PR_BODY'
# [FEATURE] ${story_title}
**Story ID**: ${story_id}
**Directory**: `${story_dir}`
$(if [[ -n "$story_github_issue" ]]; then echo "**GitHub Issue**: Closes #${story_github_issue}"; fi)
---
## Summary
${pr_summary}
---
## User Story
$(cat "${story_file}" | sed -n '/## User Story/,/##/p' | tail -n +2 | head -n -1)
---
## Acceptance Criteria
$(echo "$acceptance_criteria_list" | sed 's/^/✓ /')
---
## Tasks Completed
$(for task_file in ${tasks_dir}/TASK-*.md; do
task_id=$(basename "$task_file" .md)
task_title=$(grep "^# " "$task_file" | head -1 | sed 's/^# //')
task_gh_issue=$(grep "GitHub Issue: #" "$task_file" | sed 's/.*#//' | head -1)
if [[ -n "$task_gh_issue" ]]; then
echo "✓ [${task_id}] ${task_title} - Closes #${task_gh_issue}"
else
echo "✓ [${task_id}] ${task_title}"
fi
done)
---
## Commits
\`\`\`
$(git log --oneline ${story_start}..HEAD)
\`\`\`
**Total Commits**: ${commit_count}
---
## Quality Metrics
| Metric | Value |
|--------|-------|
| Files Changed | $(git diff --name-only "$story_start"..HEAD | wc -l) |
| Lines Added | $(git diff --stat "$story_start"..HEAD | tail -1 | grep -oP '\d+(?= insertion)' || echo "0") |
| Lines Removed | $(git diff --stat "$story_start"..HEAD | tail -1 | grep -oP '\d+(?= deletion)' || echo "0") |
| Test Coverage | ${test_coverage} |
| Tests Passing | $(echo "$test_results" | grep -oP '\d+(?= passed)' || echo "All") |
---
## Testing
\`\`\`
${test_results:-No tests run}
\`\`\`
$(if [[ -n "$coverage_result" ]]; then
echo "### Coverage Report"
echo "\`\`\`"
echo "$coverage_result" | head -20
echo "\`\`\`"
fi)
---
## Compliance & Quality Checks
### Story Review
✅ **APPROVED** by reviewer-story agent
### Project Standards
✅ Compliant with CLAUDE.md requirements
✅ Follows project architecture patterns
### Enterprise Guidelines
$(if [[ -n "$enterprise_standards_path" ]]; then
echo "✅ Compliant with enterprise standards: \`${enterprise_standards_path}\`"
else
echo "✅ Compliant with LAZY-DEV framework defaults"
fi)
### Security
✅ OWASP Top 10 compliance verified
✅ No security vulnerabilities detected
✅ Input validation implemented
✅ Authentication/authorization reviewed
### Code Quality
✅ Format: PASS (Black/Ruff)
✅ Lint: PASS (Ruff)
✅ Type: PASS (Mypy)
✅ Tests: PASS (Pytest)
### Documentation
✅ Public APIs documented
✅ README updated (if applicable)
✅ Inline comments for complex logic
---
## Integration Status
✅ All tasks integrate cohesively
✅ No conflicts between task implementations
✅ Data flows correctly between components
✅ No breaking changes to existing functionality
---
## Reviewer Notes
**Review Method**: LAZY-DEV-FRAMEWORK automated story review
**Review Agent**: `.claude/agents/reviewer-story.md`
**Review Date**: $(date -u +"%Y-%m-%d %H:%M:%S UTC")
**Summary**: ${pr_summary}
**Strengths**:
$(echo "$agent_output" | jq -r '.strengths // [] | if length > 0 then map("- " + .) | join("\n") else "- Comprehensive implementation\n- Strong test coverage\n- Clean code quality" end' 2>/dev/null || echo "- High-quality implementation")
---
## Related Issues
$(if [[ -n "$story_github_issue" ]]; then
echo "- Story: #${story_github_issue}"
fi)
$(for task_file in ${tasks_dir}/TASK-*.md; do
task_gh_issue=$(grep "GitHub Issue: #" "$task_file" | sed 's/.*#//' | head -1)
if [[ -n "$task_gh_issue" ]]; then
task_id=$(basename "$task_file" .md)
echo "- Task ${task_id}: #${task_gh_issue}"
fi
done)
---
🤖 Generated with [Claude Code](https://claude.com/claude-code) LAZY-DEV-FRAMEWORK
**Story**: ${story_id}
**Directory**: ${story_dir}
**Framework**: LAZY-DEV v1.0.0-alpha
PR_BODY
# Expand variables in PR body
eval "cat <<'EXPAND_PR_BODY' > pr_body_final.md
$(cat pr_body.md)
EXPAND_PR_BODY"
echo "✅ PR body generated: pr_body_final.md"
Create PR with gh CLI
# Determine if draft mode
draft_flag=""
if [ "$draft_mode" = "true" ]; then
draft_flag="--draft"
fi
# Create PR
echo "📦 Creating pull request..."
pr_url=$(gh pr create \
--title "[FEATURE] $story_title" \
--body-file pr_body_final.md \
--base "$base_branch" \
--label "story,automated,reviewed,story:$story_id" \
$draft_flag)
# Verify PR creation
if [ $? -eq 0 ]; then
# Get PR number
pr_number=$(gh pr list --head "$(git branch --show-current)" --json number --jq '.[0].number')
echo "✅ PR Created: $pr_url"
echo ""
echo "📁 Story: ${story_id}"
echo " Directory: ${story_dir}"
echo ""
echo "📦 PR Details:"
echo " Number: #${pr_number}"
echo " Title: [STORY] $story_title"
echo " Base: $base_branch"
echo " Commits: $commit_count"
echo ""
# Close GitHub issues
echo "🔗 Closing GitHub Issues:"
# Close main story issue
if [[ -n "$story_github_issue" ]]; then
gh issue close $story_github_issue --reason completed \
--comment "Completed in PR #${pr_number}" 2>/dev/null
if [ $? -eq 0 ]; then
echo " ✅ #${story_github_issue} - [STORY] ${story_title}"
fi
fi
# Close all task issues
for task_file in ${tasks_dir}/TASK-*.md; do
task_id=$(basename "$task_file" .md)
task_title=$(grep "^# " "$task_file" | head -1 | sed 's/^# //')
task_gh_issue=$(grep "GitHub Issue: #" "$task_file" | sed 's/.*#//' | head -1)
if [[ -n "$task_gh_issue" ]]; then
gh issue close $task_gh_issue --reason completed \
--comment "Completed in PR #${pr_number}" 2>/dev/null
if [ $? -eq 0 ]; then
echo " ✅ #${task_gh_issue} - [${task_id}] ${task_title}"
fi
fi
done
echo ""
echo "✅ All related issues closed"
echo "✅ Ready for merge"
else
echo "❌ Error: Failed to create PR"
echo "Check: gh auth status"
exit 1
fi
Parallelization During Review
While the story review is running or after it completes, you can run other commands in parallel if they are independent.Commands That Can Run in Parallel
During Review (While Waiting for Agent):
# 1. Cleanup unused code (runs on current branch)
/lazy cleanup --scope feature/US-X.Y
# 2. Generate documentation for the story
/lazy documentation --scope US-X.Y
# 3. Check memory graph for this story's entities
/lazy memory-check US-X.Y
After Review Approval (Before PR Merge):
# 1. Start work on next independent story
/lazy create-feature "Next feature brief"
# 2. Update project documentation
/lazy documentation --scope project
# 3. Run refactoring on completed work
/lazy refactor --scope US-X.Y
Commands That CANNOT Run in Parallel
Blocked Until Review Completes:
# ❌ Cannot run another story review simultaneously
/lazy story-review US-Y.Z # Wait for current review to finish
# ❌ Cannot re-execute tasks in the story being reviewed
/lazy task-exec TASK-X.Y # Wait until review fails or make changes after PR
# ❌ Cannot fix review issues until report is generated
/lazy story-fix-review US-X.Y-REVIEW-REPORT.md # Only after review fails
Recommended Workflow
Optimal Parallelization:
# Terminal 1: Run story review
/lazy story-review US-3.4
# Terminal 2: While review is running, cleanup and document in parallel
/lazy cleanup --scope feature/US-3.4
/lazy documentation --scope US-3.4
# If review APPROVED:
# - PR is created automatically
# - GitHub issues are closed
# - Ready to start next story
# If review FAILED:
# - Fix issues: /lazy story-fix-review US-3.4-REVIEW-REPORT.md
# - Re-run: /lazy story-review US-3.4
Integration with Other Commands
Workflow Integration
Complete Story Lifecycle:
1. /lazy create-feature "Brief"
↓
Creates: US-X.Y-name/US-story.md
Creates: TASKS/TASK-*.md
Creates: GitHub issues
Sets tag: story/US-X.Y-start
2. /lazy task-exec TASK-1.1
/lazy task-exec TASK-1.2
/lazy task-exec TASK-1.3
↓
Each sets tag: task/TASK-X.Y-committed
Each implements and tests feature
3. /lazy story-review US-X.Y ← THIS COMMAND
↓
Loads: All tasks, commits, standards
Invokes: reviewer-story agent
If APPROVED:
↓
Creates: PR with full context
Closes: All GitHub issues
If CHANGES_REQUIRED:
↓
Creates: US-X.Y-REVIEW-REPORT.md
Outputs: Fix guidance
4. If changes needed:
/lazy story-fix-review US-X.Y-REVIEW-REPORT.md
↓
Routes issues to appropriate agents
Fixes critical/warning issues
Then re-run:
/lazy story-review US-X.Y
5. After PR merge:
/lazy cleanup --scope US-X.Y
/lazy documentation --scope US-X.Y
Command Dependencies
story-review depends on:
/lazy create-feature(creates story structure)/lazy task-exec(completes all tasks)- Git tags:
story/*-start,task/*-committed - GitHub CLI:
ghauthenticated
Commands that depend on story-review:
/lazy story-fix-review(processes review report)- Subsequent
/lazy story-reviewruns (after fixes)
Independent parallel commands:
/lazy cleanup(code cleanup)/lazy documentation(docs generation)/lazy memory-check(graph queries)/lazy create-feature(new independent story)
Error Handling & Recovery
Error: Story file not found
❌ Error: Story US-3.4 not found
Available stories:
./project-management/US-STORY/US-1.1-user-authentication/
./project-management/US-STORY/US-2.3-payment-integration/
Usage: /lazy story-review US-X.Y
or: /lazy story-review ./project-management/US-STORY/US-X.Y-name/US-story.md
Recovery:
1. Check story ID: ls ./project-management/US-STORY/
2. Use correct story ID: /lazy story-review US-1.1
3. Or use full path to US-story.md
Error: Task tags missing
❌ Error: Not all tasks are committed
Pending tasks:
- TASK-1.2
- TASK-1.3
Next steps:
1. Run git tag -l 'task/*' to see completed tasks
2. Execute missing tasks: /lazy task-exec TASK-1.2
3. Retry: /lazy story-review US-3.4
Error: Story start tag missing
❌ Error: No story start tag found
Expected: story/US-X.Y-start
Recovery:
1. Check if create-feature was run: git tag -l 'story/*'
2. Create tag manually: git tag story/US-3.4-start $(git log --reverse --oneline | head -1 | cut -d' ' -f1)
3. Retry: /lazy story-review US-3.4
Error: No commits found
❌ Error: No commits found since story start
Story start: story/oauth2-start
Recovery:
1. Verify story tag: git log story/oauth2-start
2. Check current branch: git branch --show-current
3. Ensure tasks were committed (not just completed)
Error: Review changes needed
⚠️ Story review needs changes:
Critical Issues:
- TASK-1.3 validation: Missing edge case for declined cards
Location: src/payments/validator.py:45
Impact: Invalid cards may be processed
Next steps:
1. Fix validation in TASK-1.3
2. Re-run: /lazy task-exec TASK-1.3
3. Re-review: /lazy story-review US-3.4
Error: Tasks directory not found
❌ Error: Tasks directory not found: ./project-management/US-STORY/US-3.4-oauth2/TASKS
Story directory may be corrupt
Run /lazy create-feature to regenerate
Recovery:
1. Verify story structure: ls -la ./project-management/US-STORY/US-3.4-*/
2. Check if TASKS directory exists
3. If missing, regenerate with /lazy create-feature
Error: GitHub issue numbers missing
⚠️ Warning: Some task files don't have GitHub issue numbers
This may happen with older stories
Recovery:
1. Manually add GitHub issues
2. Or regenerate story with /lazy create-feature (includes gh issue creation)
3. Issues without numbers won't be auto-closed
Error: gh CLI not found
❌ Error: gh command not found
Recovery:
1. Install GitHub CLI: https://cli.github.com
2. Authenticate: gh auth login
3. Verify: gh auth status
4. Retry: /lazy story-review US-3.4
Error: gh auth failed
❌ Error: Not authenticated to GitHub
Recovery:
1. Run: gh auth login
2. Follow prompts to authorize
3. Verify: gh auth status
4. Retry: /lazy story-review US-3.4
Error: Base branch doesn't exist
❌ Error: Base branch 'develop' not found
Recovery:
1. Check branches: git branch -a
2. Use correct base: /lazy story-review US-3.4 --base main
3. Or create branch: git branch develop
Success Criteria
Story review is successful when:
- ✅ Story file is valid with all required sections
- ✅ Story directory structure is correct:
./project-management/US-STORY/US-X.Y-name/ - ✅ All task files found in TASKS directory
- ✅ All task tags present:
git tag -l 'task/TASK-*-committed' - ✅ All commits collected since story start
- ✅ Review agent approved entire implementation
- ✅ All acceptance criteria validated
- ✅ Architecture, security, and testing validated
- ✅ PR created with title
[STORY] {story-name} - ✅ PR body contains full story + all tasks + test results + GitHub issues
- ✅ All commits included in PR history
- ✅ PR is on correct base branch
- ✅ All related GitHub issues closed (story + tasks)
Example Usage
Basic story review with story ID
/lazy story-review US-3.4
Review with full path (backward compatible)
/lazy story-review ./project-management/US-STORY/US-3.4-oauth2-authentication/US-story.md
Review on specific base branch
/lazy story-review US-3.4 --base develop
Create as draft PR
/lazy story-review US-3.4 --draft true
Verify story state before review
# List available stories
ls -1d ./project-management/US-STORY/US-*/
# Check what tasks are completed
git tag -l 'task/*'
# Check story commits
git log story/US-3.4-start..HEAD --oneline
# Then run review
/lazy story-review US-3.4
Session Logging
All activities logged to logs/<session-id>/story-review.json:
{
"story_file": "USER-STORY.md",
"story_id": "oauth2-auth",
"base_branch": "main",
"draft_mode": false,
"timestamp": "2025-10-25T15:45:00Z",
"stages": [
{
"stage": "load_story",
"status": "completed",
"story_title": "Build OAuth2 Authentication"
},
{
"stage": "verify_tags",
"status": "completed",
"all_present": true,
"task_count": 4
},
{
"stage": "collect_commits",
"status": "completed",
"commit_count": 7
},
{
"stage": "collect_implementations",
"status": "completed",
"files_changed": 15
},
{
"stage": "run_tests",
"status": "completed",
"test_result": "passed"
},
{
"stage": "review",
"status": "approved",
"agent": "story-review-agent"
},
{
"stage": "pr_creation",
"status": "completed",
"pr_url": "https://github.com/org/repo/pull/42",
"pr_number": 42
}
],
"result": {
"approved": true,
"pr_url": "https://github.com/org/repo/pull/42",
"tasks_included": ["TASK-1.1", "TASK-1.2", "TASK-1.3", "TASK-1.4"],
"commits_included": 7,
"files_changed": 15
}
}
Integration with Other Commands
After /lazy create-feature
# create-feature creates story directory and sets start tag
/lazy create-feature "Add OAuth2 authentication"
# Creates: ./project-management/US-STORY/US-3.4-oauth2-authentication/
# US-story.md, TASKS/TASK-*.md files
# GitHub issues for story and tasks
# Sets tag: story/US-3.4-start
# Execute all tasks
/lazy task-exec TASK-1.1
/lazy task-exec TASK-1.2
/lazy task-exec TASK-1.3
# Review and create PR (using story ID)
/lazy story-review US-3.4
After /lazy task-exec
# Each task-exec sets a completion tag
/lazy task-exec TASK-1.1
# Sets tag: task/TASK-1.1-committed
# story-review uses these tags to verify completion
/lazy story-review US-3.4
Workflow Summary
/lazy create-feature
↓
Creates ./project-management/US-STORY/US-X.Y-name/
story/US-X.Y-start tag created
GitHub issues created
↓
/lazy task-exec TASK-1.1 → task/TASK-1.1-committed
/lazy task-exec TASK-1.2 → task/TASK-1.2-committed
/lazy task-exec TASK-1.3 → task/TASK-1.3-committed
↓
/lazy story-review US-X.Y
↓
Verify all tags present
↓
Collect all commits
↓
Review Agent validation
↓
Create PR (if approved)
↓
Close GitHub issues (story + tasks)
Notes
- Story review is read-only - no file modifications during review
- All validation happens through git tags (immutable markers)
- Review agent has complete context (story + tasks + implementations + tests)
- PR creation is automatic only if review is approved
- Draft mode allows additional manual review before merge
- Story state tracking enables iterative review (fix tasks, re-review)
- Accepts both story ID (US-X.Y) and full path for backward compatibility
- Automatically closes all related GitHub issues (story + all tasks)
- Works with new directory structure:
./project-management/US-STORY/US-X.Y-name/ - Task files are individual TASK-*.md files in TASKS subdirectory
- GitHub issue numbers extracted from story and task files