Build Your Own Dev Agent — Lesson 6: Building Skills
This lesson introduces a pattern you will reuse: signal, query, prioritize, report. You build three skills that follow it -- a PR reviewer, a git reviewer, and a standup generator. The standup generator adds a second pattern: skill composition, where one skill's output becomes another skill's input through shared state files.
Where You Are
your-project/
CLAUDE.md
.claude/
preferences.md
tasks-active.md
tasks-completed.md
progress.txt
error-log.md
learnings.md
priority-map.md
cron-jobs.json # 1 job: daily-planner
settings.json
hooks/
stop-telegram.sh
permission-gate.sh
skills/
daily-planner/
SKILL.md
See It: What the PR Reviewer Checks
The skill evaluates each open PR on five dimensions:
- Size -- Lines changed > 500
- Security -- Changes to auth, env, secrets, config
- Tests -- No test files modified
- Staleness -- Open for more than 3 days
- Conflicts -- Merge conflict status
Each flag gets a severity: high (blocks merge), medium (needs attention), low (informational).
Build It: PR Reviewer Skill
Prerequisites:
- The GitHub CLI (
gh) must be installed and authenticated. Install it from https://cli.github.com/ and rungh auth loginto authenticate before using this skill. - Create the
.claude/reports/directory for skill output files:mkdir -p .claude/reports
Intent: Create a skill that monitors GitHub repos for open PRs and produces a risk-flagged digest.
Prompt for Claude Code:
Create the directory .claude/skills/pr-reviewer/ and then create
.claude/skills/pr-reviewer/SKILL.md with this content:
# PR Review Agent Skill
Schedule: Configurable (default: every 4 hours during work hours)
## Input
Read before processing:
- .claude/preferences.md -- repos to monitor (look for GitHub repos list)
- .claude/priority-map.md -- priority rules for flagging
Configuration (add to preferences.md if not present):
- github_repos: list of owner/repo to monitor
## Process
1. **Query Open PRs**
For each configured repo:
- Use GitHub CLI (gh) to list open pull requests
- Command: gh pr list --repo {owner/repo} --state open --json number,title,author,createdAt,additions,deletions,changedFiles,headRefName,baseRefName,mergeable,reviewDecision,labels
- If gh is not available, note it and skip
2. **Analyze Each PR**
For each open PR, evaluate:
a. Size Check:
- additions + deletions > 500 --> flag HIGH: "Large PR ({lines} lines)"
- additions + deletions > 200 --> flag LOW: "Medium-sized PR"
b. Security Check:
- Get changed files: gh pr view {number} --repo {owner/repo} --json files
- Flag HIGH if any file matches: .env, auth, secret, credential,
security, permission, token, password, config/prod, middleware/auth
- Flag: "Security-sensitive files modified: {file list}"
c. Test Check:
- Look for test/spec files in changed files
- If code files changed but no test files --> flag MEDIUM:
"No tests modified"
d. Staleness Check:
- Calculate days since creation
- Open > stale_days threshold --> flag MEDIUM:
"Stale PR (open {N} days)"
- Open > stale_days * 2 --> flag HIGH:
"Very stale PR (open {N} days)"
e. Conflict Check:
- If mergeable == "CONFLICTING" --> flag HIGH: "Merge conflicts"
f. Review Status:
- APPROVED --> note as ready to merge
- CHANGES_REQUESTED --> note as needs work
- No reviews --> flag LOW: "No reviews yet"
3. **Prioritize**
Sort PRs by:
- Number of HIGH flags (descending)
- Number of MEDIUM flags (descending)
- Days open (descending)
4. **Generate Report**
Format as a digest:
## PR Review Digest -- [date]
### Needs Attention (HIGH flags)
For each PR with HIGH flags:
- PR #{number}: {title} by {author}
- Flags: [list of HIGH and MEDIUM flags]
- Link: {url}
### Monitor (MEDIUM flags only)
For each PR with only MEDIUM flags:
- PR #{number}: {title} by {author}
- Flags: [list]
### On Track (no flags or LOW only)
- PR #{number}: {title} -- {status}
### Summary
- Total open PRs: {count}
- Needs attention: {count}
- Ready to merge: {count}
- Average age: {days} days
## Output
Write the digest to .claude/reports/pr-review-[date].md
## State Update
- Append to progress.txt: "[timestamp] -- PR review: {total} open PRs,
{high_count} need attention, {ready_count} ready to merge"
- If any PR has been flagged HIGH for 3+ consecutive runs, add a P1 task
to tasks-active.md: "Review PR #{number} in {repo} -- consistently flagged"
Expected output: A complete PR reviewer skill file.
Build It: Add Repos to Preferences
Intent: Add GitHub repos to monitor in your preferences file.
Prompt for Claude Code:
Append the following section to .claude/preferences.md:
## GitHub Monitoring
Repos to monitor for PR reviews:
- owner/repo-name (replace with your actual repos)
Expected output: Updated preferences with repo configuration.
Build It: Add PR Reviewer Cron Entry
Intent: Schedule the PR reviewer.
Prompt for Claude Code:
Add a cron entry for the pr-reviewer skill to .claude/cron-jobs.json.
Schedule it 3x daily on weekdays (9 AM, 1 PM, 5 PM). Set expires to 7d.
Keep the existing daily-planner entry.
Expected output: cron-jobs.json with two entries.
Build It: Test the PR Reviewer
Intent: Run the skill manually to verify it works.
Prompt for Claude Code:
Run the pr-reviewer skill. Read .claude/skills/pr-reviewer/SKILL.md
and follow its instructions. Use one of my actual repos if configured
in preferences.md, or use a well-known public repo like cli/cli as a test.
Expected output: A PR review digest file and a progress.txt entry.
Skill 2: Git Reviewer
The git reviewer follows the same signal-query-prioritize-report pattern with a different data source. It monitors commits across your configured repos. For each commit, it explains three things: WHAT changed, WHY it changed, and the IMPACT on the system.
Intent: Create a skill that reviews recent commits and produces a categorized digest.
Prompt for Claude Code:
Create the directory .claude/skills/git-reviewer/ and then create
.claude/skills/git-reviewer/SKILL.md with this content:
# Git Reviewer Skill
Schedule: 12:00 PM daily (weekdays)
## Input
Read before processing:
- .claude/preferences.md -- repos to monitor
- .claude/priority-map.md -- priority rules
## Process
1. **Query Recent Commits**
For each repo configured in preferences.md:
- Use: gh api repos/{owner}/{repo}/commits --jq '.[0:20]'
- Or use: git log --since="24 hours ago" --oneline for local repos
- Collect: hash, author, message, date, files changed
2. **Analyze Each Commit**
For each commit, determine:
- WHAT: One-line summary of what changed
- WHY: Reason from commit message body or linked issue
- IMPACT: Categorize changed files (API, database, UI,
infrastructure, tests, docs). Flag HIGH impact: migrations,
auth changes, API breaking changes, dependency updates.
3. **Categorize**
Group commits into: Features, Fixes, Refactors, Chores, Unknown
4. **Generate Digest**
Format:
## Git Review -- [date]
### High Impact
- {hash} by {author}: {WHAT} | WHY: {reason} | IMPACT: {areas}
### Features
- {hash}: {summary}
### Fixes
- {hash}: {summary}
### Summary
- Total commits: {count} | Contributors: {list} | High impact: {count}
## Output
Write digest to progress.txt (appended)
## State Update
- Append summary to progress.txt
- If any commit touches database migrations with no tests, add a
task to tasks-active.md
Rules:
- Do not overwrite existing files
- Only create what is missing
- List created files when done
Expected output: Git reviewer skill file created at .claude/skills/git-reviewer/SKILL.md.
Skill 3: Standup Generator
The standup generator demonstrates skill composition -- it reads data the agent already has (git commits from yesterday's reviewer, completed tasks, active tasks, and progress log) and composes a ready-to-paste standup. No skill calls another skill directly. They communicate through shared state files.
Intent: Create a skill that generates your daily standup by combining existing agent data.
Prompt for Claude Code:
Create the directory .claude/skills/standup-generator/ and then create
.claude/skills/standup-generator/SKILL.md with this content:
# Standup Generator Skill
Schedule: 8:30 AM daily (weekdays)
## Purpose
Generate a ready-to-paste daily standup message by combining data
the agent already has. No external API calls needed.
## Input
Read these files (all internal to the agent):
- .claude/tasks-completed.md -- what was done yesterday
- .claude/tasks-active.md -- what is planned today
- .claude/progress.txt -- recent action log entries (last 24h)
- Latest git review entry in progress.txt (from git-reviewer skill)
## Process
1. **Extract Yesterday's Work**
From tasks-completed.md, find entries dated yesterday.
From progress.txt, find entries from yesterday.
Combine into a deduplicated list of accomplishments.
2. **Extract Today's Plan**
From tasks-active.md, find tasks due today or marked as
current priority. Group by priority level.
3. **Identify Blockers**
Scan tasks-active.md for items tagged with [blocked] or
past deadline. Scan progress.txt for entries containing
"blocked", "waiting", "failed", or "stuck".
4. **Include Code Activity**
If a git review ran yesterday, summarize:
- Number of commits authored by the user
- Key PRs merged or reviewed
5. **Generate Standup**
Format (ready to paste into Slack/Teams):
**Yesterday:**
- {accomplishment 1}
- {accomplishment 2}
- {accomplishment 3}
**Today:**
- {planned task 1}
- {planned task 2}
**Blockers:**
- {blocker or "None"}
Keep it concise -- 3-5 bullets per section max.
Use plain language, not internal file references.
Write "Merged PR #{number}: {title}" not "completed task from
tasks-completed.md"
## Output
Display the standup message in the terminal for copy-paste.
Optionally send via Telegram if configured.
## State Update
- Append to progress.txt: "[timestamp] -- Standup generated:
{yesterday_count} done, {today_count} planned, {blocker_count}
blockers"
## Why This Skill Matters
This demonstrates SKILL COMPOSITION:
- Git reviewer runs at noon --> writes to progress.txt
- Daily planner runs at 5:33 PM --> updates tasks
- Standup generator runs at 8:30 AM --> reads both outputs
- No skill calls another skill directly. They communicate
through shared state files. This is the agent pattern.
Rules:
- Do not overwrite existing files
- Only create what is missing
- List created files when done
Expected output: Standup generator skill file created at .claude/skills/standup-generator/SKILL.md.
Build It: Add Cron Entries for All Three Skills
Intent: Schedule all three new skills.
Prompt for Claude Code:
Add three new entries to .claude/cron-jobs.json (keep the existing
daily-planner entry):
1. pr-reviewer: 3x daily weekdays (9 AM, 1 PM, 5 PM), expires 7d
2. git-reviewer: noon weekdays, expires 7d
3. standup-generator: 8:30 AM weekdays, expires 7d
The file should now have 4 jobs total.
Expected output: cron-jobs.json with four entries.
Checkpoint
Your .claude/ directory should now contain: skills/pr-reviewer/SKILL.md, skills/git-reviewer/SKILL.md, skills/standup-generator/SKILL.md, updated preferences.md with GitHub repos, and cron-jobs.json with 4 jobs (daily-planner, pr-reviewer, git-reviewer, standup-generator).
This is part of the Build Your Own Dev Agent course. ← Previous Lesson | Next Lesson →