| name | standup-post |
| description | Use when the user needs to write, generate, or post a daily standup update — pulling together what they did since yesterday from Linear tickets, GitHub PRs/commits, and the prior standup, especially when they say "do my standup", "what did I do yesterday", "draft my standup for |
standup-post
Overview
A daily standup is a delta: what changed since the last standup, not a re-dump of every open ticket. This skill aggregates three sources — the Linear ticket tracker, GitHub activity (merged/opened PRs, pushed commits), and the previous Slack standup — into one formatted post, then emits only the new items since the last run. It keeps an append-only log of prior runs so the "since" window is exact rather than a guessed "last 24 hours", which silently breaks across weekends and PTO.
The whole value is in the boundary math and the dedup. Get the "since last standup" timestamp wrong and you either repeat yesterday's items or drop a Friday-through-Monday gap. Get the dedup wrong and the same piece of work shows up twice — once as a merged PR, once as a closed ticket.
When to Use
Use this skill when the user is:
- Writing their daily standup and wants it assembled from Linear + GitHub + last standup.
- Asking "what did I get done since yesterday / since my last standup".
- Drafting or posting a standup to a Slack channel.
- Setting up a recurring standup that should report the delta, not the full backlog.
Do NOT use this for: weekly/sprint recaps spanning many days (use weekly-recap), retros, or sprint-planning summaries of upcoming work. This skill reports what already happened in a single standup window, not what's planned.
Setup (config.json)
Read config.json in this skill directory first. It holds:
slack_channel — where the standup posts (e.g. #eng-standup).
github_org — org to scope GitHub activity to.
linear_team_id — Linear team whose tickets count.
If any value is empty, call the AskUserQuestion tool to collect it (offer the obvious choices as options where you can — e.g. the user's recent Slack channels for slack_channel). After collecting, offer to persist the answers back into config.json so the next run is zero-prompt. Never invent an org or channel — ask.
Memory (delta-only)
Durable run history lives outside this skill dir at ${CLAUDE_PLUGIN_DATA}/standups.log (the skill dir is wiped on upgrade; ${CLAUDE_PLUGIN_DATA} survives). It is append-only — one line per posted standup. Each line records at minimum:
{"ts":"2026-06-22T09:02:00Z","since":"2026-06-19T09:00:00Z","items":["ENG-412","PR#1183","PR#1186"],"channel":"#eng-standup"}
The delta loop, every run:
- Read the last line of
standups.log. Its ts (in UTC) is the start of this run's window. If the file is missing/empty, this is the first run — default the window to the last business day and say so in the post.
- Window = (last ts) → now. Pull Linear + GitHub activity in that window only.
- Subtract any item ids present in the last run's
items (defense-in-depth against clock skew / re-runs) so nothing is reported twice.
- Emit only the new items.
- Append a new line with this run's
ts, the since you used, and the flat list of item ids you reported.
This is what makes each standup a delta and not a full status dump.
Typical Flow
- Load
config.json (ask + optionally persist if unset).
- Read last
standups.log line → compute the since UTC timestamp.
- Gather, scoped to the window:
- Linear: tickets in
linear_team_id moved to Done/In Review/closed since since.
- GitHub: PRs merged or opened, and commits pushed, in
github_org since since.
- Prior standup: last post text, to carry forward anything still flagged as a blocker.
- Dedup across sources (see Gotchas) — collapse PR+ticket pairs.
- Format as:
- Yesterday / Since last standup — completed + in-flight items, deduped.
- Today — in-progress tickets and open PRs.
- Blockers — carried from the prior standup unless resolved in the window.
- Post to
slack_channel (or hand back the draft if the user wants to review first).
- Append the new
standups.log line.
Gotchas
ALWAYS treat these as real, observed failure modes — each has produced a wrong or embarrassing standup before.
-
The "since last standup" boundary is the last logged run timestamp in UTC — never a hardcoded "last 24 hours". A naïve 24h window posted on Monday drops everything from Friday afternoon through the weekend, and a window posted after PTO drops the whole gap. Always diff against the last ts in standups.log. Store and compare in UTC; a local-time boundary double-counts or skips an hour around DST and timezone changes.
-
Weekend and PTO gaps are a feature of the delta, not a bug to "fix". When the gap since the last run is several days, the window is genuinely several days wide — report all of it. Do not cap the window at one day to "look normal"; that silently hides real work. If the gap is large, say so ("covering since last Thursday") so the reader knows why the post is long.
-
The same work shows up as both a merged PR and a closed ticket — collapse it. A PR that closes ENG-412 and the ENG-412 ticket flipping to Done are one accomplishment. Dedup on the PR→ticket reference (the Fixes ENG-412 / branch-name / Linear-link). Report it once, preferably as the ticket with the PR linked. Listing both inflates the standup and reads as padding.
-
Carry blockers forward, don't regenerate them. A blocker raised yesterday is still a blocker today unless something in the window resolved it. Read the prior standup's blocker section and keep unresolved ones; don't drop a blocker just because no new event mentioned it.
-
Append, never rewrite, standups.log. The log is the only record of where each window started. Truncating or rewriting it corrupts the next run's boundary. One new line per run; never edit prior lines.
-
A re-run in the same window must not double-post. If the last log line's ts is within minutes of now (the user ran it twice), there is no new delta — say "nothing new since your last standup" rather than re-emitting the same items. Step 3's id-subtraction backstops this.
Files
config.json — setup: slack_channel, github_org, linear_team_id (empty by default; collected via AskUserQuestion when unset, optionally persisted back).
${CLAUDE_PLUGIN_DATA}/standups.log — runtime memory (NOT in this dir). Append-only, one line per posted standup; defines each run's delta window. Created on first run.