| name | pm-standup |
| version | 0.3.0 |
| description | Daily standup briefing. Pulls commits from all your active GitHub repos, Linear, Google Calendar, and Granola. Works from a standalone Product OS folder — no need to be inside a codebase. Surfaces today's meetings, cross-repo activity, priorities, and drift. |
| allowed-tools | Bash, Read, Write, Edit, Glob, Grep, AskUserQuestion, Agent, mcp__claude_ai_Google_Calendar__gcal_list_events, mcp__claude_ai_Google_Calendar__gcal_list_calendars, mcp__claude_ai_Granola__list_meetings, mcp__claude_ai_Granola__query_granola_meetings |
Multi-host portability rules. When invoking AskUserQuestion:
- The
header field MUST be a short noun phrase (≤ 12 characters). Mistral Vibe
rejects longer headers with string_too_long. Pick from: Start, Target,
Scope, Audience, Methodology, Feature, Question.
- The
options list MUST have at least 2 items. Vibe rejects empty/single-option
calls. For free-text input, always provide ≥ 2 framing options (e.g. Yes, here's the input /
Skip) — never call ask_user_question with options: [].
Preamble (run first)
source ~/.nanopm/lib/nanopm.sh 2>/dev/null || \
source .nanopm/lib/nanopm.sh 2>/dev/null || \
{ echo "ERROR: nanopm not installed. Run: curl -fsSL https://raw.githubusercontent.com/nmrtn/nanopm/main/setup | bash"; exit 1; }
nanopm_preamble
_STANDUP_FILE="$(nanopm_wiki_series_path standups "$(date +%F)")"
When to run this
Run /pm-standup at the start of your workday to:
- Know what you shipped or moved yesterday
- See today's meetings at a glance
- Set your top 1-3 priorities for today
- Surface any blockers before they cost you time
- Stay aligned with the roadmap without opening 4 tools
This skill never asks questions. It reads context, generates the briefing, done.
Phase 1: Gather yesterday's activity
GitHub — multi-repo commits (last 24h):
source ~/.nanopm/lib/nanopm.sh 2>/dev/null || source .nanopm/lib/nanopm.sh 2>/dev/null || true
_TIER_GITHUB=$(nanopm_has_connector github)
echo "GITHUB_TIER: $_TIER_GITHUB"
If GITHUB tier is MCP or API:
- Fetch all commits by the authenticated user across all repos in the last 24h
- Use GitHub API:
GET /search/commits?q=author:{username}+committer-date:>{yesterday_iso}&sort=committer-date
- For each commit extract: repo name, commit message, timestamp
- Group by repo — show repo name as prefix:
[repo-name] commit message
- Limit to 15 commits total, most recent first
If GITHUB not available: fall back to local git:
git log --since="24 hours ago" --oneline --no-merges 2>/dev/null | head -10 || echo "NO_GIT"
Note in output: "(local repo only — connect GitHub for multi-repo view)"
First-run repo list:
On first run, store the list of active repos found via GitHub API:
source ~/.nanopm/lib/nanopm.sh 2>/dev/null || source .nanopm/lib/nanopm.sh 2>/dev/null || true
nanopm_config_get "github_active_repos"
If empty: fetch repos with pushes in the last 30 days, store as comma-separated list:
source ~/.nanopm/lib/nanopm.sh 2>/dev/null || source .nanopm/lib/nanopm.sh 2>/dev/null || true
nanopm_config_set "github_active_repos" "{repo1},{repo2},..."
This speeds up subsequent runs — only query known active repos instead of all repos.
Linear (if available):
source ~/.nanopm/lib/nanopm.sh 2>/dev/null || source .nanopm/lib/nanopm.sh 2>/dev/null || true
_TIER_LINEAR=$(nanopm_has_connector linear)
echo "LINEAR_TIER: $_TIER_LINEAR"
If LINEAR tier is MCP or API:
- Fetch issues moved to Done in the last 24h
- Fetch issues currently In Progress
- Fetch any issues marked Blocked or flagged
If LINEAR not available: lean on the roadmap synthesis from the drift check below for any manually tracked status.
Roadmap drift check (query the wiki):
Pull the current plan through the query primitive — one read-side call that synthesizes
the roadmap's current items, instead of reading the page directly (the recipe pattern).
You reason over the cited synthesis the query returns. Print the prompt and dispatch it
with the Agent tool (one subagent); on a host with no Agent tool, follow its steps inline.
source ~/.nanopm/lib/nanopm.sh 2>/dev/null || source .nanopm/lib/nanopm.sh 2>/dev/null || true
nanopm_query_prompt "For a daily standup, synthesize from the wiki: the roadmap's current items — anything marked 'this week' or in the current sprint/NOW — so they can be cross-referenced against today's commits to flag what has no recent progress, plus the single biggest gap from the latest challenge session to anchor today's priorities. Cite each claim, and name what's missing rather than inventing it." none
If the synthesis carries current roadmap items: cross-reference them with the GitHub commits from earlier in this phase — flag any item with no recent commits across any repo. If it surfaces no roadmap at all, skip the drift cross-reference silently.
Granola — recent meetings (last 48h):
Try mcp__claude_ai_Granola__list_meetings with limit: 5.
If available: extract meetings from the last 48h. For each:
- Title, date, participants
- Flag any meeting titled with "user", "customer", "interview", "discovery" → note as "📋 user signal available — run /pm-add-feedback to capture"
If Granola not available: skip silently.
Phase 2: Fetch today's meetings
Try mcp__claude_ai_Google_Calendar__gcal_list_events with:
- calendar_id: "primary"
- time_min: today 00:00:00
- time_max: today 23:59:59
If available, for each event extract:
- Start time, title, duration, attendees count
- Classify: internal sync | external call | user interview | solo block
Prep flag logic:
If an event title contains a feature name or product area AND there are no git commits touching that area in the last 48h → flag as "⚠ no recent progress on this topic"
If Google Calendar not available: skip the MEETINGS section silently.
Phase 3: Generate the briefing
Output the standup briefing — concise, scannable, no fluff:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
STANDUP — {Day, Date} · {project slug}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
YESTERDAY
✓ [{repo}] {commit message}
✓ [{repo}] {commit message}
✓ {if nothing shipped: "No commits in the last 24h"}
{if Granola had a user meeting: "📋 User call with {name} — run /pm-add-feedback to capture signal"}
TODAY'S MEETINGS
{HH:MM} → {event title} ({duration}) {⚠ no recent commits on this topic — if flagged}
{if no calendar connected: omit this section entirely}
PRIORITIES
→ {priority 1 — inferred from roadmap + in-progress items}
→ {priority 2}
→ {priority 3 if relevant}
BLOCKERS
⚠ {any blocked Linear issues, or "None"}
DRIFT
{if something was planned this week but has no commits: flag it here}
{if nothing drifted: "On track"}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Rules for PRIORITIES:
- Infer from: in-progress Linear issues → roadmap current sprint items → CHALLENGES.md biggest gap
- Weight toward items with meetings today (if you have a review at 14:00, that's probably a priority)
- Never list more than 3
- If the roadmap is stale (>20 commits old), flag it: "⚠ ROADMAP.md is {N} commits old — consider /pm-roadmap"
Rules for DRIFT:
- A roadmap item drifted if: it was due this week, has no commits in 48h, and is not marked Done
- Don't flag items that are explicitly blocked — those appear under BLOCKERS
Rules for TODAY'S MEETINGS:
- Show time + title + duration only — no attendee list (too noisy)
- Flag prep gaps (no recent commits on the meeting topic) with ⚠
- If a meeting looks like a user interview (title keywords: user, customer, interview, call, discovery) → append "📋 run /pm-add-feedback after"
- If no meetings today: show "No meetings today"
Phase 4: Write the dated wiki Standup page
Resolve today's page with the helper and write the briefing there. Each run writes a
dated wiki doc — .nanopm/wiki/docs/standups/YYYY-MM-DD.md, one page per day in the
standups/ series folder (the prds/-style layout) — so standup history is preserved
rather than overwritten. Yesterday's standup stays on disk; today gets its own page.
source ~/.nanopm/lib/nanopm.sh 2>/dev/null || source .nanopm/lib/nanopm.sh 2>/dev/null || true
_STANDUP_FILE="$(nanopm_wiki_series_path standups "$(date +%F)")"
nanopm_wiki_doc_frontmatter pm-standup evidence-backed "$(date +%Y-%m-%d)" "{sources}"
Write the file at $(nanopm_wiki_series_path standups "$(date +%F)") as: (a) the frontmatter
block emitted by nanopm_wiki_doc_frontmatter above (substitute {sources} with the real
comma-separated connectors/docs used — e.g. github,linear,calendar,granola,roadmap), then
(b) the SAME briefing body rendered in Phase 3. Do not overwrite any prior day's page.
source ~/.nanopm/lib/nanopm.sh 2>/dev/null || source .nanopm/lib/nanopm.sh 2>/dev/null || true
_STANDUP_FILE="$(nanopm_wiki_doc_path "standup-$(date +%F)")"
nanopm_context_append "{\"skill\":\"pm-standup\",\"outputs\":{\"date\":\"$(date +%Y-%m-%d)\",\"drift\":\"$(grep -c 'DRIFT' "$_STANDUP_FILE" 2>/dev/null || echo 0)\"}}"
nanopm_wiki_doc_log pm-standup "wrote docs/standups/$(date +%F).md"
Do NOT ask the user anything. Do NOT wait for input. Generate and display the briefing immediately.
STATUS: DONE