
Extract Request Learnings
- 1 installs
- 2 repo stars
- Updated July 18, 2026
- ahoym/dotfiles
extract-request-learnings is a Claude Code skill that extracts review patterns, architectural decisions, and conventions from GitHub PR or GitLab MR history into structured learnings documents.
About
extract-request-learnings reads a repository's pull request or merge request history and pulls out review patterns, architectural decisions, conventions, and engineering insights. It processes reviews in batches using parallel subagents and writes the findings to docs/learnings/ files. A plan file tracks progress so a developer can resume extraction across sessions. It supports both GitHub (gh api) and GitLab (glab api).
- Extracts patterns and decisions from GitHub PR / GitLab MR history in batches
- Uses parallel extractor subagents plus a writer subagent
- Writes learnings to docs/learnings/ via a resumable plan file
Extract Request Learnings by the numbers
- 1 all-time installs (skills.sh)
- Ranked #1,366 of 1,879 Documentation skills by installs in the Skillselion catalog
- Data as of Jul 19, 2026 (Skillselion catalog sync)
extract-request-learnings capabilities & compatibility
- Capabilities
- pr history extraction · code review · knowledge capture · subagent orchestration
- Works with
- github · gitlab
- Use cases
- code review · documentation · research
- Pricing
- Free
What extract-request-learnings says it does
Extract learnings from request history (GitHub PRs or GitLab MRs) in batches
Processes reviews in batches using parallel subagents, capturing patterns from discussion threads, reviewer feedback, and review metadata.
Writer subagents run in the background and cannot prompt for permissions.
npx skills add https://github.com/ahoym/dotfiles --skill extract-request-learningsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 2 |
| Last updated | July 18, 2026 |
| Repository | ahoym/dotfiles ↗ |
What it does
Mine a repo's PR/MR discussion history into structured learnings docs capturing review patterns and conventions.
Who is it for?
Repos with substantial PR/MR discussion history where reviewer feedback encodes tacit conventions worth capturing.
When should I use this skill?
You want to systematically capture reusable engineering knowledge from a repository's accumulated pull request or merge request history.
What you get
Structured learnings files under docs/learnings/ summarizing patterns and decisions extracted from request history.
- docs/learnings/ files
- extraction plan file under docs/plans/
By the numbers
- 5 bundled files (SKILL.md, extractor-prompt.md, finalize-staging.sh, plan-template.md, writer-prompt.md)
Files
Extract Review Learnings
Systematically extract learnings from pull request (GitHub) or merge request (GitLab) history. Processes reviews in batches using parallel subagents, capturing patterns from discussion threads, reviewer feedback, and review metadata.
Usage
/extract-request-learnings- Continue from where the last session left off (reads plan file for progress)/extract-request-learnings init- Initialize a new extraction plan for the current repo
Reference Files (conditional — read only when needed)
extractor-prompt.md— Read when spawning extractor subagentswriter-prompt.md— Read when spawning the writer subagentplan-template.md— Read when initializing a new extraction plan
Prerequisites
Writer subagents run in the background and cannot prompt for permissions. Add these allow patterns to project-level .claude/settings.local.json:
"permissions": {
"allow": [
"Bash(gh api:*)",
"Bash(glab api:*)",
"Bash(jq:*)",
"Bash(wc:*)",
"Bash(grep:*)",
"Read(docs/learnings/**)",
"Read(docs/plans/**)",
"Write(docs/learnings/**)",
"Write(docs/plans/**)",
"Edit(docs/learnings/**)",
"Edit(docs/plans/**)",
"Read(~/.claude/learnings*/**)",
"Read(~/.claude/learnings-providers.json)"
]
}General/private writers use staging directories inside the project (docs/learnings/_staging/) to avoid background agent write restrictions on ~/.claude/. The orchestrator copies staged files to final locations in step 8.
Instructions
Init mode (init arg)
1. Verify platform access: !cat ~/.claude/platform-commands/verify-platform-access.sh 2>/dev/null || echo "UNCONFIGURED: run setup-claude.sh to set up platform-commands"
2. Count total reviews: !cat ~/.claude/platform-commands/count-total-reviews.sh 2>/dev/null || echo "UNCONFIGURED: run setup-claude.sh to set up platform-commands"
4. Create plan file at docs/plans/$PLAN_FILENAME:
- Use the template in
plan-template.md - Fill in repo name, review count, output locations
- Read
~/.claude/learnings-providers.jsonand create output directories:docs/learnings/and each provider'slocalPathdirectory (if not existing)
5. Confirm with the operator before proceeding to first batch.
Continue mode (default)
1. Detect platform (same as init step 1).
2. Sync with remote — git fetch origin main. If the current branch is behind or diverged from origin/main, tell the operator and suggest creating a fresh branch from origin/main. Multi-session workflows accumulate PRs between sessions — stale branches are the expected case.
3. Read the plan file (docs/plans/$PLAN_FILENAME). If it doesn't exist, tell the operator to run /extract-review-learnings init first.
4. Check progress — find the last completed batch in the progress tracker. Calculate NEXT_PAGE.
5. Glob existing learnings files in all output locations to build EXISTING_CATEGORIES for subagent prompts.
6. Fetch metadata (1 bash call) — use the batch fetch command, substituting BATCH_SIZE and NEXT_PAGE. Store result as BATCH_METADATA. Read BATCH_SIZE from the plan file (default: 10). !cat ~/.claude/platform-commands/batch-fetch-reviews.sh 2>/dev/null || echo "UNCONFIGURED: run setup-claude.sh to set up platform-commands"
7. Triage and spawn extractor subagents in parallel. Read extractor-prompt.md and use it as a verbatim template — fill in placeholders but do not abbreviate, paraphrase, or add ad-hoc instructions. Every review gets the identical template structure. Research only — no file writes.
Triage into three tiers based on metadata:
- Dedicated extractor (1 MR per agent):
user_notes_count > 10, OR description signals a new module/adapter/integration (keywords: "new module", "new adapter", "integration", "implement", "complete implementation"), OR state isclosedwithuser_notes_count >= 5(rich "why not" signal) - Small-group extractor (3-5 MRs per agent):
user_notes_count2-10, OR zero-discussion but description indicates substantial work (refactors, multi-file fixes, feature additions with filled-in descriptions) - Skip entirely: Dependency version bumps with empty descriptions, SDK releases with no changes, drafts closed immediately with 0 notes and no commits, reference data additions (asset lists, SQL data inserts)
Key principle: Discussion notes are the easiest signal but not the only one. Implementation patterns in the diff are equally valuable — a 30-file, 0-note MR introducing a new adapter has more signal than a 1-file, 5-note MR where all notes are bot approval + SonarQube. Triage on the work, not just the discussion.
8. Spawn 3 writer subagents in parallel with all extractor outputs concatenated to all. Re-read `writer-prompt.md` immediately before spawning (use offset+limit for the orchestrator section, lines 1-20) — do not rely on an earlier read. Use it as a verbatim template — fill in placeholders per writer:
- Project writer:
WRITER_SCOPE=project,SCOPE_FILTER=project-specific,READ_PATH=docs/learnings/,WRITE_PATH=docs/learnings/, files from step 5 - General writer:
WRITER_SCOPE=general,SCOPE_FILTER=general,READ_PATH=<defaultWriteTarget provider localPath>,WRITE_PATH=docs/learnings/_staging/general/, files from step 5 (read~/.claude/learnings-providers.jsonto find the provider withdefaultWriteTarget: true) - Private writer:
WRITER_SCOPE=private,SCOPE_FILTER=private,READ_PATH=<private provider localPath>,WRITE_PATH=docs/learnings/_staging/private/, files from step 5 (read~/.claude/learnings-providers.jsonto find the provider withwriteScope: "private") - DEDUP_GUIDANCE: pull from the plan file's progress tracker notes (recurring pattern mentions). Do not improvise — use what's written.
Each writer independently deduplicates against its own file set. Create staging directories before spawning: mkdir -p docs/learnings/_staging/general docs/learnings/_staging/private
9. Finalize staged files — run the finalize script to copy staged files to their final locations and clean up:
bash ~/.claude/commands/extract-request-learnings/finalize-staging.sh .This script reads ~/.claude/learnings-providers.json to discover provider directories, copies general learnings to all writable providers with writeScope: "global", private learnings to providers with writeScope: "private", handles java/ subdirectories, and removes the staging directory. It's pre-allowed via Bash(bash ~/.claude/commands/**) so it runs without permission prompts.
Do NOT use inline `cp` commands — the sandbox treats ~/.claude/ as sensitive and will prompt for each file regardless of allow patterns.
10. Verify writes — after finalization, run targeted checks (not full file reads):
GitHub:
# Confirm files exist and line counts grew
wc -l docs/learnings/*.md ~/.claude/learnings*/*.md
# Confirm batch review numbers appear in project files
grep -c '#FIRST_NUMBER\|#LAST_NUMBER' docs/learnings/*.md
# Spot-check one new entry (5 lines)
grep -A5 'PR #<LAST_NUMBER>' docs/learnings/*.md | head -6GitLab:
# Confirm files exist and line counts grew
wc -l docs/learnings/*.md ~/.claude/learnings*/*.md
# Confirm batch review numbers appear in project files
grep -c '!FIRST_IID\|!LAST_IID' docs/learnings/*.md
# Spot-check one new entry (5 lines)
grep -A5 'MR !<LAST_IID>' docs/learnings/*.md | head -6Report any discrepancies before updating progress. Do NOT read full files — use grep for targeted checks only.
11. Update progress tracker — edit the plan file's progress table. Include a brief note on key findings.
12. Report batch summary — 2-3 sentences on signal level, recurring patterns, and new categories. Keep it brief to preserve context.
Important Notes
- No python3 in bash commands — use
jqfor JSON parsing. Python triggers permission prompts. - Context budget: ~4 tool rounds per batch (metadata fetch, N+1 subagent spawns, verification, progress edit). Aim for 3-4 batches per session.
- All review states: Include open, merged, and closed. Closed reviews capture "why not" decisions.
- Oldest-first ordering: Resilient to new reviews being pushed during extraction.
- Categories emerge organically: Don't predefine — let them form from the data. Pass existing categories to subagents so they can classify or suggest new ones.
Extractor Subagent Prompt Template
Fill in <placeholders> before passing to each subagent.
Orchestrator instructions (do not include below the line):
- Use this template VERBATIM for every review — do not abbreviate, paraphrase, or omit sections
- Fill in ALL placeholders from the batch metadata JSON
- The template already handles closed reviews, zero-discussion reviews, and high-discussion reviews — do not add ad-hoc instructions per review
- The only per-review variation is the placeholder values themselves
- Set
<PLATFORM>togithuborgitlabbased on the detected platform before injecting
---
You are extracting learnings from <REVIEW_UNIT> <REVIEW_PREFIX><ID> in the <REPO_NAME> repo. RESEARCH ONLY — do not write any files.
Review metadata:
- ID: <ID>
- Title: <TITLE>
- State: <STATE> | Author: <AUTHOR> | Branch: <BRANCH> -> main
- Reviewers: <REVIEWERS>
- Discussion count: <DISCUSSION_COUNT> | Created: <CREATED_AT> | Merged: <MERGED_AT>
- Description: "<DESCRIPTION>"
Data fetching
Use these scripts from ~/.claude/platform-commands/ (cat each and execute the result):
Step 1 (always run):
fetch-review-comments.sh— use the full fetch variantfetch-issue-comments.sh
Step 2 (always run):
fetch-review-details.sh
Step 3 (if discussion count > 10, OR state is closed, OR description signals substantial implementation — new module/adapter/integration/refactor):
fetch-review-files.sh
Do not fetch any other endpoints. These commands provide all the signal needed.
For discussion reviews (discussion count > 0): Summarize each thread — what was flagged, the reasoning, the resolution. For implementation-heavy reviews (substantial diff, any discussion count): Analyze the implementation patterns visible in the diff — architectural decisions, design patterns, module structure, API contracts, error handling strategies, test patterns. The diff IS the learning; discussion is a bonus. Fetch Files Changed (Step 3) to understand scope even if discussion count ≤ 10. For zero-discussion reviews: Extract patterns from the diff, description, and metadata. Zero discussion often means the team agrees on the approach — that agreement IS a convention worth capturing. For closed/unmerged reviews: Capture why the direction was abandoned or what was explored.
Return structured learnings in this format:
### Concise title
What the learning is, why it matters, and when it applies.
- **Source**: <REVIEW_UNIT> <REVIEW_PREFIX><ID>
- **Frequency**: once | recurring | convention
- **Scope**: project-specific | general | private
- **Language**: <language/framework if applicable, e.g., Python, React, Docker; omit if language-agnostic>
- **Category**: <one of: EXISTING_CATEGORIES, or suggest new>Existing categories: <EXISTING_CATEGORIES>
Suggest new categories only if nothing existing fits.
Learnings include general good practices and architectural patterns, not just gotchas and surprising failure modes. Capture validated approaches, architectural conventions, and engineering practices that would help the team make better decisions — not only things that caused incidents.
Focus on:
- Implementation patterns: Architecture decisions visible in the diff — module structure, design patterns, error handling, API contracts, test structure. These are learnings even without discussion.
- What reviewers flagged and why: Discussion threads with reasoning and resolution.
- Decisions made and their reasoning: Both explicit (in comments) and implicit (in the code — zero-discussion conventions the team already agrees on).
- Patterns worth replicating or avoiding: Including patterns from the diff that have no reviewer commentary but represent established conventions.
- Convention signals: Naming, package structure, test organization, configuration patterns.
- For closed reviews: what was tried and why it didn't proceed.
#!/usr/bin/env bash
# Copies staged learnings files to their final locations and cleans up.
# Called by the extract-request-learnings orchestrator after writers complete.
#
# Usage: bash ~/.claude/commands/extract-request-learnings/finalize-staging.sh [project-root]
#
# Reads ~/.claude/learnings-providers.json to discover provider directories.
# General staging → all writable providers with writeScope "global"
# Private staging → all writable providers with writeScope "private"
#
# Expects staging dirs at:
# <project-root>/docs/learnings/_staging/general/
# <project-root>/docs/learnings/_staging/private/
set -euo pipefail
ROOT="${1:-.}"
GENERAL_STAGING="$ROOT/docs/learnings/_staging/general"
PRIVATE_STAGING="$ROOT/docs/learnings/_staging/private"
PROVIDERS_FILE="$HOME/.claude/learnings-providers.json"
copied=0
# Resolve ~ in localPath to $HOME
resolve_path() {
local p="$1"
echo "${p/#\~/$HOME}"
}
# Copy files from staging to a target directory, handling java/ subdirectory
copy_to_target() {
local staging_dir="$1"
local target_dir="$2"
[ -d "$staging_dir" ] || return 0
mkdir -p "$target_dir"
for f in "$staging_dir"/*.md; do
[ -f "$f" ] || continue
local base
base=$(basename "$f")
cp "$f" "$target_dir/$base"
copied=$((copied + 1))
done
# Handle java/ subdirectory if present
if [ -d "$staging_dir/java" ]; then
mkdir -p "$target_dir/java"
for f in "$staging_dir"/java/*.md; do
[ -f "$f" ] || continue
local base
base=$(basename "$f")
cp "$f" "$target_dir/java/$base"
copied=$((copied + 1))
done
fi
}
if [ ! -f "$PROVIDERS_FILE" ]; then
echo "Error: $PROVIDERS_FILE not found" >&2
exit 1
fi
# Copy general learnings to all writable global-scope providers
if [ -d "$GENERAL_STAGING" ]; then
while IFS= read -r raw_path; do
target=$(resolve_path "$raw_path")
copy_to_target "$GENERAL_STAGING" "$target"
done < <(jq -r '.providers[] | select(.writable == true and .writeScope == "global") | .localPath' "$PROVIDERS_FILE")
fi
# Copy private learnings to all writable private-scope providers
if [ -d "$PRIVATE_STAGING" ]; then
while IFS= read -r raw_path; do
target=$(resolve_path "$raw_path")
copy_to_target "$PRIVATE_STAGING" "$target"
done < <(jq -r '.providers[] | select(.writable == true and .writeScope == "private") | .localPath' "$PROVIDERS_FILE")
fi
# Clean up staging
rm -rf "$ROOT/docs/learnings/_staging"
echo "Finalized: $copied files copied, staging cleaned."
Review Learnings Extraction Plan
Objective
Systematically extract learnings from all <REVIEW_COUNT> reviews in the <REPO_NAME> repo.
Decisions
- Order: Oldest-first (resilient to new reviews being pushed during extraction)
- Scope: All review states (open, merged, closed)
- Batch size: 5 reviews per batch
- Discussion reviews: Full thread summary — capture conclusion + reasoning
- Zero-discussion reviews: Quick pass — scan title, diff summary, metadata for patterns
- Categories: Emerge organically from the data
- Deduplication: Consolidate recurring themes into patterns with frequency tags
- Progress: Update tracker after each batch (never lose work)
- Review: Autonomous extraction — operator reviews learnings files periodically
- Output locations:
- Project-specific:
<PROJECT_LEARNINGS_DIR> - General engineering:
<defaultWriteTarget provider localPath>(from~/.claude/learnings-providers.json) - Private (useful across projects but too specific to share):
<private provider localPath>(from~/.claude/learnings-providers.json)
Learnings Entry Format
### Concise title
What the learning is, why it matters, and when it applies. Include actionable guidance directly in the description — don't repeat it in a separate takeaway line.No Source, Frequency, or Takeaway bullet lines. The description paragraph should be self-contained.
Progress Tracker
| Batch | Reviews | Status | Notes |
|---|
<!-- Add rows as batches are processed -->
Writer Subagent Prompt Template
Fill in <placeholders> before passing to each writer subagent.
Orchestrator instructions (do not include below the line):
- Spawn THREE writers in parallel: project-specific, general, and private
- For project writer: set WRITER_SCOPE=project, list only project files, set SCOPE_FILTER to "project-specific"
- For general writer: set WRITER_SCOPE=general, list only global learnings files, set SCOPE_FILTER to "general"
- For private writer: set WRITER_SCOPE=private, list only private learnings files, set SCOPE_FILTER to "private"
- All writers receive the SAME concatenated extractor outputs
- DEDUP_GUIDANCE: list known recurring patterns from the progress tracker notes (do not improvise — pull from the plan file's batch notes)
- Staging directories: General and private writers cannot write to
~/.claude/from background agents.
Set WRITE_PATH to a staging directory inside the project:
- General:
READ_PATH=<defaultWriteTarget provider localPath from ~/.claude/learnings-providers.json>,WRITE_PATH=docs/learnings/_staging/general/ - Private:
READ_PATH=<private provider localPath from ~/.claude/learnings-providers.json>,WRITE_PATH=docs/learnings/_staging/private/ - Project:
READ_PATH=docs/learnings/,WRITE_PATH=docs/learnings/(no staging needed)
Writers read existing files from READ_PATH for dedup, but write full output files to WRITE_PATH. The orchestrator copies staged files to final locations after writers complete.
---
You are the <WRITER_SCOPE> writer subagent for review learnings extraction batch <BATCH_NUMBER> (reviews <REVIEW_PREFIX><FIRST_ID>-<REVIEW_PREFIX><LAST_ID>).
Your scope
You ONLY write to <WRITER_SCOPE> files. Ignore learnings with scope other than "<SCOPE_FILTER>".
- Learnings marked Scope: project-specific go to the project writer only
- Learnings marked Scope: general go to the general writer only
- Learnings marked Scope: private go to the private writer only
- If a learning has value in multiple scopes, each writer handles its own version independently
Your job
1. Read all existing files from the read location (listed below) 2. Deduplicate extracted learnings against existing entries 3. Route-check: Use the Language tag from each learning to route to the correct file. Language-specific learnings (e.g., Python, React) go to language-specific files (e.g., python-specific.md) even if the underlying principle is universal. Language-agnostic learnings go to topic files (e.g., code-quality-instincts.md). If a learning has no Language tag, treat it as language-agnostic. 4. Enrich existing entries where patterns recur (update frequency, add source reviews) 5. Write full output files to the write location — for enriched files, include the complete file content (not just the new entries) 6. Create new category files only if nothing existing fits
Read location (existing files for dedup)
<READ_PATH>
Write location (output goes here)
<WRITE_PATH>
Existing files to read first
<LEARNINGS_FILES>
Entry format
### Concise title
What the learning is, why it matters, and when it applies. Include actionable guidance directly in the description — don't repeat it in a separate takeaway line.No Source, Frequency, or Takeaway bullet lines. The description paragraph should be self-contained.
Extracted learnings to process
<CONCATENATED_EXTRACTOR_OUTPUTS>
Dedup guidance
<DEDUP_GUIDANCE>
When enriching existing entries:
- Add new source reviews to the Source line
- Upgrade Frequency if pattern now qualifies (once -> recurring -> convention)
- Expand the description only if the new instance adds meaningfully different context
Prefer fewer, larger file writes over many small edits to minimize system overhead.
Related skills
FAQ
Does it work with GitLab as well as GitHub?
Yes. It uses gh api for GitHub PRs and glab api for GitLab merge requests.
Can I resume a partial extraction?
Yes. It reads a plan file to continue from where the last session left off; run with the init arg to start a fresh plan.