update
Error handling convention for ALL bash commands in this skill:
- IF command exits non-zero → capture stderr, print diagnostic, fallback gracefully:
✗ {command} failed: {stderr summary} → Try: {suggested fix} → Fallback: {what the skill does instead} - Never stop the entire skill for a single command failure — degrade and skip the affected section
0. Parse Arguments & Validate Environment
Parse mode from $ARGUMENTS:
- IF empty or "full" → MODE=full
- IF "quick" → MODE=quick
- IF "risks" → MODE=risks
- IF "strategy" → MODE=strategy
- IF unrecognized → show usage and stop: "Usage: /product:update [quick|full|risks|strategy]"
Check git repo:
- Run
git rev-parse --is-inside-work-tree 2>&1 - IF exit code non-zero → stop:
"✗ Not inside a git repo. Run
git initor cd into your project."
Check Linear CLI:
- Run
linear auth whoami 2>&1 - IF command not found → set LINEAR_AVAILABLE=false, warn:
✗ linear CLI not found → Try: Install from https://github.com/schpet/linear-cli → Fallback: Generating update from git data only (Limited risk analysis) - ELIF output contains auth error or exit code non-zero → set LINEAR_AVAILABLE=false, warn:
✗ linear CLI not authenticated → Try: Run `linear auth` to log in → Fallback: Generating update from git data only - ELSE → LINEAR_AVAILABLE=true
Read project scope:
- IF
.linear-projectexists:- Read and trim:
PROJECT=$(cat .linear-project | tr -d '\n' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') - IF empty after trim → warn and continue unscoped
- ELIF LINEAR_AVAILABLE → validate via
linear project list 2>&1 | grep -qi "$PROJECT"- IF not found → warn: "Project '{PROJECT}' not found in Linear. Continuing unscoped."
- ELSE → note: "Scoped to: {PROJECT}"
- Build PROJECT_FLAG:
${PROJECT:+--project '$PROJECT'}
- Read and trim:
- IF missing → continue unscoped (don't interrupt update flow)
Print header:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
PRODUCT ► UPDATE [{PROJECT or "All Projects"}] ({MODE})
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. Gather Project State
Collect data from all available sources. Run independent commands in parallel.
From Linear (skip if LINEAR_AVAILABLE=false):
linear issue list -s started --limit 20 $PROJECT_FLAG 2>&1→ in-progress worklinear issue list -s completed --limit 20 $PROJECT_FLAG 2>&1→ recently completed (velocity data)linear issue list -s unstarted --limit 20 $PROJECT_FLAG 2>&1→ remaining backloglinear issue list --limit 50 $PROJECT_FLAG 2>&1→ all recent issues (scope analysis)- For each command: IF fails → warn, set that data to empty, continue
From Git:
git log --oneline --since="7 days ago" 2>&1→ this week's commitsgit log --oneline --since="14 days ago" 2>&1→ last two weeks (trend comparison)git shortlog -sn --since="14 days ago" 2>&1→ contributor activitygit diff --stat HEAD~20 2>/dev/null→ recent change volume- IF any git command fails (e.g., not enough commits) → use available data, skip what's missing
From GSD (if .planning/ exists):
- Read
.planning/STATE.mdfor current phase - Read
.planning/ROADMAP.mdfor overall progress (completed phases / total phases) - Read
.planning/PROJECT.mdfor stated objectives and timeline - IF files missing → skip silently
From Risk Register (if .product-risks.json exists at repo root):
- Read and parse the file
- Load previous risks for trend comparison (new vs mitigated vs recurring)
- IF file is malformed → warn: "Risk register exists but couldn't be parsed. Starting fresh."
Compute derived metrics:
- VELOCITY_THIS_WEEK = count of issues completed in last 7 days
- VELOCITY_LAST_WEEK = count of issues completed 7-14 days ago
- COMMITS_THIS_WEEK = count of commits in last 7 days
- COMMITS_LAST_WEEK = count of commits 7-14 days ago
- TOTAL_BACKLOG = count of unstarted issues
- TOTAL_IN_PROGRESS = count of started issues
IF MODE=quick → skip to Step 4.
2. Analyze Risks
Automatically detect risks across four categories. Each risk gets a severity level: HIGH (❌), MEDIUM (⚠), LOW (○).
Schedule Risks
Overdue issues → HIGH:
- For each in-progress issue with a due date in the past → flag as HIGH
- "ENG-123 'Feature X' was due {date} — N days overdue"
Velocity decline → MEDIUM:
- IF VELOCITY_THIS_WEEK < VELOCITY_LAST_WEEK AND VELOCITY_LAST_WEEK > 0: "Velocity down: {this_week} issues closed this week vs {last_week} last week"
- IF VELOCITY_THIS_WEEK = 0 AND VELOCITY_LAST_WEEK > 0 → escalate to HIGH: "No issues completed this week (vs {last_week} last week)"
Backlog vs capacity → HIGH:
- IF GSD PROJECT.md has a target date AND VELOCITY_THIS_WEEK > 0:
- WEEKS_REMAINING = (target_date - today) / 7
- ESTIMATED_CAPACITY = VELOCITY_THIS_WEEK * WEEKS_REMAINING
- IF TOTAL_BACKLOG > ESTIMATED_CAPACITY * 1.5 → HIGH: "Remaining work ({TOTAL_BACKLOG} issues) exceeds estimated capacity ({ESTIMATED_CAPACITY}) by deadline"
Scope Risks
Mid-sprint additions → MEDIUM:
- Count issues created in the last 7 days that are now in-progress or were not in original backlog
- IF > 0 → "N new issues added mid-sprint (potential scope creep)"
Unbounded issues → LOW:
- Count in-progress issues with no estimate/points
- IF > 0 → "N in-progress issues have no estimate"
Issue count growth → MEDIUM:
- Compare total issue count now vs what risk register recorded last time (if available)
- IF growth > 20% → "Total issue count grew by N% since last update"
Execution Risks
Blocked work → HIGH per blocked item:
- From Linear data, identify issues with blocking relations
- "ENG-789 blocked by ENG-012 ({title}) for N days"
Stale work → MEDIUM:
- In-progress issues with no commits referencing them in 48h+
- "ENG-456 in-progress with no commits in N days"
Single-contributor concentration → MEDIUM:
- From
git shortlog -sn, check if one contributor has > 80% of commits in last 14 days - IF so → "N% of recent commits from one contributor — bus factor risk"
No recent activity → HIGH:
- IF COMMITS_THIS_WEEK = 0 → "No commits in the last 7 days"
Technical Risks
Code health proxy:
- Run
grep -rn -E 'TODO|FIXME|HACK|@ts-ignore' src/ app/ lib/ components/ 2>/dev/null | wc -l - IF count < 10 → LOW (or skip)
- IF 10-30 → MEDIUM: "N code markers (TODO/FIXME/HACK) in codebase. Run
/tech-debtfor a prioritized audit." - IF > 30 → HIGH: "N code markers — technical debt accumulating. Run
/tech-debtfor a prioritized remediation plan." - IF grep fails (dirs don't exist) → skip
Present risk assessment:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
RISK ASSESSMENT
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Schedule:
❌ HIGH — 2 overdue issues (ENG-123 due Mar 28, ENG-456 due Mar 30)
⚠ MEDIUM — Velocity down: 4 closed this week vs 7 last week
Scope:
⚠ MEDIUM — 3 new issues added mid-sprint
○ LOW — 5 issues have no estimate
Execution:
❌ HIGH — ENG-789 blocked by ENG-012 (3 days)
⚠ MEDIUM — ENG-456 stale: no commits in 4 days
Technical:
⚠ MEDIUM — 18 code markers (TODO/FIXME/HACK)
{IF risk register exists:}
Trend: 2 new risks since last update, 1 mitigated, 3 recurring
Count totals: N high, N medium, N low.
IF MODE=risks → skip to Step 5 (save and route).
3. Strategic Review
IF MODE=quick → skip to Step 4.
Progress Summary:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
STRATEGIC REVIEW
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Progress:
Completed this period: N issues
- {top 3-5 by impact, human-readable titles}
In progress: N issues
Remaining backlog: N issues
Velocity: {this_week}/week (trend: ↑ / ↓ / → vs last week)
{IF GSD ROADMAP.md exists:}
Roadmap: Phase {current} of {total} — {phase_name}
{completed_phases} phases complete, {remaining_phases} remaining
{IF target date exists:}
Timeline: {weeks_remaining} weeks to deadline
At current velocity: estimated {estimated_weeks} weeks to clear backlog
Status: ON TRACK / TIGHT / AT RISK
Recommendations (2-4 concrete actions based on risks):
Generate actionable recommendations. Examples:
- "Unblock ENG-789 by prioritizing ENG-012 — it's the only blocker"
- "Consider descoping ENG-345 (low priority, added mid-sprint) to protect the deadline"
- "Add estimates to the 5 unbounded issues for better forecasting"
- "Run
/tech-debtfor a prioritized debt audit, or/product:maintain --fixfor quick auto-fixes"
Ask the PM: "Anything to add or adjust? Any context I'm missing about these risks?"
- IF PM adds context → incorporate into the update
- IF PM adjusts recommendations → update
- IF looks good → proceed
4. Generate Project Update
Executive Summary:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
PROJECT UPDATE
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
{PROJECT or repo name} — Week of {current Monday's date}
Status: ON TRACK / AT RISK / OFF TRACK
Highlights:
✓ {Top 3-5 completed items, human-readable}
In Progress:
→ {Top 3-5 active items}
{IF risks found:}
Risks:
{Top 2-3 risks by severity, human-readable}
Next Week:
○ {Top 3-5 planned focus items}
Determine overall status:
- ON TRACK: 0 high risks, velocity stable or up
- AT RISK: 1-2 high risks OR velocity down > 30%
- OFF TRACK: 3+ high risks OR no activity OR estimated completion past deadline
5. Generate WhatsApp Message
First-time preference check: Ask: "Do you want emoji in the WhatsApp messages? (Yes / No / Minimal)"
- Store preference for this session
- IF user has responded before in this conversation → use their preference
Generate the message:
WhatsApp messages use plain text only — no markdown rendering. Use WhatsApp formatting where helpful:
- Bold:
*bold text* - Line breaks for readability
- Keep under 500 characters for quick mode, under 800 for full mode
Quick mode template:
WhatsApp Message (copy below):
─────────────────────────────
*{project-name} Update* — {date}
*Done:*
- {highlight 1}
- {highlight 2}
- {highlight 3}
*Risks:*
- {top risk, plain language}
*Next:*
- {focus 1}
- {focus 2}
*Status: {ON TRACK / AT RISK / OFF TRACK}*
Full mode template (includes more detail):
WhatsApp Message (copy below):
─────────────────────────────
*{project-name} Weekly Update*
{date range}
*What we shipped:*
- {completed item 1}
- {completed item 2}
- {completed item 3}
*In progress:*
- {active item 1} — {brief status}
- {active item 2} — {brief status}
*Risks flagged:*
- {risk 1, plain language}
- {risk 2, plain language}
*Focus for next week:*
- {priority 1}
- {priority 2}
*Overall: {STATUS}*
{IF any risk is HIGH:}
Happy to jump on a quick call to discuss the flagged risks.
Key rules for WhatsApp messages:
- Strip all issue IDs (ENG-123) — PMs communicate in plain language
- Strip branch names, commit hashes, technical jargon
- Use human-readable descriptions ("Login page shipped" not "ENG-123 merged")
- Keep language direct and confident
Interactive refinement: Ask: "How does this look? You can:"
- Adjust tone → "more formal" / "more casual" / "shorter"
- Add context → "mention that we're waiting on design feedback for X"
- Highlight something → "emphasize the auth system launch"
- Change a detail → free-form edit
- Looks good → finalize
IF PM requests changes → regenerate the message with adjustments and ask again. Continue until PM approves or says "looks good."
6. Save & Route
Update Risk Register
IF .product-risks.json exists:
- Load existing risks
- Mark risks that no longer appear as "mitigated" (update status, set lastSeen to today)
- Add new risks detected this run (assign incrementing IDs: R-001, R-002, etc.)
- Update lastSeen date for recurring risks
- Write updated file
IF .product-risks.json does NOT exist:
- Ask: "Save a risk register to track risks over time? This helps spot trends in future updates."
- Yes → create the file with current risks
- No → skip
Risk register schema (.product-risks.json):
{
"lastUpdated": "2026-04-02",
"projectName": "{project-name}",
"risks": [
{
"id": "R-001",
"description": "2 overdue issues past deadline",
"category": "schedule",
"severity": "high",
"status": "open",
"firstSeen": "2026-03-28",
"lastSeen": "2026-04-02",
"relatedIssues": ["ENG-123", "ENG-456"]
}
],
"history": [
{
"date": "2026-04-02",
"status": "AT RISK",
"highRisks": 2,
"mediumRisks": 3,
"lowRisks": 1,
"velocity": 4,
"backlogSize": 15
}
]
}
Route to Next Action
Based on the final state:
- IF high risks involving blocked work → "Unblock the critical path. Run
/product:start-task ENG-XXXto pick up the blocker" - IF high technical risks → "Run
/tech-debtto audit and prioritize technical debt remediation" - IF high schedule risks → "Run
/product:syncto reconcile stale issues and update Linear" - IF strategy recommended descoping → "Update the backlog in Linear to reflect the adjusted scope"
- IF everything healthy → "Project is on track. Run
/product:update quicknext week for a fast WhatsApp update." - Always suggest: "Run
/product:daily-standuptomorrow for the daily view."
<success_criteria>
- Project state gathered from Linear, git, and GSD with graceful fallback for each source
- All bash commands have exit code checking and fallback behavior
- Risks detected across 4 categories (schedule, scope, execution, technical) with correct severity
- Risk register created or updated (if user opted in)
- Executive summary generated with clear ON TRACK / AT RISK / OFF TRACK status
- WhatsApp message generated in plain text, no jargon, copy-pasteable
- PM had opportunity to adjust tone, add context, and highlight items before finalizing
- Interactive refinement loop until PM approves
- Clear next action suggested based on risk profile </success_criteria>
More from seangjr/product-skills
daily-standup
Morning standup — surface blockers, stale work, and today's focus
8sync
Sync project state with Linear — detect gaps, consolidate objectives, clean up, route to next action
7maintain
Codebase health check — type errors, lint, git hygiene, deps, Linear, build, and auto-fix
7start-task
Pick up the next Linear issue — validate context, create branch, plan approach
7init-project
Scaffold a new project with Next.js, GSD, skills, Linear integration, and MCP config
7finish-task
Wrap up current task — commit, update Linear, optionally create PR, route to next
7