update

Installation
SKILL.md

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 init or 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-project exists:
    • 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'}
  • 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 work
  • linear 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 backlog
  • linear 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 commits
  • git log --oneline --since="14 days ago" 2>&1 → last two weeks (trend comparison)
  • git shortlog -sn --since="14 days ago" 2>&1 → contributor activity
  • git 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.md for current phase
  • Read .planning/ROADMAP.md for overall progress (completed phases / total phases)
  • Read .planning/PROJECT.md for 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-debt for a prioritized audit."
  • IF > 30 → HIGH: "N code markers — technical debt accumulating. Run /tech-debt for 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-debt for a prioritized debt audit, or /product:maintain --fix for 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-XXX to pick up the blocker"
  • IF high technical risks → "Run /tech-debt to audit and prioritize technical debt remediation"
  • IF high schedule risks → "Run /product:sync to 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 quick next week for a fast WhatsApp update."
  • Always suggest: "Run /product:daily-standup tomorrow 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>
Related skills
Installs
6
First Seen
Apr 2, 2026