A command-line tool that reads your sprint notes (and, optionally, your team's GitHub activity) and uses Claude to write reflection cards into a Parabol Retrospective meeting — automatically, in the right column, with sources linked.
If your retros tend to start with an awkward five minutes of "…what happened this sprint again?" — this is for you.
- You drop notes into an
inputs/directory (markdown, plain text, or JSON — whatever you have). - (Optional) You point it at one or more GitHub repos.
- You run three commands. The bot pulls everything together, asks Claude to draft cards that match your meeting's prompt columns, lets you review them, and submits them to the meeting.
Each card is short (1–3 sentences), tagged 🤖 so attendees know it's automated, and links to its source (a PR, an issue, etc.) when there's an honest URL to point at.
git clone <this-repo> retro-reflect-bot
cd retro-reflect-bot
pnpm install
cp .env.example .envOpen .env and fill in two values:
PARABOL_PAT— a Parabol Personal Access Token with theMEETINGS_WRITEscope (find PAT settings in your Parabol account)ANTHROPIC_API_KEY— your Claude API key from console.anthropic.com
pnpm cli doctorYou should see green checks for environment variables and the Parabol API. The gh CLI checks may show as warnings — that's fine unless you want to use --github.
mkdir -p inputs
cat > inputs/sprint-23.md <<'EOF'
# Sprint 23 notes
- Three production outages, all caused by a race condition in the billing
worker. We finally fixed it on Wednesday with a transaction.
- The new onboarding flow shipped! Activation rate is up ~12% week-over-week.
- Code review felt slow. Two PRs sat for >3 days each.
EOF# Find your retro's URL — something like https://action.parabol.co/meet/m-12345
RETRO_URL="https://action.parabol.co/meet/m-12345"
pnpm cli gather "$RETRO_URL"
pnpm cli generate
pnpm cli submitYou'll see:
gatherresolve the meeting, list its prompt columns, walkinputs/, and write a run state directory underout/.generateask Claude to draft cards (Pass 1), then review them for redundancy (Pass 2), then print them grouped by column.submitaskSubmit N cards to "Sprint 23 Retro"? [y/N]— typey, and the cards appear in the meeting.
That's it. Stop reading here unless you want to bring in GitHub activity or customize anything.
If your team works in GitHub, the bot can survey one or more repos for the same time period:
pnpm cli gather "$RETRO_URL" \
--since "8 weeks ago" \
--github your-org/your-repo \
--github your-org/your-other-repo
pnpm cli generate
pnpm cli submitThis spins up a Claude agent that calls gh (read-only) to look at merged PRs, open PRs touched in the window, issues + comments, and releases. The agent decides what's worth drilling into; you'll see verbose progress like:
[github] iter 1: gh search prs --repo your-org/your-repo --merged ">=2026-03-11" --json number,title,url,mergedAt
[github] ← 3,140 bytes
[github] iter 2: gh pr view 1842 --repo your-org/your-repo --comments
[github] ← 8,927 bytes
To use this, install the GitHub CLI and authenticate it:
gh auth loginImportant: when prompted, choose "Login with a web browser". SAML-enforced GitHub orgs typically reject classic Personal Access Tokens (
ghp_*). The browser flow uses GitHub CLI's bundled OAuth App (gho_*token), which is accepted by virtually all org policies.pnpm cli doctorwill warn you if your auth is using a classic PAT.
The three commands share state under out/<run-id>/:
out/2026-05-06-143015/
├── meta.json # written by gather
├── context.json # written by gather
├── cards.json # written by generate
└── submission-log.json # written by submit
Want to drop a card you don't agree with? Open out/<run-id>/cards.json, delete it, save, then run submit. Same for context.json between gather and generate if you want to thin the corpus before the LLM sees it.
Each run is independent. gather mints a new run id; generate and submit default to the latest. Pass --run <id> if you want to act on a specific older run.
Just preview, don't submit:
pnpm cli submit --dry-runRenders the cards and exits without touching Parabol.
Run from CI (no prompts):
pnpm cli submit --yesSkips the interactive confirmation. Exit code is non-zero if any card failed to submit.
Different time window:
pnpm cli gather "$RETRO_URL" --since "2026-03-01" --until "2026-03-15"--since and --until accept ISO dates (2026-03-01), compact durations (14d, 2w, 1m), or natural language ("last sprint", "8 weeks ago").
Save tokens with a smaller model:
pnpm cli generate --model claude-sonnet-4-6The default is claude-opus-4-7, which produces the highest-quality cards but costs more per run. Sonnet is a good fallback when context is sparse or you're iterating.
Demo / redact proprietary content:
pnpm cli generate --amend-prompt "Redact proprietary information: replace account names, customer names, internal codenames, and trade secrets with bracketed placeholders like [CLIENT-A] or [PROJECT-X]. Be creative — preserve the shape of each observation but strip identifying detail."--amend-prompt appends additional instructions to the system prompt for both the draft and critique passes, so redaction is applied uniformly. Useful when sharing the bot's output publicly (e.g., demos, screenshots, conference talks) without exposing your team's data. The amendment is not persisted to cards.json's metadata — re-runs require passing it again.
Skip the critique pass:
pnpm cli generate --skip-critiqueReduces generate to one LLM call. Useful when context is sparse and the critique pass would add latency without much benefit.
| Command | Purpose |
|---|---|
doctor |
Verify env, PAT, optional gh install + auth |
inspect <meeting-url> |
Print the meeting's prompt columns |
gather <meeting-url> |
Run all data sources, write out/<run-id>/{meta,context}.json |
generate |
Draft + critique cards via Claude, write cards.json |
submit |
Render, confirm, submit each card via createReflection |
revert |
Remove reflections from the meeting (by run, by content, or all) |
| Flag | Default | Description |
|---|---|---|
--inputs-dir <path> |
./inputs |
Directory of input documents (.md, .txt, .json) |
--since <when> |
2 weeks ago |
Time window start |
--until <when> |
now | Time window end |
--github <owner/repo> |
— | Survey a GitHub repo (repeatable for multi-repo) |
--github-prompt <text> |
default | Override the GitHub agent's mission |
--model <name> |
claude-opus-4-7 |
Claude model id (used by GitHub agent) |
--out-dir <path> |
./out |
Run state directory |
| Flag | Default | Description |
|---|---|---|
--run <id> |
latest | Run to operate on |
--out-dir <path> |
./out |
Run state directory |
--model <name> |
claude-opus-4-7 |
Model id |
--skip-critique |
off | Skip the critique pass (one LLM call instead of two) |
--amend-prompt <text> |
— | Extra instructions appended to the system prompt for both passes (e.g. redaction) |
| Flag | Default | Description |
|---|---|---|
--run <id> |
latest | Run whose meeting to operate on (and, in default mode, whose submission-log scopes the deletion) |
--out-dir <path> |
./out |
Run state directory |
--all |
off | Remove every reflection in the meeting |
--substring [text] |
— / retro-reflect-bot if bare |
Remove every reflection in the meeting whose plaintext content contains <text> |
--yes |
off | Skip the interactive confirm |
--all and --substring are mutually exclusive. Without either, revert reads submission-log.json and removes only the reflections submitted in the named run — useful for "undo my last submit." --substring (bare) defaults to the bot's tag (retro-reflect-bot), which is handy when run state is gone but you want to clear only bot-generated cards.
# Undo the most recent submit
pnpm cli revert
# Remove anything the bot ever wrote in this meeting
pnpm cli revert --substring
# Remove every reflection (yours and others) — confirms first
pnpm cli revert --allrevert requires the meeting to still be in the Reflect or Group phase (Parabol's API rejects removals after the group phase ends).
| Flag | Default | Description |
|---|---|---|
--run <id> |
latest | Run to submit |
--out-dir <path> |
./out |
Run state directory |
--dry-run |
off | Render the cards and exit |
--yes |
off | Skip the interactive confirm |
Cards use a small subset of markdown for inline rich formatting. The bot writes:
[anchor text](https://...)— inline links to PRs, issues, documents, etc. Used liberally for source-of-truth references.**bold**,*italic*,`code`— emphasis where it helps readability.
The submitted card looks like this in the meeting (rendered):
Three production outages this sprint, all rooted in the billing-worker race condition. Fixed in PR #1842.
🤖 retro-reflect-bot
The 🤖 line is how attendees can tell at a glance which cards are bot-generated.
| Variable | Default | Description |
|---|---|---|
PARABOL_PAT |
— | Parabol PAT, must include MEETINGS_WRITE scope |
ANTHROPIC_API_KEY |
— | Claude API key |
PARABOL_BASE_URL |
https://action.parabol.co |
Override for self-hosted or staging |
Parabol API rejected your PAT (HTTP 401/403)
Your PAT is missing, expired, or doesn't include the MEETINGS_WRITE scope. Re-mint it in Parabol and update .env.
Meeting m-XXX Reflect phase is complete
The bot only adds cards while the meeting is in the Reflect phase. Move the meeting back to Reflect (or run on a different meeting).
No runs found in ./out
You need to run gather first. Each subsequent command (generate, submit) defaults to the latest run.
<Org> blocks classic Personal Access Tokens
Your gh is authed with a classic PAT (ghp_*) and the org enforces SAML. Run gh auth logout && gh auth login and choose "Login with a web browser". If pnpm cli doctor still shows OAuth (gho_*) but you're hitting this error, check env | grep -E '^(GITHUB|GH)_TOKEN' — an environment variable with a classic PAT will override the stored OAuth credential. unset GITHUB_TOKEN GH_TOKEN for the session.
Model response hit max_tokens (8192) and was truncated
Your gathered context produced more cards than fit in one Claude response. Narrow --since, thin inputs/, or pass --model claude-sonnet-4-6 for a more concise output.
Gathered NNN,NNN characters of content (> 200,000 soft limit)
Informational. Generation will work but be slower and more expensive, and is more likely to hit max_tokens. Narrow --since or thin inputs/ if you want.
Long-running GitHub gather
The agent can take a few minutes for active repos. If a single run goes longer than ~5 minutes, narrow --since or run with --github-prompt "<focused mission>".
Cards too long / truncated in the meeting
Cards are capped at 2000 characters of stringified TipTap content. The bot shortens overflowing prose with an ellipsis and warns. If this happens often, lower the model output via --model claude-sonnet-4-6.
If you want to understand or extend the code, the design spec lives at docs/superpowers/specs/2026-05-06-retro-reflect-bot-design.md. Per-sprint implementation plans are in docs/superpowers/plans/.
The short version: three commands sharing state on disk; a DataSource interface (files + GitHub today, anything else tomorrow); a two-pass LLM pipeline (draft → critique); the GitHub source is itself a Claude agent that calls gh as a sandboxed tool.
MIT.