Skill: alirezarezvani/roadmap-communicator (version 2.1.1)

--- name: roadmap-communicator description: Use when preparing roadmap narratives, release notes, changelogs, or stakeholder updates tailored for executives, engineering teams, and customers. --- # Roadmap Communicator Create clear roadmap communication artifacts for internal and external stakeholders. ## When To Use Use this skill for: - Building roadmap presentations in different formats - Writing stakeholder updates (board, engineering, customers) - Producing release notes (user-facing and internal) - Generating changelogs from git history - Structuring feature announcements ## Roadmap Formats 1. Now / Next / Later - Best for uncertainty and strategic flexibility. - Communicate direction without false precision. 2. Timeline roadmap - Best for fixed-date commitments and launch coordination. - Requires active risk and dependency management. 3. Theme-based roadmap - Best for outcome-led planning and cross-team alignment. - Groups initiatives by problem space or strategic objective. See `references/roadmap-templates.md` for templates. ## Stakeholder Update Patterns ### Board / Executive - Outcome and risk oriented - Focus on progress against strategic goals - Highlight trade-offs and required decisions ### Engineering - Scope, dependencies, and sequencing clarity - Status, blockers, and resourcing implications ### Customers - Value narrative and timing window - What is available now vs upcoming - Clear expectation setting See `references/communication-templates.md` for reusable templates. ## Release Notes Guidance ### User-Facing Release Notes - Lead with user value, not internal implementation details. - Group by workflows or user jobs. - Include migration/behavior changes explicitly. ### Internal Release Notes - Include technical details, operational impact, and known issues. - Capture rollout plan, rollback criteria, and monitoring notes. ## Changelog Generation Use: ```bash python3 scripts/changelog_generator.py --from v1.0.0 --to HEAD ``` Features: - Reads git log range - Parses conventional commit prefixes - Groups entries by type (`feat`, `fix`, `chore`, etc.) - Outputs markdown or plain text ## Feature Announcement Framework 1. Problem context 2. What changed 3. Why it matters 4. Who benefits most 5. How to get started 6. Call to action and feedback channel ## Communication Quality Checklist - [ ] Audience-specific framing is explicit. - [ ] Outcomes and trade-offs are clear. - [ ] Terminology is consistent across artifacts. - [ ] Risks and dependencies are not hidden. - [ ] Next actions and owners are specified.

path: references/communication-templates.md
content: # Communication Templates

## Stakeholder Update Email

Subject: Product roadmap update - [Period]

Hi [Audience],

Here is the [weekly/monthly/quarterly] product update.

- Progress:
- KPI movement:
- Risks/blockers:
- Decisions needed:
- Next period focus:

Thanks,
[Owner]

## User-Facing Release Notes Template

# Release [Version/Date]

## Highlights
- [User value outcome]

## New
- [Feature + benefit]

## Improved
- [Improvement + impact]

## Fixed
- [Issue + user-facing resolution]

## Known Limitations
- [If applicable]

## Internal Release Notes Template

# Internal Release [Version/Date]

## Scope
- Included workstreams and commit range

## Operational Notes
- Rollout plan
- Monitoring checks
- Rollback criteria

## Risks
- Known issues and mitigations

## Feature Announcement Template

Title: [Outcome-focused headline]

1. The problem:
2. The new capability:
3. Why this matters:
4. Who should use it:
5. How to start:
6. Feedback channel:


path: references/roadmap-templates.md
content: # Roadmap Templates

## Now / Next / Later Template

### Now (0-1 quarter)
- Committed initiatives in active execution
- Success metrics and owners
- Dependencies and known risks

### Next (1-2 quarters)
- Prioritized bets with confidence levels
- Discovery items needed before commit
- Resource assumptions

### Later (2+ quarters)
- Strategic themes and directional intent
- Explicitly marked as non-commitment

## Quarterly Roadmap Template

| Quarter | Theme | Key Initiatives | Success Metrics | Risks |
|---|---|---|---|---|
| Q1 |  |  |  |  |
| Q2 |  |  |  |  |
| Q3 |  |  |  |  |
| Q4 |  |  |  |  |

## Theme-Based Roadmap Template

| Theme | Problem Statement | Initiatives | KPI Link | Owner |
|---|---|---|---|---|
| Activation |  |  |  |  |
| Retention |  |  |  |  |
| Expansion |  |  |  |  |

## OKR-Aligned Roadmap Template

| Objective | Key Result | Initiative | Milestone | Team |
|---|---|---|---|---|
|  |  |  |  |  |

Guideline:
- Every initiative should map to an objective or key result.
- Mark items without alignment as candidate de-scope.


path: scripts/changelog_generator.py
content: #!/usr/bin/env python3
"""Generate changelog sections from git log or piped commit messages using conventional commit prefixes."""

import argparse
import shutil
import subprocess
import sys
from collections import defaultdict


SECTIONS = {
    "feat": "Features",
    "fix": "Fixes",
    "docs": "Documentation",
    "refactor": "Refactors",
    "test": "Tests",
    "chore": "Chores",
    "perf": "Performance",
    "ci": "CI",
    "build": "Build",
    "style": "Style",
    "revert": "Reverts",
}

DEMO_COMMITS = [
    "feat: add user dashboard with analytics widgets",
    "feat: implement dark mode toggle",
    "fix: resolve crash on empty CSV import",
    "fix: correct timezone offset in calendar view",
    "docs: update API reference for v2 endpoints",
    "refactor: extract shared validation into utils module",
    "chore: bump dependencies to latest patch versions",
    "perf: optimize database queries for user listing",
]


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        description="Generate changelog from git commits or piped input.",
        epilog="Examples:\n"
               "  %(prog)s --from v1.0.0 --to HEAD\n"
               "  git log --pretty=format:%%s v1.0..HEAD | %(prog)s --stdin\n"
               "  %(prog)s --demo\n",
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )
    parser.add_argument("--from", dest="from_ref", default="HEAD~50",
                        help="Start ref for git log (default: HEAD~50)")
    parser.add_argument("--to", dest="to_ref", default="HEAD",
                        help="End ref for git log (default: HEAD)")
    parser.add_argument("--format", choices=["markdown", "text"], default="markdown",
                        help="Output format (default: markdown)")
    parser.add_argument("--stdin", action="store_true",
                        help="Read commit subjects from stdin instead of git log")
    parser.add_argument("--demo", action="store_true",
                        help="Run with sample data (no git required)")
    return parser.parse_args()


def get_git_log(from_ref: str, to_ref: str) -> list[str]:
    """Get commit subjects from git log. Requires git on PATH and a git repo."""
    if not shutil.which("git"):
        print("Error: git not found on PATH. Use --stdin or --demo instead.", file=sys.stderr)
        sys.exit(1)
    commit_range = f"{from_ref}..{to_ref}"
    cmd = ["git", "log", "--pretty=format:%s", commit_range]
    try:
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
    except subprocess.TimeoutExpired:
        print("Error: git log timed out.", file=sys.stderr)
        sys.exit(1)
    if result.returncode != 0:
        print(f"Error: git log failed: {result.stderr.strip()}", file=sys.stderr)
        sys.exit(1)
    lines = [line.strip() for line in result.stdout.splitlines() if line.strip()]
    return lines


def read_stdin() -> list[str]:
    """Read commit subjects from stdin, one per line."""
    return [line.strip() for line in sys.stdin if line.strip()]


def group_commits(subjects: list[str]) -> dict[str, list[str]]:
    grouped: dict[str, list[str]] = defaultdict(list)

    for subject in subjects:
        commit_type = "other"
        for prefix in SECTIONS:
            if subject.startswith(f"{prefix}:") or subject.startswith(f"{prefix}("):
                commit_type = prefix
                break
        grouped[commit_type].append(subject)

    return grouped


def render_markdown(grouped: dict[str, list[str]]) -> str:
    out = ["# Changelog", ""]
    ordered_types = list(SECTIONS.keys()) + ["other"]
    for commit_type in ordered_types:
        commits = grouped.get(commit_type, [])
        if not commits:
            continue
        header = SECTIONS.get(commit_type, "Other")
        out.append(f"## {header}")
        for item in commits:
            out.append(f"- {item}")
        out.append("")
    return "\n".join(out).rstrip() + "\n"


def render_text(grouped: dict[str, list[str]]) -> str:
    out: list[str] = []
    ordered_types = list(SECTIONS.keys()) + ["other"]
    for commit_type in ordered_types:
        commits = grouped.get(commit_type, [])
        if not commits:
            continue
        header = SECTIONS.get(commit_type, "Other")
        out.append(header.upper())
        for item in commits:
            out.append(f"* {item}")
        out.append("")
    return "\n".join(out).rstrip() + "\n"


def main() -> int:
    args = parse_args()

    if args.demo:
        subjects = DEMO_COMMITS
    elif args.stdin:
        subjects = read_stdin()
    else:
        subjects = get_git_log(args.from_ref, args.to_ref)

    if not subjects:
        print("No commits found.", file=sys.stderr)
        return 0

    grouped = group_commits(subjects)

    if args.format == "markdown":
        print(render_markdown(grouped), end="")
    else:
        print(render_text(grouped), end="")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)