# Stakeholder Update

> Generate a weekly / monthly / launch stakeholder update — synthesises PRs, closed issues, AgDRs, and roadmap into a narrative.

- Skill: `me2resh/stakeholder-update` (Agent Skill)
- Install (CLI): `npx skillmds@latest add me2resh/stakeholder-update`
- Raw SKILL.md: https://api.skillmd.com/api/skills/me2resh/stakeholder-update/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Product & Planning
- Author: me2resh (https://skillmd.com/u/me2resh)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/me2resh/stakeholder-update

---


# /stakeholder-update — Stakeholder Update Generator

Read `.claude/rules/writing-standard.md`. Use the **controlled technical writing profile** for the
stakeholder update: open with the outcome, impact, and next action.

Synthesises recent activity into a stakeholder-facing update. The skill is audience-aware: weekly is dense and tactical for the team, monthly is strategic for leadership, launch is celebratory and metrics-heavy for the broader org or external stakeholders.

## Path resolution

Read the registry path via `portfolio_registry`, the per-project docs dir via `portfolio_projects_dir`, and the ideas backlog via `portfolio_ideas_backlog` — all from `.claude/hooks/_lib-portfolio-paths.sh`. Source the helper at the top of any bash block that touches those paths:

```bash
source "$(git rev-parse --show-toplevel)/.claude/hooks/_lib-read-config.sh"
source "$(git rev-parse --show-toplevel)/.claude/hooks/_lib-portfolio-paths.sh"
source "$(git rev-parse --show-toplevel)/.claude/hooks/_lib-tracker.sh"
projects_dir=$(portfolio_projects_dir)
registry=$(portfolio_registry)
```

Defaults match today's single-fork layout (`./apexyard.projects.yaml`, `./projects`, `./projects/ideas-backlog.md`). Adopters in split-portfolio mode override the `portfolio.{registry, projects_dir, ideas_backlog}` keys in `.claude/project-config.json`. Don't hardcode literal `apexyard.projects.yaml` or `projects/` paths in bash blocks — the helper resolves whichever mode the adopter is in. See `docs/multi-project.md`.

**Write targets** (see me2resh/apexyard#373 + #443): paths documented as `projects/<name>/X` in this skill are canonical adopter-facing forms — implement them in bash as `"${projects_dir}/<name>/X"`. Never construct from `"${PWD}/projects/..."`, `"$(git rev-parse --show-toplevel)/projects/..."`, or a literal `./projects/...` — those break in split-portfolio v2 mode where `projects_dir` resolves to a sibling repo.

**REQUIRED per-block preamble** (see #443): Claude executes each ```bash``` block as a separate shell invocation. The `projects_dir` assignment from the Path resolution section above does NOT carry into later blocks. Every bash block that writes to a `projects/<name>/X` path MUST start with this three-line preamble so it's self-contained:

```bash
source "$(git rev-parse --show-toplevel)/.claude/hooks/_lib-read-config.sh"
source "$(git rev-parse --show-toplevel)/.claude/hooks/_lib-portfolio-paths.sh"
projects_dir=$(portfolio_projects_dir)
# ... now write to "${projects_dir}/<name>/X"
```

The Path resolution section's example sources the helper *once* for documentation purposes; it does not absolve later blocks from sourcing it themselves. Treat each ```bash``` fence as a fresh process.

## Usage

```
/stakeholder-update weekly
/stakeholder-update monthly
/stakeholder-update launch
/stakeholder-update weekly --project example-app
```

## Scope

Aggregated across every project in `apexyard.projects.yaml` (the registry at the root of your ops repo), unless `--project <name>` is passed to scope to one.

## Inputs

The skill pulls from:

| Source | What it gives | Axis |
|--------|---------------|------|
| `gh pr list --state merged --search "merged:>=<since>"` | What shipped | forge (#711) |
| `tracker_list "$repo" state=closed since=<since>` | What got resolved | issue ✓ |
| `git log --since=<since> --oneline` | Commit volume / themes | — |
| `docs/agdr/AgDR-*.md` (in this period, inside each project) | Decisions made | — |
| `projects/<name>/roadmap.md` | Strategic direction | — |
| `gh pr list --state open` | What's in flight | forge (#711) |
| `projects/ideas-backlog.md` | Ideas captured | — |

> **Scope caveat (forge axis, #711).** The **PR** rows still call `gh pr list` (the PR/MR forge abstraction is a separate ticket), so `/stakeholder-update` is *issue-axis* tracker-agnostic — the "resolved issues" row works on GitLab-tracked projects; the "shipped / in-flight PRs" rows are GitHub-only until #711. The `since` filter on non-GitHub trackers is applied client-side on `updatedAt` (gh applies it server-side via the `closed:>=` search qualifier).

`<since>` is computed from the update type:

| Type | Window |
|------|--------|
| weekly | 7 days |
| monthly | 30 days |
| launch | last release tag → today (or 90 days if no tag) |

## Audience tailoring

### Weekly (tactical, for the team)

- Dense
- Bullet-heavy
- Includes PR numbers and issue links
- Highlights blockers and risks
- ~300–500 words
- Tone: "here's what happened, here's what's next, here's what's stuck"

### Monthly (strategic, for leadership)

- Narrative
- Roadmap-anchored
- Includes velocity and quality metrics
- Highlights strategic decisions (AgDRs)
- ~500–800 words
- Tone: "we're tracking against the plan; here's what changed and what it means"

### Launch (celebratory, for external/wider audience)

- Headline-driven
- Outcome-focused (not commit-focused)
- Includes user-visible changes only
- Quotes / screenshots placeholders
- Metrics that matter to non-engineers
- ~400–600 words
- Tone: "here's what's now possible, here's what it means for users"

## Templates

### Weekly

```markdown
# Weekly Update — {project} — Week of {YYYY-MM-DD}

**Author**: @{git user} · **Period**: last 7 days

## Shipped
- {#PR} — {title} ({PR url})
- ...

## In Flight
- {#PR or #Issue} — {title} — {status}
- ...

## Decisions
- AgDR-{NNNN}: {title}
- ...

## Blockers
- {item} — {what's needed to unblock}
- ...

## Next Week
- {top 3 items from "Now" milestone}
- ...

## Metrics
- PRs merged: {N}
- Issues closed: {N}
- Open PRs: {N}
- Avg. PR review time: {…}
```

### Monthly

```markdown
# Monthly Update — {project} — {Month YYYY}

**Author**: @{git user} · **Period**: {start} to {end}

## Highlights
{2–3 sentence narrative summary of the month}

## Roadmap Progress
| Item | Status | Notes |
|------|--------|-------|
| ... | ... | ... |

## Shipped This Month
{Themed list, not commit-by-commit. Group by area.}

### {Area 1}
- {What changed and why it matters}

### {Area 2}
- ...

## Strategic Decisions
{AgDRs from this month, with one-line context for each}

## Quality & Health
- Test coverage: {…}
- CI green rate: {…}
- Open critical issues: {…}
- Open security findings: {…}

## Looking Ahead — Next Month
{Top 3–5 outcomes we're targeting}

## Risks
{1–3 risks worth surfacing to leadership}
```

### Launch

```markdown
# {Project / Feature} — Launch Update

**Date**: {YYYY-MM-DD} · **Owner**: @{git user}

## What launched
{One-paragraph headline. What did users get?}

## Why it matters
{2–3 bullets on user value}

## What's now possible
- {capability 1}
- {capability 2}
- {capability 3}

## By the numbers
- {leading indicator}
- {feature scope: lines / files / endpoints / pages — only if relevant}
- {launch blast radius: % of users, regions, etc.}

## Behind the scenes
{One-paragraph credit reel: who built it, what was hard}

## What's next
{2–3 follow-up items already on the roadmap}

## Try it
{Link / steps to actually use the thing}
```

## Process

1. Parse the update type from `$ARGUMENTS` (default: `weekly`)
2. Compute `<since>` based on type
3. Read the registry; resolve `--project` if passed, otherwise iterate all projects
4. Pull all inputs in parallel
5. Synthesise the update using the matching template
6. Print to stdout, **and** offer to write it to `projects/<name>/updates/{type}-{YYYY-MM-DD}.md`
7. Offer to post to the team's communication channel (Slack/Discord) — only as a follow-up suggestion, never automatic

## Portfolio rollup

Without `--project`, generate one section per project, prefixed with the project name and bounded by separators. Add a portfolio summary at the top:

```
PORTFOLIO ROLLUP — Week of 2026-04-06

3 projects · 12 PRs merged · 18 issues closed · 4 AgDRs

═══════════════════════════════════════
example-app — Weekly
═══════════════════════════════════════
{full weekly update}

═══════════════════════════════════════
billing-api — Weekly
═══════════════════════════════════════
{full weekly update}

═══════════════════════════════════════
marketing-site — Weekly
═══════════════════════════════════════
{full weekly update}
```

## Rules

1. **Audience-aware** — never use weekly format for a launch update
2. **Always include the period** — start and end dates explicit
3. **Never invent metrics** — if a metric can't be computed, omit it
4. **Use real PR/issue numbers** — every claim links to evidence
5. **AgDRs are first-class** — decisions belong in updates, not just code
6. **Don't auto-publish** — write the file, suggest the channel, but never post on the user's behalf
7. **Scope-aware** — one section per project, portfolio rollup when no `--project` flag
8. **Tone matches type** — terse (weekly), narrative (monthly), celebratory (launch)

## Related skills

- `/status` — what's currently in flight
- `/projects` — portfolio table
- `/roadmap` — what's planned
- `/decide` — produces AgDRs that this skill cites

---

*Part of [ApexYard](https://github.com/me2resh/apexyard) — multi-project SDLC framework for Claude Code · MIT.*

