Generate a daily standup summary of what was accomplished since the last standup, from a business logic perspective. Reads PR bodies to understand what changes actually enabled.
Scanned 9/3/2026
Install to Claude Code
npx -y skills add auerbachb/claude-code-config --skill standup --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Standup?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/auerbachb-standup)More formats (shields.io, HTML) on the badges page.
---
name: standup
description: Generate a daily standup summary of what was accomplished since the last standup, from a business logic perspective. Reads PR bodies to understand what changes actually enabled.
triggers:
- daily standup
- what did I do yesterday
- recent work summary
argument-hint: "[since-time] — omit for smart default (skips weekends/holidays); e.g. \"Friday at noon ET\""
model: sonnet
allowed-tools:
- Read
- Glob
- Grep
- Bash
- WebFetch
- WebSearch
---
Generate a standup report summarizing what was accomplished since $ARGUMENTS (default: smart lookback to previous workday noon ET — skips weekends and US federal holidays).
## How to gather data
### Step 1: Find repos and set time range
1. **Find all repos the user works in.** Check recent git activity across known repo paths. Start with the current working directory, then check other repos mentioned in conversation context or memory.
2. **Determine the lookback cutoff.** If the user provided an explicit `$ARGUMENTS` time reference, use it directly (skip to the ISO conversion below). If no argument was given, compute the smart default: find the most recent prior workday by walking backwards from yesterday, skipping weekends, US federal holidays, and the day after Thanksgiving (a de facto holiday for most organizations).
**Smart lookback algorithm** (run only when `$ARGUMENTS` is empty):
```bash
# Delegates to workday.sh, which implements the full weekend +
# US-federal-holiday + day-after-Thanksgiving calculator with observed-date
# rules (Sat → Fri, Sun → Mon) and cross-year lookbacks.
#
# Resolve the script path robustly: /standup runs from arbitrary repos,
# so a bare `.claude/scripts/workday.sh` only works when CWD happens to be
# this config repo. Check in this order: skills-worktree (canonical),
# ~/.claude/scripts (global symlink fallback), git root of the current repo,
# then CWD-relative.
# Capture GIT_ROOT first and only include that candidate when non-empty —
# otherwise `$(git rev-parse …)` expands to "" and the candidate becomes
# `/.claude/scripts/workday.sh` (absolute-root path), which would
# incorrectly match an unrelated root-level file if one existed.
WORKDAY_SH=""
GIT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || true)
for candidate in \
"$HOME/.claude/skills-worktree/.claude/scripts/workday.sh" \
"$HOME/.claude/scripts/workday.sh" \
"${GIT_ROOT:+$GIT_ROOT/.claude/scripts/workday.sh}" \
".claude/scripts/workday.sh"; do
[ -n "$candidate" ] || continue
if [ -x "$candidate" ]; then
WORKDAY_SH="$candidate"
break
fi
done
if [ -z "$WORKDAY_SH" ]; then
echo "Error: could not locate workday.sh" >&2
exit 1
fi
# Preserve workday.sh's exit-code contract (exit 3 = runtime failure).
# A plain `LOOKBACK_DATE=$(...)` would swallow non-zero exits and later
# collapse them to a generic `exit 1`; `|| exit $?` keeps the original.
LOOKBACK_DATE=$("$WORKDAY_SH" --last-workday) || exit $?
# LOOKBACK_DATE is now the most recent prior workday (YYYY-MM-DD)
```
3. **Convert to an ISO 8601 timestamp** with the correct UTC offset (handles EST/EDT automatically):
```bash
if [ -n "$ARGUMENTS" ]; then
# User provided an explicit time reference — parse it directly, bypass smart lookback
# The agent should convert $ARGUMENTS to the appropriate date -d / date -v expression.
# Example for "yesterday at noon ET": date -d 'yesterday 12:00' or date -v-1d -v12H -v0M -v0S
SINCE_ISO=$(TZ='America/New_York' date -d "$ARGUMENTS" '+%Y-%m-%dT%H:%M:%S%z' 2>/dev/null || TZ='America/New_York' date -jf '%Y-%m-%d %H:%M' "$ARGUMENTS" '+%Y-%m-%dT%H:%M:%S%z' 2>/dev/null)
if [ -z "$SINCE_ISO" ]; then
echo "Error: Could not parse time reference: $ARGUMENTS" >&2
exit 1
fi
else
# Smart default — LOOKBACK_DATE was set above by workday.sh; any failure
# there already propagated via `|| exit $?`, so LOOKBACK_DATE is non-empty
# here by contract.
# On Windows (Git Bash), TZ may be wrong — try PowerShell first for noon ET on LOOKBACK_DATE.
SINCE_ISO=$(powershell -Command "\$tz=[System.TimeZoneInfo]::FindSystemTimeZoneById('Eastern Standard Time'); \$d=[DateTime]::ParseExact('${LOOKBACK_DATE}','yyyy-MM-dd',[Globalization.CultureInfo]::InvariantCulture); \$local=[DateTime]::SpecifyKind(\$d.Date.AddHours(12), [DateTimeKind]::Unspecified); \$dto=[DateTimeOffset]::new(\$local, \$tz.GetUtcOffset(\$local)); \$dto.ToString('yyyy-MM-ddTHH:mm:sszzz')" 2>/dev/null \
|| TZ='America/New_York' date -d "${LOOKBACK_DATE} 12:00" '+%Y-%m-%dT%H:%M:%S%z' 2>/dev/null \
|| TZ='America/New_York' date -jf '%Y-%m-%d %H:%M' "${LOOKBACK_DATE} 12:00" '+%Y-%m-%dT%H:%M:%S%z')
if [ -z "$SINCE_ISO" ]; then
echo "Error: Failed to convert lookback date to ISO timestamp" >&2
exit 1
fi
fi
SINCE_ISO=$(printf '%s' "$SINCE_ISO" | sed -E 's/([+-][0-9]{2})([0-9]{2})$/\1:\2/')
```
The explicit `if/else` ensures `$ARGUMENTS` overrides the smart lookback cleanly. Both branches produce `SINCE_ISO` in the same format for downstream use.
### Step 2: Pull issues, PRs, and line counts
For each repo, run:
```bash
# Closed issues since the cutoff
gh issue list --state closed --search "closed:>$SINCE_ISO" --json number,title,closedAt --limit 100
# Merged PRs since the cutoff
gh pr list --state merged --search "merged:>$SINCE_ISO" --json number,title,mergedAt,additions,deletions --limit 100
# Currently open PRs (in progress work)
gh pr list --state open --author @me --json number,title,createdAt,additions,deletions
```
### Step 3: Read PR bodies (CRITICAL — do not skip)
**This is what makes the report useful.** Titles alone cannot convey business context.
For every merged PR and every open PR (using the `number` field from Step 2's JSON output), read the PR body:
```bash
# For each PR number from Step 2:
gh pr view "$PR_NUMBER" --json body,title,additions,deletions
```
Scan each PR body for:
- **What the change enables** — the "so what" for the business
- **Concrete numbers** — record counts, accuracy metrics, coverage stats, thresholds
- **Which part of the system** this advances — classification, scraping, data pipeline, UI, etc.
If a PR body is thin or template-only, extract the linked issue number via `pr-issue-ref.sh --first` (matches all nine GitHub closing keywords — `close`/`closes`/`closed`/`fix`/`fixes`/`fixed`/`resolve`/`resolves`/`resolved`, case-insensitive) and read the issue body. `--first` is required: default mode is set-valued (issue #1492), and this call feeds a single `gh issue view`. /standup runs from arbitrary repos, so resolve the script path with the same multi-candidate lookup used for `workday.sh` above. The helper exits 1 with empty stdout when no link is found — distinguish that benign case from exits 2/3/4 (real errors) so genuine failures surface:
```bash
PR_ISSUE_REF_SH=""
GIT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || true)
for candidate in \
"$HOME/.claude/skills-worktree/.claude/scripts/pr-issue-ref.sh" \
"$HOME/.claude/scripts/pr-issue-ref.sh" \
"${GIT_ROOT:+$GIT_ROOT/.claude/scripts/pr-issue-ref.sh}" \
".claude/scripts/pr-issue-ref.sh"; do
[ -n "$candidate" ] || continue
if [ -x "$candidate" ]; then
PR_ISSUE_REF_SH="$candidate"
break
fi
done
if [ -z "$PR_ISSUE_REF_SH" ]; then
echo "Error: could not locate pr-issue-ref.sh" >&2
exit 1
fi
ISSUE_NUMBER=""
if RAW_REF=$("$PR_ISSUE_REF_SH" --first "$PR_NUMBER" 2>&1); then
ISSUE_NUMBER="$RAW_REF"
else
REF_RC=$?
if [ "$REF_RC" -ne 1 ]; then
echo "Warning: pr-issue-ref.sh exit $REF_RC for PR #$PR_NUMBER: $RAW_REF — skipping linked-issue lookup" >&2
fi
fi
if [ -n "$ISSUE_NUMBER" ]; then
gh issue view "$ISSUE_NUMBER" --json body,title
fi
```
### Step 4: Identify business themes
Group the PRs/issues into **2-5 business themes** based on what they collectively accomplish. A theme is a capability or milestone, not a file or module. Examples of good themes:
- "Carrier classification pipeline is production-ready"
- "Portal coverage map is now accurate and scrapable"
- "Batch scraping infrastructure is ready to execute"
Each theme should map to one section of the report.
## How to write the report
### Opening line
Lead with scale stats in a single line:
```text
Since [time reference]: [N] PRs merged, [K] open, ~[M] issues closed, ~[L] lines added / ~[D] removed (~[net] net)
```
- Lines = sum additions and deletions across merged PRs separately, then compute net
### Body: themed sections
For each business theme, write a short paragraph (2-5 sentences) that explains:
1. **What the system can now do** that it couldn't before (lead with this)
2. **Key concrete numbers** from the PR bodies — record counts, accuracy percentages, coverage stats, state counts, etc. These make the report credible and useful.
3. **How it fits** into the broader goal or next step
Name each theme with a bold one-liner that captures the business outcome, not the technical action. e.g., "**Carrier classification pipeline is production-ready**" not "**Added classification code**".
### Open PRs
Mention open PRs inline if they relate to a theme, or as a standalone line at the end:
```text
**Open PR:** #N (short description of what it does and why)
```
### Closing synthesis
End with a 1-2 sentence "net effect" that answers: "What can the system do now that it couldn't at the start of this period?" This is the single most important line — it's what a PM or exec would read if they read nothing else.
## Writing rules
- Frame everything in terms of **business value and system capabilities**, not file names or technical implementation
- **Include concrete numbers** from PR bodies — these are what make the report useful vs. generic. Counts, percentages, thresholds, coverage metrics.
- Group related issues/PRs into a single theme — never list PRs individually unless there are fewer than 4 total
- Write from the user's perspective ("I" / "we") for direct paste into standup
- No word limit — let the report be as long as it needs to be to convey meaningful context, but stay concise. Typical range: 150-400 words depending on volume of work.
- Do NOT mention CR review cycles, code review tooling, or process details — focus on outcomes
- Do NOT pad with filler or repeat the same point in different words
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!