Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,13 +267,23 @@ Additional commands for enhanced quality and validation:
| `/speckit.clarify` | Clarify underspecified areas (recommended before `/speckit.plan`; formerly `/quizme`) |
| `/speckit.analyze` | Cross-artifact consistency & coverage analysis (run after `/speckit.tasks`, before `/speckit.implement`) |
| `/speckit.checklist` | Generate custom quality checklists that validate requirements completeness, clarity, and consistency (like "unit tests for English") |
| `/speckit.feedback` | Extract and store lessons learned from PR review comments for future reference |

### Environment Variables

| Variable | Description |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `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. |

### Lessons Learned

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:

- **`memory/lessons.md`** - Central lessons database organized by category (architecture, code-quality, testing, security, performance, documentation)
- **`memory/feedback/pr-<number>-lessons.md`** - Per-PR detailed feedback summaries that preserve the full context of each review
Comment on lines +278 to +283
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟑 Minor

Include the β€œother” category in the list.

Line 282 lists categories but omits other, which is supported in the feedback template.

Suggested fix
-- **`memory/lessons.md`** - Central lessons database organized by category (architecture, code-quality, testing, security, performance, documentation)
+- **`memory/lessons.md`** - Central lessons database organized by category (architecture, code-quality, testing, security, performance, documentation, other)
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
### Lessons Learned
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:
- **`memory/lessons.md`** - Central lessons database organized by category (architecture, code-quality, testing, security, performance, documentation)
- **`memory/feedback/pr-<number>-lessons.md`** - Per-PR detailed feedback summaries that preserve the full context of each review
### Lessons Learned
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:
- **`memory/lessons.md`** - Central lessons database organized by category (architecture, code-quality, testing, security, performance, documentation, other)
- **`memory/feedback/pr-<number>-lessons.md`** - Per-PR detailed feedback summaries that preserve the full context of each review
πŸ€– Prompt for AI Agents
In `@README.md` around lines 278 - 283, Update the "Lessons Learned" section where
the categories are listed (the paragraph referencing memory/lessons.md) to
include the missing `other` category; specifically modify the bulleted
description that enumerates categories (architecture, code-quality, testing,
security, performance, documentation) to append `other` so it matches the
feedback template and supported categories.


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.
Comment on lines +278 to +285
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

The PR description mentions lessons being stored under docs/feedback/lessons.md, but the documentation here (and templates) refer to .specify/memory/lessons.md. Please align the documentation/PR description so users don’t create lessons in the wrong location.

Copilot uses AI. Check for mistakes.

## πŸ“š Core Philosophy

Spec-Driven Development is a structured process that emphasizes:
Expand Down Expand Up @@ -401,7 +411,7 @@ The first step should be establishing your project's governing principles using
/speckit.constitution Create principles focused on code quality, testing standards, user experience consistency, and performance requirements. Include governance for how these principles should guide technical decisions and implementation choices.
```

This step creates or updates the `.specify/memory/constitution.md` file with your project's foundational guidelines that the AI agent will reference during specification, planning, and implementation phases.
This step creates or updates the `memory/constitution.md` file with your project's foundational guidelines that the AI agent will reference during specification, planning, and implementation phases.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟑 Minor

🧩 Analysis chain

🏁 Script executed:

cd . && wc -l README.md

Repository: buddhisthead/spec-kit

Length of output: 78


🏁 Script executed:

# Read the relevant sections of README.md
sed -n '410,420p' README.md

Repository: buddhisthead/spec-kit

Length of output: 797


🏁 Script executed:

# Read the directory tree section
sed -n '458,474p' README.md

Repository: buddhisthead/spec-kit

Length of output: 458


🏁 Script executed:

# Search for any references to constitution.md in the repository
rg 'constitution\.md' -B 2 -A 2

Repository: buddhisthead/spec-kit

Length of output: 8908


🏁 Script executed:

# Search for .specify directory references
rg '\.specify' README.md

Repository: buddhisthead/spec-kit

Length of output: 1441


Clarify the constitution file path to match the directory structure.

Line 414 references the path as memory/constitution.md, but the directory tree shown in lines 458-474 explicitly displays .specify/memory/constitution.md. The docs/upgrade.md guide also consistently uses the full .specify/memory/constitution.md path. Either clarify the working directory context (if memory/constitution.md is relative to .specify/) or update line 414 to use the full path .specify/memory/constitution.md for consistency with the directory structure shown on the same page.

πŸ€– Prompt for AI Agents
In `@README.md` at line 414, Update the README.md text at the sentence referencing
memory/constitution.md so it matches the repo layout: either clarify that
"memory/constitution.md" is relative to the .specify directory, or replace the
path with the full ".specify/memory/constitution.md" string to be consistent
with the directory tree and docs/upgrade.md; adjust the sentence that currently
mentions memory/constitution.md to explicitly use
".specify/memory/constitution.md" (or add a short parenthetical note that the
path is relative to .specify) so readers aren't confused.


### **STEP 2:** Create project specifications

Expand Down Expand Up @@ -431,6 +441,11 @@ see yours. You can edit any comments that you make, but you can't edit comments
delete any comments that you made, but you can't delete comments anybody else made.
```

You can mention a number of issue in your description and it will be used to generate the branch number, such as
```text
For GH issue #123, Develop BugZapper, a new fuzzy test framework".
```

After this prompt is entered, you should see Claude Code kick off the planning and spec drafting process. Claude Code will also trigger some of the built-in scripts to set up the repository.

Once this step is completed, you should have a new branch created (e.g., `001-create-taskify`), as well as a new specification in the `specs/001-create-taskify` directory.
Expand Down
220 changes: 220 additions & 0 deletions scripts/bash/fetch-pr-feedback.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
#!/usr/bin/env bash
#
# fetch-pr-feedback.sh - Extract PR data for the speckit.feedback agent
#
# Usage:
# ./fetch-pr-feedback.sh <pr_number>
# ./fetch-pr-feedback.sh --find-current # Find open PR for current branch (preferred)
# ./fetch-pr-feedback.sh --find-recent # Find most recently merged PR
#
# Output: JSON with PR metadata, review comments, and discussion comments
#

set -euo pipefail

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

error() {
echo -e "${RED}ERROR: $1${NC}" >&2
exit 1
}

warn() {
echo -e "${YELLOW}WARNING: $1${NC}" >&2
}

info() {
echo -e "${GREEN}$1${NC}" >&2
}

# Check for gh CLI
command -v gh >/dev/null 2>&1 || error "GitHub CLI (gh) is required but not installed."

# Check for jq
command -v jq >/dev/null 2>&1 || error "jq is required but not installed. Install with: brew install jq"

# Verify authentication
gh auth status >/dev/null 2>&1 || error "Not authenticated with GitHub. Run 'gh auth login' first."

# Get repository info
get_repo_info() {
gh repo view --json owner,name -q '"\(.owner.login)/\(.name)"' 2>/dev/null || error "Not in a GitHub repository."
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

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

get_repo_info wraps the interpolated owner/repo in extra quotes ("..."), which can produce a string containing quotes (e.g., "owner/repo") and break the later owner="${repo_info%/*}" / repo="${repo_info#*/}" split. Return the raw owner/repo without embedded quotes (or output JSON and parse with jq) so GraphQL parameters are correct.

Suggested change
gh repo view --json owner,name -q '"\(.owner.login)/\(.name)"' 2>/dev/null || error "Not in a GitHub repository."
gh repo view --json owner,name -q '.owner.login + "/" + .name' 2>/dev/null || error "Not in a GitHub repository."

Copilot uses AI. Check for mistakes.
}

# Find most recently merged PR for current branch
find_recent_merged_pr() {
local current_branch
current_branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null) || error "Not in a git repository."

# First try to find a merged PR for the current branch
local pr_number
pr_number=$(gh pr list --state merged --head "$current_branch" --json number -q '.[0].number' 2>/dev/null)

if [[ -z "$pr_number" || "$pr_number" == "null" ]]; then
# Fallback: get the most recently merged PR in the repo
pr_number=$(gh pr list --state merged --json number,mergedAt --limit 10 -q 'sort_by(.mergedAt) | reverse | .[0].number' 2>/dev/null)
fi

if [[ -z "$pr_number" || "$pr_number" == "null" ]]; then
error "No merged PRs found for branch '$current_branch' or in recent history."
fi

echo "$pr_number"
}

# Find open PR for current branch (preferred for pre-merge workflow)
find_current_pr() {
local current_branch
current_branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null) || error "Not in a git repository."

# First try to find an open PR for the current branch
local pr_number
pr_number=$(gh pr list --state open --head "$current_branch" --json number -q '.[0].number' 2>/dev/null)

if [[ -n "$pr_number" && "$pr_number" != "null" ]]; then
echo "$pr_number"
return
fi

# Fallback: try to find a merged PR for the current branch
pr_number=$(gh pr list --state merged --head "$current_branch" --json number -q '.[0].number' 2>/dev/null)

if [[ -n "$pr_number" && "$pr_number" != "null" ]]; then
warn "No open PR found, using most recently merged PR for this branch."
echo "$pr_number"
return
fi

error "No open or merged PRs found for branch '$current_branch'."
}

# Fetch PR basic info
fetch_pr_info() {
local pr_number=$1
gh pr view "$pr_number" --json number,title,body,state,mergedAt,headRefName,url,author 2>/dev/null || error "Failed to fetch PR #$pr_number"
}

# Fetch review comments via GraphQL
fetch_review_comments() {
local pr_number=$1
local repo_info
repo_info=$(get_repo_info)
local owner="${repo_info%/*}"
local repo="${repo_info#*/}"

local result
result=$(gh api graphql -f query='
query($owner: String!, $repo: String!, $number: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $number) {
reviews(first: 100) {
nodes {
body
author { login }
state
submittedAt
comments(first: 50) {
nodes {
body
path
line
author { login }
}
}
}
}
}
}
}
' -f owner="$owner" -f repo="$repo" -F number="$pr_number" 2>/dev/null)

if [[ -z "$result" ]]; then
warn "Failed to fetch review comments for PR #$pr_number"
echo "null"
else
echo "$result"
fi
}

# Fetch PR discussion comments
fetch_discussion_comments() {
local pr_number=$1
local result
result=$(gh pr view "$pr_number" --json comments 2>/dev/null)

if [[ -z "$result" ]]; then
warn "Failed to fetch discussion comments for PR #$pr_number"
echo "null"
else
echo "$result"
fi
}

# Main function to fetch all PR feedback data
fetch_all_feedback() {
local pr_number=$1

info "Fetching PR #$pr_number data..."

local pr_info
local review_comments
local discussion_comments

pr_info=$(fetch_pr_info "$pr_number")
review_comments=$(fetch_review_comments "$pr_number")
discussion_comments=$(fetch_discussion_comments "$pr_number")

# Normalize empty strings to "null" for jq
[[ -z "$review_comments" || "$review_comments" == "null" ]] && review_comments="null"
[[ -z "$discussion_comments" || "$discussion_comments" == "null" ]] && discussion_comments="null"

# Combine all data into a single JSON object
jq -n \
--argjson pr_info "$pr_info" \
--argjson review_comments "$review_comments" \
--argjson discussion_comments "$discussion_comments" \
'{
pr: $pr_info,
reviews: $review_comments,
discussion: $discussion_comments
}'
}

# Parse arguments
case "${1:-}" in
--find-current)
pr_number=$(find_current_pr)
info "Found PR for current branch: #$pr_number"
fetch_all_feedback "$pr_number"
;;
--find-recent)
pr_number=$(find_recent_merged_pr)
info "Found most recent merged PR: #$pr_number"
fetch_all_feedback "$pr_number"
;;
--help|-h)
echo "Usage: $0 <pr_number> | --find-current | --find-recent"
echo ""
echo "Arguments:"
echo " <pr_number> Specific PR number to fetch feedback from"
echo " --find-current Find and fetch the open PR for current branch (falls back to merged)"
echo " --find-recent Find and fetch the most recently merged PR for current branch"
echo ""
echo "Output: JSON with PR metadata, review comments, and discussion comments"
exit 0
;;
"")
error "No PR number provided. Use '$0 <pr_number>', '$0 --find-current', or '$0 --find-recent'"
;;
*)
if [[ "$1" =~ ^[0-9]+$ ]]; then
fetch_all_feedback "$1"
else
error "Invalid PR number: $1"
fi
;;
esac
Loading