Skip to content

Commit cd8892a

Browse files
buddhistheadclaude
andcommitted
feat: Add feedback command and lessons.md integration for continuous improvement
This PR introduces a comprehensive feedback loop system that captures lessons from PR reviews and applies them to future development work. ## New Features ### 1. /speckit.feedback Command - Extracts lessons learned from PR review comments and discussions - Stores lessons in .specify/memory/lessons.md (alongside constitution.md) - Stores PR-specific summaries in .specify/memory/feedback/pr-<number>-lessons.md - Supports three modes: - Auto-detect current PR: --find-current - Specific PR: --pr <number> - Manual lesson entry: inline text input - Categorizes lessons: code-quality, architecture, testing, documentation, security, performance, other - Deduplicates lessons and tracks frequency - Optional auto-commit with --commit flag ### 2. Lessons.md Integration Across Commands All core speckit commands now load and apply relevant lessons: - /speckit.specify loads architecture & documentation lessons - /speckit.plan loads architecture, testing & performance lessons - /speckit.implement loads code-quality, security & testing lessons ### 3. Supporting Infrastructure - fetch-pr-feedback.sh script: Fetches PR data using GitHub CLI - Command templates for all AI agents (Claude, Gemini, Cursor, Copilot, etc.) - Lessons stored in .specify/memory/ alongside project constitution - PR-specific feedback preserved in .specify/memory/feedback/ ## Files Added - scripts/bash/fetch-pr-feedback.sh - templates/commands/feedback.md ## Files Modified - templates/commands/specify.md (added Step 0: Load Lessons - 6 lines) - templates/commands/plan.md (added Step 0: Load Lessons - 6 lines) - templates/commands/implement.md (added Step 0: Load Lessons - 6 lines) - README.md (added Lessons Learned section explaining the system) - src/specify_cli/__init__.py (added feedback to next steps output) ## Benefits - Continuous Improvement: Lessons from PR reviews automatically inform future work - Universal Compatibility: Works with all 15+ supported AI agents - Non-Breaking: Optional integration - only activates when lessons.md exists - Category-Aware: Each command loads only relevant lessons to reduce noise - Team Learning: Captures institutional knowledge from code reviews - Compounding Knowledge: Team wisdom accumulates in memory alongside constitution ## How It Works 1. After PR review, run /speckit.feedback to extract lessons 2. Lessons are stored in .specify/memory/lessons.md with categories 3. PR-specific context preserved in .specify/memory/feedback/ 4. Future runs of /speckit.specify, /speckit.plan, /speckit.implement automatically load and apply relevant lessons 5. Teams avoid repeating past mistakes and compound knowledge over time 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 9111699 commit cd8892a

7 files changed

Lines changed: 519 additions & 0 deletions

File tree

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,13 +267,23 @@ Additional commands for enhanced quality and validation:
267267
| `/speckit.clarify` | Clarify underspecified areas (recommended before `/speckit.plan`; formerly `/quizme`) |
268268
| `/speckit.analyze` | Cross-artifact consistency & coverage analysis (run after `/speckit.tasks`, before `/speckit.implement`) |
269269
| `/speckit.checklist` | Generate custom quality checklists that validate requirements completeness, clarity, and consistency (like "unit tests for English") |
270+
| `/speckit.feedback` | Extract and store lessons learned from PR review comments for future reference |
270271

271272
### Environment Variables
272273

273274
| Variable | Description |
274275
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
275276
| `SPECIFY_FEATURE` | Override feature detection for non-Git repositories. Set to the feature directory name (e.g., `001-photo-albums`) to work on a specific feature when not using Git branches.<br/>\*\*Must be set in the context of the agent you're working with prior to using `/speckit.plan` or follow-up commands. |
276277

278+
### Lessons Learned
279+
280+
Spec-kit implements a continuous improvement system that captures lessons from PR reviews and applies them to future development work. The `/speckit.feedback` command extracts insights from code review comments and stores them in two places:
281+
282+
- **`.specify/memory/lessons.md`** - Central lessons database organized by category (architecture, code-quality, testing, security, performance, documentation)
283+
- **`.specify/memory/feedback/pr-<number>-lessons.md`** - Per-PR detailed feedback summaries that preserve the full context of each review
284+
285+
When you run `/speckit.specify`, `/speckit.plan`, or `/speckit.implement`, these commands automatically load relevant lessons from the central database for their phase and apply them proactively. This creates a compounding knowledge effect where your team's collective wisdom from past reviews continuously improves future implementations, helping avoid repeated mistakes and reinforcing best practices without manual intervention.
286+
277287
## 📚 Core Philosophy
278288

279289
Spec-Driven Development is a structured process that emphasizes:

scripts/bash/fetch-pr-feedback.sh

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
#!/usr/bin/env bash
2+
#
3+
# fetch-pr-feedback.sh - Extract PR data for the speckit.feedback agent
4+
#
5+
# Usage:
6+
# ./fetch-pr-feedback.sh <pr_number>
7+
# ./fetch-pr-feedback.sh --find-current # Find open PR for current branch (preferred)
8+
# ./fetch-pr-feedback.sh --find-recent # Find most recently merged PR
9+
#
10+
# Output: JSON with PR metadata, review comments, and discussion comments
11+
#
12+
13+
set -euo pipefail
14+
15+
# Colors for output
16+
RED='\033[0;31m'
17+
GREEN='\033[0;32m'
18+
YELLOW='\033[1;33m'
19+
NC='\033[0m' # No Color
20+
21+
error() {
22+
echo -e "${RED}ERROR: $1${NC}" >&2
23+
exit 1
24+
}
25+
26+
warn() {
27+
echo -e "${YELLOW}WARNING: $1${NC}" >&2
28+
}
29+
30+
info() {
31+
echo -e "${GREEN}$1${NC}" >&2
32+
}
33+
34+
# Check for gh CLI
35+
command -v gh >/dev/null 2>&1 || error "GitHub CLI (gh) is required but not installed."
36+
37+
# Check for jq
38+
command -v jq >/dev/null 2>&1 || error "jq is required but not installed. Install with: brew install jq"
39+
40+
# Verify authentication
41+
gh auth status >/dev/null 2>&1 || error "Not authenticated with GitHub. Run 'gh auth login' first."
42+
43+
# Get repository info
44+
get_repo_info() {
45+
gh repo view --json owner,name -q '"\(.owner.login)/\(.name)"' 2>/dev/null || error "Not in a GitHub repository."
46+
}
47+
48+
# Find most recently merged PR for current branch
49+
find_recent_merged_pr() {
50+
local current_branch
51+
current_branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null) || error "Not in a git repository."
52+
53+
# First try to find a merged PR for the current branch
54+
local pr_number
55+
pr_number=$(gh pr list --state merged --head "$current_branch" --json number -q '.[0].number' 2>/dev/null)
56+
57+
if [[ -z "$pr_number" || "$pr_number" == "null" ]]; then
58+
# Fallback: get the most recently merged PR in the repo
59+
pr_number=$(gh pr list --state merged --json number,mergedAt --limit 10 -q 'sort_by(.mergedAt) | reverse | .[0].number' 2>/dev/null)
60+
fi
61+
62+
if [[ -z "$pr_number" || "$pr_number" == "null" ]]; then
63+
error "No merged PRs found for branch '$current_branch' or in recent history."
64+
fi
65+
66+
echo "$pr_number"
67+
}
68+
69+
# Find open PR for current branch (preferred for pre-merge workflow)
70+
find_current_pr() {
71+
local current_branch
72+
current_branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null) || error "Not in a git repository."
73+
74+
# First try to find an open PR for the current branch
75+
local pr_number
76+
pr_number=$(gh pr list --state open --head "$current_branch" --json number -q '.[0].number' 2>/dev/null)
77+
78+
if [[ -n "$pr_number" && "$pr_number" != "null" ]]; then
79+
echo "$pr_number"
80+
return
81+
fi
82+
83+
# Fallback: try to find a merged PR for the current branch
84+
pr_number=$(gh pr list --state merged --head "$current_branch" --json number -q '.[0].number' 2>/dev/null)
85+
86+
if [[ -n "$pr_number" && "$pr_number" != "null" ]]; then
87+
warn "No open PR found, using most recently merged PR for this branch."
88+
echo "$pr_number"
89+
return
90+
fi
91+
92+
error "No open or merged PRs found for branch '$current_branch'."
93+
}
94+
95+
# Fetch PR basic info
96+
fetch_pr_info() {
97+
local pr_number=$1
98+
gh pr view "$pr_number" --json number,title,body,state,mergedAt,headRefName,url,author 2>/dev/null || error "Failed to fetch PR #$pr_number"
99+
}
100+
101+
# Fetch review comments via GraphQL
102+
fetch_review_comments() {
103+
local pr_number=$1
104+
local repo_info
105+
repo_info=$(get_repo_info)
106+
local owner="${repo_info%/*}"
107+
local repo="${repo_info#*/}"
108+
109+
gh api graphql -f query='
110+
query($owner: String!, $repo: String!, $number: Int!) {
111+
repository(owner: $owner, name: $repo) {
112+
pullRequest(number: $number) {
113+
reviews(first: 100) {
114+
nodes {
115+
body
116+
author { login }
117+
state
118+
submittedAt
119+
comments(first: 50) {
120+
nodes {
121+
body
122+
path
123+
line
124+
author { login }
125+
}
126+
}
127+
}
128+
}
129+
}
130+
}
131+
}
132+
' -f owner="$owner" -f repo="$repo" -F number="$pr_number" 2>/dev/null || warn "Failed to fetch review comments for PR #$pr_number"
133+
}
134+
135+
# Fetch PR discussion comments
136+
fetch_discussion_comments() {
137+
local pr_number=$1
138+
gh pr view "$pr_number" --json comments 2>/dev/null || warn "Failed to fetch discussion comments for PR #$pr_number"
139+
}
140+
141+
# Main function to fetch all PR feedback data
142+
fetch_all_feedback() {
143+
local pr_number=$1
144+
145+
info "Fetching PR #$pr_number data..."
146+
147+
local pr_info
148+
local review_comments
149+
local discussion_comments
150+
151+
pr_info=$(fetch_pr_info "$pr_number")
152+
review_comments=$(fetch_review_comments "$pr_number")
153+
discussion_comments=$(fetch_discussion_comments "$pr_number")
154+
155+
# Combine all data into a single JSON object
156+
jq -n \
157+
--argjson pr_info "$pr_info" \
158+
--argjson review_comments "${review_comments:-null}" \
159+
--argjson discussion_comments "${discussion_comments:-null}" \
160+
'{
161+
pr: $pr_info,
162+
reviews: $review_comments,
163+
discussion: $discussion_comments
164+
}'
165+
}
166+
167+
# Parse arguments
168+
case "${1:-}" in
169+
--find-current)
170+
pr_number=$(find_current_pr)
171+
info "Found PR for current branch: #$pr_number"
172+
fetch_all_feedback "$pr_number"
173+
;;
174+
--find-recent)
175+
pr_number=$(find_recent_merged_pr)
176+
info "Found most recent merged PR: #$pr_number"
177+
fetch_all_feedback "$pr_number"
178+
;;
179+
--help|-h)
180+
echo "Usage: $0 <pr_number> | --find-current | --find-recent"
181+
echo ""
182+
echo "Arguments:"
183+
echo " <pr_number> Specific PR number to fetch feedback from"
184+
echo " --find-current Find and fetch the open PR for current branch (falls back to merged)"
185+
echo " --find-recent Find and fetch the most recently merged PR for current branch"
186+
echo ""
187+
echo "Output: JSON with PR metadata, review comments, and discussion comments"
188+
exit 0
189+
;;
190+
"")
191+
error "No PR number provided. Use '$0 <pr_number>', '$0 --find-current', or '$0 --find-recent'"
192+
;;
193+
*)
194+
if [[ "$1" =~ ^[0-9]+$ ]]; then
195+
fetch_all_feedback "$1"
196+
else
197+
error "Invalid PR number: $1"
198+
fi
199+
;;
200+
esac

src/specify_cli/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1224,6 +1224,7 @@ def init(
12241224
steps_lines.append(" 2.3 [cyan]/speckit.plan[/] - Create implementation plan")
12251225
steps_lines.append(" 2.4 [cyan]/speckit.tasks[/] - Generate actionable tasks")
12261226
steps_lines.append(" 2.5 [cyan]/speckit.implement[/] - Execute implementation")
1227+
steps_lines.append(" 2.6 [cyan]/speckit.feedback[/] - Capture lessons from PR reviews")
12271228

12281229
steps_panel = Panel("\n".join(steps_lines), title="Next Steps", border_style="cyan", padding=(1,2))
12291230
console.print()

0 commit comments

Comments
 (0)