From Flagrare
Generates a human-readable standup report covering yesterday's code contributions (PRs, reviews, deploys, tickets) and today's priority queue from GitHub, local git, and configured trackers.
How this skill is triggered — by the user, by Claude, or both
Slash command
/flagrare:standup-reportThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Generate a daily standup recap that reads like a human wrote it. The reader is either the user (preparing what to say at standup) or their team (skimming a Slack post). Either way, they want the *story* of yesterday's code work, not a JSON dump of commits.
Generate a daily standup recap that reads like a human wrote it. The reader is either the user (preparing what to say at standup) or their team (skimming a Slack post). Either way, they want the story of yesterday's code work, not a JSON dump of commits.
The single rule that shapes everything below: work is named by what it was, not by its ID. "Fixed the image cache eviction" beats "Merged PR #481" every time. Nobody remembers numbers; everyone remembers the bug.
Config lives at ~/.claude/skills/flagrare/config.json — a single file shared across all flagrare skills, outside the plugin tree so it survives plugin updates and reinstalls. Skill-agnostic keys (GitHub login, display name, repo scope, local roots) sit at the top level; skill-specific keys nest under skills.<name>.
In Bash, expand ~ explicitly: "$HOME/.claude/skills/flagrare/config.json". The directory may not exist yet — mkdir -p "$HOME/.claude/skills/flagrare" before writing.
If ~/.claude/skills/flagrare/config.json does not exist but a legacy per-skill config does, migrate it:
LEGACY="{skill_directory}/config.json" # old location, lost on plugin reinstall
NEW="$HOME/.claude/skills/flagrare/config.json"
if [ ! -f "$NEW" ] && [ -f "$LEGACY" ]; then
mkdir -p "$(dirname "$NEW")"
# Wrap legacy keys: standup-specific ones (extra_mcps) move under skills.standup-report
jq '{
github_login, display_name, first_person, repo_scope, local_repo_roots, tracker_mcp,
skills: { "standup-report": { extra_mcps: .extra_mcps } }
} | with_entries(select(.value != null))' "$LEGACY" > "$NEW"
fi
Tell the user once: "Migrated your config from the old per-plugin location to ~/.claude/skills/flagrare/config.json so it survives plugin updates."
Use AskUserQuestion to collect:
author:, commenter:, reviewed-by: searches. If missing, run gh api user --jq '.login' and confirm.org:<name> — all repos in a GitHub org (best for company work)user:<login> — all repos under the user's account (best for personal projects)owner/repo strings — when work spans orgs~/Dev, ~/work). The skill walks one level deep looking for .git/ to enumerate repos.Save the shared keys at the top level and the standup-specific extra_mcps under skills["standup-report"]:
{
"github_login": "aturing",
"display_name": "Alan",
"first_person": true,
"repo_scope": { "type": "org", "value": "acme-corp" },
"local_repo_roots": ["~/Dev", "~/work"],
"tracker_mcp": "linear",
"skills": {
"standup-report": {
"extra_mcps": ["slack"]
}
}
}
Confirm with the user before saving. Preserve any pre-existing skills.* blocks from other flagrare skills — merge, don't overwrite.
If ~/.claude/skills/flagrare/config.json exists, read the top-level keys plus skills["standup-report"]. If only some top-level keys exist (e.g. brag-doc was set up but not standup-report), reuse what's there and only ask for extra_mcps. If the user says "reconfigure" or "edit setup", re-run the setup flow — but only rewrite the skills["standup-report"] block plus any top-level keys the user changes; leave other skills' blocks untouched.
First, determine today's date and current time by running:
date '+%A %Y-%m-%d %H:%M'
Do NOT guess the day of the week from context or the current date string. LLMs are unreliable at day-of-week calculations. Always run the command above and use its output.
"Yesterday" at standup means last working day, not literal yesterday. Apply this logic to the output of the date command:
today = Mon → window starts Friday 00:00
today = Tue–Fri → window starts previous calendar day 00:00
today = Sat/Sun → window starts most recent Friday 00:00
The window always ends at the current time (now), not at midnight of the previous day. Work done earlier today (before the skill is invoked) is part of the standup. For example, if it's Tuesday 9:30am, the window is Monday 00:00 through Tuesday 09:30.
If the user specifies a window in the prompt ("since Friday", "last 3 days", "this week"), honor it. Otherwise apply the rule above. State the resolved window in the report header so the reader knows what's covered.
Run the following queries in parallel — they're independent and slow if serialized. Use ISO 8601 dates (YYYY-MM-DD) for the window boundaries. {FROM} is the start of the window (last working day). {TO} is today's date (so that any work done between midnight and now is captured).
gh api "search/issues?q={SCOPE}+is:pr+author:{LOGIN}+updated:{FROM}..{TO}&per_page=100" \
--jq '.items[] | {number, title, html_url, state, draft, merged_at, created_at, updated_at, body, repo: (.repository_url | split("/") | last), labels: [.labels[].name]}'
For each PR returned, also fetch:
gh api "repos/{OWNER}/{REPO}/pulls/{NUMBER}/commits" \
--jq '[.[] | select(.commit.author.email == "{EMAIL}" or .author.login == "{LOGIN}") | {sha, message: .commit.message, date: .commit.author.date}]'
gh api "repos/{OWNER}/{REPO}/pulls/{NUMBER}/reviews" \
--jq '[.[] | select(.user.login | test("\\[bot\\]$") | not) | {user: .user.login, state, submitted_at, body}]'
gh api "search/issues?q={SCOPE}+is:pr+reviewed-by:{LOGIN}+updated:{FROM}..{TO}&per_page=100" \
--jq '.items[] | {number, title, html_url, repo: (.repository_url | split("/") | last), author: .user.login}'
For each, fetch your reviews specifically to know whether you approved, requested changes, or commented:
gh api "repos/{OWNER}/{REPO}/pulls/{NUMBER}/reviews" \
--jq '[.[] | select(.user.login == "{LOGIN}") | {state, submitted_at, body}]'
gh api "search/issues?q={SCOPE}+commenter:{LOGIN}+updated:{FROM}..{TO}&per_page=100" \
--jq '.items[] | {number, title, html_url, repo: (.repository_url | split("/") | last)}'
Deduplicate against the prior two queries — only count this PR if it wasn't surfaced as authored-by or reviewed-by you. The remaining set is PRs where you contributed just a comment.
For each configured local repo root, enumerate */.git/ one level deep, then for each repo:
git -C {repo_path} log --author="{LOGIN_OR_EMAIL}" \
--since="{FROM}" --until="{TO} 23:59:59" \
--pretty=format:'%H|%ai|%s|%b%n---'
These catch work that hasn't hit GitHub yet — local WIP, branches not pushed. Deduplicate SHAs against the GitHub PR commits already collected.
For each merged PR in step 1, check whether a release workflow fired afterward:
gh api "repos/{OWNER}/{REPO}/actions/runs?created=>={MERGE_DATE}&per_page=20" \
--jq '.workflow_runs[] | select(.name | test("release|deploy|publish"; "i")) | {name, conclusion, html_url, created_at, head_sha}'
Match on head_sha (the merged PR's merge commit SHA) or by time proximity (workflow created within ~5 min of merge). Record: did it run, did it succeed, when. If the conclusion is failure, surface that explicitly — a "shipped" PR that didn't actually deploy is the kind of detail standup is for.
For each PR collected, scan body and title for ticket references:
\b[A-Z]{2,5}-\d+\b (e.g., ENG-142)notion.so/...#\d+ references resolved within the repoUse the configured tracker's MCP to fetch each ticket's title and status. The title is what you use in the narrative ("the image cache eviction bug") — the ticket ID stays in the footnote.
For each opted-in extra MCP (from setup), pull anything from the time window that mentions the user or references the PRs/tickets above. Examples:
@{user} or threads where they posted code-related replies during the window. Filter aggressively — birthday wishes and lunch polls are noise.Treat MCP results as narrative seasoning, not primary data. If an MCP errors out or returns nothing, skip silently — the standup still works without it.
Run these queries in parallel with steps 1–7. Their output feeds the Today section only — they do not affect the Yesterday narrative.
After collecting yesterday's data, flag any of these as carry-over candidates:
open and not merged — especially those with changes_requested reviews or no approvals yetdraft stateOrder carry-overs by recency of last push (most recently active first). These are the highest-signal "likely working today" items because work was already in motion.
Fetch tickets assigned to the user in a not-yet-started state:
assignee: me with state type in [triage, backlog, unstarted], ordered by priority ASCassignee = currentUser() AND status in ("To Do", "Open", "Backlog") ORDER BY priority ASCNormalize priority to a consistent scale for ranking: Urgent → High → Medium → Low → No priority (no-priority sorts last). Limit to 10 results; note "and N more" if the queue is longer.
Cross-reference against carry-overs: if an open PR or local branch references a ticket that also appears in the queue, treat them as the same item — list it once, under the carry-over heading, with the ticket title as the label.
If the tracker MCP is unavailable or returns nothing, omit the queue silently. Carry-overs from GitHub/local git are always shown.
gh api "search/issues?q={SCOPE}+is:pr+is:open+review-requested:{LOGIN}&per_page=50" \
--jq '[.items[] | select(.draft == false) | {number, title, html_url, repo: (.repository_url | split("/") | last), author: .user.login, updated_at}]'
These are open, non-draft PRs where the user is an explicitly requested reviewer and has not yet submitted a review. Exclude:
.draft == true) — the author isn't ready for reviewFor each result, note the PR author — "Daniel's auth refactor" is more useful than a bare title in the Today context. If the PR body or title references a linked ticket, resolve its title via the tracker MCP (same logic as step 6).
For every PR, commit cluster, or ticket, derive a human phrase that names the work. Priority order:
"Image cache evicts entries on retry" → "the image cache eviction bug" or just "image cache eviction")fix(cache): LRU eviction on retry → "fixing the LRU eviction on retry")src/cache/lru.ts → "the LRU cache code")The phrase goes in the prose; the PR number and ticket ID go in the refs footnote. Inline numbers belong only when the user explicitly asks ("include PR links inline").
This is where the skill earns its keep. The naive version of this skill enumerates events. The version worth shipping reads like a Staff Engineer's standup: impact-first, root-cause-aware, and honest about judgment calls.
The reframe that matters: a standup is not a status report on you. It's a status report on the system — what's better, who's unblocked, what risks were caught, what's still in flight and why. The work is the vehicle; the impact is the cargo.
Apply these shifts when synthesizing:
The same events, written two ways. Both are accurate. Only one reads like a Staff Engineer wrote it.
❌ Junior recap (events as a to-do list, dressed up):
Fixed the LRU eviction bug in the image cache and merged the PR. The release workflow deployed it. Reviewed two PRs — approved Daniel's auth refactor and requested changes on Carol's cache benchmarks. Addressed three comments on my queue refactor PR.
✅ Staff recap (impact, causation, judgment):
The image-cache regression that's been paging the on-call rotation for a week is fixed and in prod — root cause was the LRU admitting entries faster than it evicted under burst load, which only surfaced because our retry policy amplifies traffic on the hot path. While that was baking, I unblocked Daniel on the auth-service refactor; the migration plan was sound and we agreed on the rollback path inline. Pushed back on Carol's cache-benchmark methodology — the workload she's measuring doesn't match what production sees, and shipping the conclusions as-is would have driven the wrong tuning decisions next quarter. My own queue refactor is in re-review after addressing the back-pressure concerns from Tuesday.
Notice: same five events, but the second version names the consequence of each one. The reader walks away knowing what changed about the system, not what tickets moved columns.
Before writing, scan the collected data for these patterns. They're the raw material for the impact framing above:
Across all sections — paragraph, recap, bullets, refs — these categories are always excluded:
If an activity produced a real outcome (a bug found, a risk surfaced, a decision made) — write the outcome, not the activity that led to it. A debugging session is worth one standup line: the root cause, not the method.
Write in past tense. First-person if first_person: true, otherwise use the configured display name in the third person.
Use connective tissue that conveys rhythm without literal timestamps: most of the day, while that was running, on the side, between meetings, late afternoon, one thing that took longer than expected. These cue the reader to time-of-day shape and let you order beats by importance rather than by clock.
Avoid the word "PR" in prose if you can substitute the work-name. "Shipped the image cache fix" beats "Merged the image-cache PR". Avoid "addressed feedback" without saying what the feedback was — "addressed the back-pressure concerns from Tuesday" tells the reader something; "addressed feedback" doesn't.
The Today section is the forward-looking half of the standup. Its job is to answer "where are you putting your energy today?" without overpromising.
These are inferences, not commitments. Frame everything as "likely working today" — the report is a prediction based on what's in motion, not a schedule the user will be held to. The reader should walk away with a reasonable picture of where the day is headed, not a list they expect to be checked off.
Ordering logic — three tiers:
updated_at descending (most recently active first — the author may be waiting on this right now). Name both the work and the author: "Daniel's auth refactor" not just the PR title.Cap at 5 items total. If there are more, pick the 5 with the strongest signal (active carry-overs first, then highest-priority queue items) and note "queue has N more" in the Refs footnote.
When a carry-over is close to done, say so. "One review away from merge" or "waiting on CI" is more useful than just the work name.
When the queue is empty and no carry-overs exist, omit the Today section entirely rather than speculating. An honest "nothing lined up" is better than invented filler.
# Standup — {YYYY-MM-DD}
> Covering: {window_human} | {N} PRs touched | {M} reviews given | {K} commits
## Yesterday
{2-3 sentence narrative paragraph. Lead with impact: what changed about
the system, who's unblocked, what risk was caught. Not "I did X and Y" —
"The X problem is fixed and shipped; Y is unblocked; Z is now flagged
for next quarter." If the day was mostly meetings or interrupts, say so
plainly and frame what it enabled.}
## Recap
{Long-form journal section. 2-5 short paragraphs grouping events by
thread, not by source. Each paragraph is one coherent story with its
own impact line. Cross-reference where it helps — "the same auth
refactor I reviewed Tuesday, Daniel ended up shipping before EOD; the
migration ran clean."
Open paragraphs with varied shapes — not every one starts with a verb.
Lead with the noun ("The auth refactor..."), the constraint ("Most of
the morning..."), or the surprise ("One thing that took longer than
expected..."). Pure verb-first openers across every paragraph is the
junior tell.}
## Today
{Inferences about where the day is headed — not a schedule, not a
commitment. Frame each item with hedged language. Three tiers:
carry-overs → pending review requests → priority queue.
Omit this section entirely if all three are empty.}
**Carry-overs:**
- {work name} — {status: "one approval short of merge" / "waiting on CI" / "changes requested"}
- …
**Pending reviews:**
- {author}'s {work name} — {context, e.g. "requested Tuesday, auth service"}
- …
**Up next (from queue):**
- {ticket title} — {priority}
- …
## For the channel
{One opening line — the **big picture** of the day in plain English.
What was the day *about*? Not a list of things done, but the
single sentence a teammate would use to summarize your day to
someone who wasn't there. Examples:
"Mostly heads-down on the image cache — root cause found, fix shipped, on-call relieved."
"Split between unblocking the auth refactor and spiking the queue-sharding approach."
"All reviews day — three PRs, design review for the new API surface."
If the day had no clear theme, lead with the most impactful item.}
**Yesterday:**
{Tight bullet list, 4-8 lines, slack-pasteable. Each bullet still
carries impact framing — what changed, what's unblocked, what's
flagged. Naked "Reviewed X" / "Approved Y" bullets are a regression
to the junior format; even compressed, the bullets should say *why
it mattered*. Names work in human terms. Deploy state inlined only
when it's notable.
**NEVER include in bullets or prose:**
- Skills invoked, slash commands run, or AI tooling used ("ran debug-hunt", "used standup skill", etc.)
- Process steps ("grepped the codebase", "ran evals", "read the docs")
- Ticket-column moves that produced no code change
- Self-reviews, bot-authored PRs handled individually (collapse to "approved N dependency bumps")
These are process, not outcome. If a debugging session is worth mentioning,
name what was *found* and *fixed*, not the method used.}
- Image-cache regression shipped — on-call rotation should stop paging
- Unblocked Daniel on auth refactor (approved after working through the rollback path inline)
- Pushed back on Carol's cache-benchmark methodology — workload doesn't match prod
- Queue refactor back in review after addressing the back-pressure concerns
**Today:**
{1-3 lines max. Priority order: carry-overs first, then pending
review requests, then queue items. Don't list more than 3 — the
team needs the headline, not the full picture. Hedged language:
"likely", "plan to", "continuing", "reviewing", "starting on".
If nothing is lined up, omit this block entirely.}
- Continuing queue refactor — one approval away from merge
- Reviewing Daniel's auth service changes (requested Tuesday)
- Starting on auth token expiry edge case (high priority)
## Refs
{Compact footnote with the actual identifiers, for anyone who wants to
chase a link. One line per work item. Include today's queue items
at the end with their ticket IDs.}
- image cache eviction — PR acme-corp/api#481, ENG-142, deployed
- auth refactor (Daniel) — PR acme-corp/api#478 (reviewed)
- LRU cache benchmarks — PR acme-corp/api#479 (reviewed, changes requested)
- queue refactor — PR acme-corp/api#483 (carry-over, awaiting review)
- auth service refactor (Daniel) — PR acme-corp/api#485 (review requested)
- auth token expiry edge case — ENG-145 (High, in queue)
If the window contains no activity (PTO, sick day, all-meetings day):
# Standup — 2026-05-26
> Covering: Friday 2026-05-22 | no code activity
## Yesterday
Quiet day — nothing landed in code. {If MCPs surfaced context: "Spent the day in meetings — design review for X, planning for Y." Otherwise omit this clause.}
## Today
{Still show the Today section if there are carry-overs or queue items —
a quiet day doesn't mean there's nothing lined up next.}
## For the channel
No code shipped yesterday.
**Today:** {highest-priority carry-over or queue item, or omit if nothing}
Don't fabricate activity. An honest "quiet day" beats invented bullets.
sha.gh itself is unavailable, tell the user to run gh auth login first since GitHub is the primary source.Always render the full report inline in the conversation.
If the user asks to "post it" or "send to Slack", offer to copy the "For the channel" section specifically — the prose sections are for them, the bullets are for the team. If they configured a Slack MCP and gave a channel, offer to post directly.
If the user asks to save it, default to ./standup-{YYYY-MM-DD}.md in the current working directory.
npx claudepluginhub flagrare/agent-skills --plugin flagrareProvides behavioral guidelines to reduce common LLM coding mistakes, focusing on simplicity, surgical changes, assumption surfacing, and verifiable success criteria.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.