Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Compose a daily standup in the team's Slack format (🔨 Done today / 📅 Planned for tomorrow / 🚧 Blockers / risks), aggregating recent PRs, reviews, and CI from tetherto/qvac. Use when asked for a daily update, standup, EOD, or invoking /qv-devops-daily-update.
.claude/skills/tetherto-qv-devops-daily-update/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-07 | ✗→✓ | ▲ Improved | 205% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 249% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 271% | 0% |
| case-18 | ✗→✓ | ▲ Improved | 146% | 0% |
| case-20 | ✗→✓ | ▲ Improved | 403% | 0% |
Composes a standup / EOD update in the team's standard Slack format and writes it to a temp file ready to paste. Sourced from the user's GitHub activity in tetherto/qvac plus optional Asana context.
The skill is read-only with respect to GitHub state and the local working tree. It NEVER posts the message — the user copies it manually. The canonical Slack form is documented in Step 8.
Use when:
/qv-devops-daily-updategh CLI installed and authenticated (gh auth status)tetherto/qvac--since <ISO date | Nd | Nw> — defaults to yesterday 00:00 in the user's local timezone. The default 24-hour lookback works for both EOD posts (late evening) and morning standups; extend it for Monday-after-weekend (--since 3d) or post-holiday (--since 1w).--format slack | markdown — defaults to slack. The Slack form is what gets pasted; Markdown is the chat preview form (**bold**, [text](URL)) and is also accepted by Asana rich-text comments.--no-asana — skip the Asana lookup even if the MCP is available.If the user did not specify, default to yesterday 00:00 / slack.
This skill is read-only. It does NOT:
~/.cache/The skill MAY write its assembled output to /tmp/devops-daily-update-<YYYY-MM-DD>.txt so the user can pbcopy < <path>. The extension is .txt (not .md) because the canonical form is Slack mrkdwn, not GitHub-flavored Markdown.
Total shell calls per run: ≤ 6 (one per data source + one for the timestamp + one to write the temp file). Cache gh api user and reuse via Read for the rest of the session. If a data source errors (e.g., Asana MCP not configured), continue with that section's items missing from the aggregate rather than failing the whole skill — the canonical form does not have an "Asana" section, so missing Asana data only thins out the bullet pools, not the layout.
bashSINCE="$(date -u -v-1d -j -f "%Y-%m-%d" "$(date -u +%Y-%m-%d)" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null \ || date -u -d 'yesterday 00:00' +%Y-%m-%dT%H:%M:%SZ)" echo "$SINCE"
Parse --since if provided (Nd → N days, Nw → N weeks, ISO date → that date 00:00 UTC).
bashgh api user --jq '.login' > /tmp/devops-daily-update-user.txt
Reuse via Read for the rest of the run.
bashgh search prs \ --repo tetherto/qvac \ --author "@me" \ --merged-at ">=$SINCE" \ --json number,title,url,closedAt \ --limit 30 \ > /tmp/devops-daily-update-merged.json
These feed 🔨 Done today. gh search prs --json does not expose mergedAt, additions, or deletions — only closedAt is available, and the --merged-at ">=$SINCE" filter already guarantees the result set is merged-in-window. If size signal is needed for the bullet wording, fetch it per-PR via gh pr view <num> --json additions,deletions (one extra call per PR — only do this when the user asks for it).
bashnode .cursor/skills/_lib/pr-skills/pr-status.mjs --mode my \ > /tmp/devops-daily-update-my.txt 2> /tmp/devops-daily-update-my.stderr gh search prs \ --repo tetherto/qvac \ --review-requested "@me" \ --state open \ --json number,title,url,author,updatedAt \ --limit 30 \ > /tmp/devops-daily-update-reviews-owed.json
If pr-status.mjs stderr contains SLACK_VALIDATION_REQUIRED, follow the validation gate in pr-mine's workflow (step 2). Do not present the daily update until the gate clears.
Output routing:
$SINCE (i.e., I pushed work on them today) → 🔨 Done today with the action addressed comments on the PR (when the recent commits follow a review event) or pushed updates on <topic> (otherwise).📅 Planned for tomorrow with the action continue / wrap up <topic>.--review-requested "@me") → 📅 Planned for tomorrow as review #<num> — <title> by <author>. Cap surfaced reviews at 5 (sorted by updatedAt desc — most recent first); if the queue is longer, append a single line (+N more review requests in queue — run /qv-devops-pr-status for the full list). A standup with 30 review-bullets is unreadable.mergeable: CONFLICTING → 🚧 Blockers / risks as conflicts on #<num> — needs rebase.🚧 Blockers / risks as stale review on #<num> — pinged <reviewer> on <date>.gh run list does not have an author filter. Approximate the user's runs by scoping to recent PR head branches:
bashgh run list \ --repo tetherto/qvac \ --created ">=$SINCE" \ --limit 50 \ --json conclusion,event,headBranch,name,url,workflowName,headSha,displayTitle \ > /tmp/devops-daily-update-runs.json
Filter client-side: keep runs where headBranch matches one of the user's PRs from steps 3 or 4. Failed runs feed 🚧 Blockers / risks as CI failing on #<num> — <workflowName>. In-progress / queued runs are NOT surfaced (too noisy for a daily update).
If the Asana MCP is available and --no-asana was not passed, call the appropriate tool (read the descriptor first per the agentic-automation rule) to fetch the user's tasks. Filter to:
📅 Planned for tomorrow as <TICKET>: <task title>🚧 Blockers / risks as <TICKET>: blocked — <reason from notes>Asana tickets in the QVAC project follow the QVAC-\d+ format and slot directly into the bullet shape.
If Asana is unavailable or --no-asana is set, skip this step. The output will rely on GitHub-derived items only.
Before writing /tmp/devops-daily-update-<YYYY-MM-DD>.txt, run a regex check on every PR title, branch name, run name, Asana task title, and any user-provided extras:
(sk_live_|AIza[0-9A-Za-z\-_]{35}|AKIA[0-9A-Z]{16}|ghp_[A-Za-z0-9]{36}|gho_|github_pat_|xoxb-|-----BEGIN [A-Z ]+ KEY-----)If any string matches, redact the matching span ([REDACTED]) and add a chat-only note: "Daily update redacted N suspicious tokens — review the source PRs/runs manually." Never include the raw matched string anywhere in the output, the chat preview, or the temp file.
Build the message in two forms:
/tmp/devops-daily-update-<YYYY-MM-DD>.txt.Each item from steps 3–6 must be normalized to a TICKET: action bullet. Ticket extraction rules:
QVAC-\d+ (or [A-Z]+-\d+) from the PR title; that's the ticket.feat/QVAC-12345-thing).#<pr-number> as the leading label.prefix[tags]:), past tense for Done today, action-verb-leading for Planned for tomorrow. Drop the prefix[tags]: from the rendered action.🔨 *Done today*
- <TICKET-or-#num>: <past-tense action>
- ...
- <optional sub-bullet>
📅 *Planned for tomorrow*
- <TICKET-or-#num>: <forward-looking action>
- ...
🚧 *Blockers / risks*
- N/AEmpty section → single bullet - N/A (literal). Three sections always rendered, in this order, separated by a single blank line. Bare ticket bullets (- QVAC-13860 with no : and no action) are allowed when the work is self-evident from the ticket title.
**🔨 Done today**
- <TICKET-or-#num>: <past-tense action>
- ...
**📅 Planned for tomorrow**
- <TICKET-or-#num>: <forward-looking action>
- ...
**🚧 Blockers / risks**
- N/A(Same content, GitHub-flavored Markdown rendering for the chat preview only.)
If the user requested --format markdown, save the Markdown form to the temp file too. Conversion rules between the two forms:
| Markdown | Slack | |---|---| | **X** | *X* | | *X* (italic) | _X_ | | [text](URL) | <URL\|text> | | # H1 / ## H2 | not used (use Slack-bold instead) | | Plain QVAC-\d+ | Plain QVAC-\d+ (the workspace's Slack/Asana integration auto-links) | | 4-space-indented - sub | 4-space-indented - sub (Slack respects 4-space indent for sub-bullets) |
Do NOT pre-link ticket numbers via <URL|TICKET> — the workspace's Asana app handles auto-linking. Pre-linking conflicts with that and renders awkwardly.
bash pbcopy < /tmp/devops-daily-update-<YYYY-MM-DD>.txt # macOS xclip -selection clipboard < /tmp/devops-daily-update-<YYYY-MM-DD>.txt # Linux
Before printing the output, verify:
- N/A bullet (never _(none)_, never empty, never removed)TICKET: (or #<pr-num>: only when no ticket could be extracted)[needs-review], [ready], etc.) — that meta is folded into prose actionsDone today item is genuinely activity since $SINCE (merged PR, pushed commits, etc. — not stale)Planned for tomorrow → review item is open and the user is in requestedReviewersBlockers / risks → CI failing item is on a PR the user authored or a branch they own**bold** (uses *bold*), no GitHub-style links| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 4,284 | 10,100 | +136% | 1 | 1 | 0% | 491 | 4,350 | +786% | 0 | 0 | — |
case-16 | fail→fail | 9,677 | 8,630 | -11% | 1 | 1 | 0% | 1,544 | 4,039 | +162% | 0 | 0 | — |
case-02 | fail→fail | 7,446 | 10,297 | +38% | 1 | 1 | 0% | 1,233 | 4,300 | +249% | 0 | 0 | — |
case-03 | pass→fail | 4,954 | 9,962 | +101% | 1 | 1 | 0% | 725 | 4,295 | +492% | 0 | 0 | — |
case-04 | fail→fail | 5,459 | 28,182 | +416% | 1 | 1 | 0% | 806 | 4,276 | +431% | 0 | 0 | — |
case-05 | fail→fail | 7,500 | 10,856 | +45% | 1 | 1 | 0% | 1,320 | 4,349 | +229% | 0 | 0 | — |
case-06 | pass→pass | 6,054 | 2,748 | -55% | 1 | 1 | 0% | 923 | 3,954 | +328% | 0 | 0 | — |
case-07 | fail→pass | 7,787 | 3,070 | -61% | 1 | 1 | 0% | 1,306 | 3,980 | +205% | 0 | 0 | — |
case-08 | fail→pass | 7,863 | 3,448 | -56% | 1 | 1 | 0% | 1,174 | 4,101 | +249% | 0 | 0 | — |
case-09 | fail→fail | 7,747 | 9,930 | +28% | 1 | 1 | 0% | 1,074 | 4,220 | +293% | 0 | 0 | — |
case-10 | fail→pass | 7,401 | 5,916 | -20% | 1 | 1 | 0% | 1,203 | 4,465 | +271% | 0 | 0 | — |
case-11 | pass→pass | 6,284 | 2,755 | -56% | 1 | 1 | 0% | 1,119 | 4,052 | +262% | 0 | 0 | — |
case-12 | fail→fail | 9,733 | 9,448 | -3% | 1 | 1 | 0% | 1,494 | 4,160 | +178% | 0 | 0 | — |
case-13 | fail→fail | 4,266 | 9,244 | +117% | 1 | 1 | 0% | 642 | 4,036 | +529% | 0 | 0 | — |
case-14 | pass→pass | 8,254 | 3,623 | -56% | 1 | 1 | 0% | 1,385 | 4,138 | +199% | 0 | 0 | — |
case-15 | fail→fail | 4,801 | 7,114 | +48% | 1 | 1 | 0% | 755 | 3,837 | +408% | 0 | 0 | — |
case-17 | pass→pass | 7,183 | 1,944 | -73% | 1 | 1 | 0% | 1,094 | 3,772 | +245% | 0 | 0 | — |
case-18 | fail→pass | 10,719 | 3,046 | -72% | 1 | 1 | 0% | 1,613 | 3,971 | +146% | 0 | 0 | — |
case-19 | pass→pass | 10,345 | 3,062 | -70% | 1 | 1 | 0% | 1,701 | 4,014 | +136% | 0 | 0 | — |
case-20 | fail→pass | 5,287 | 6,482 | +23% | 1 | 1 | 0% | 897 | 4,509 | +403% | 0 | 0 | — |
case-21 | fail→pass | 5,728 | 2,947 | -49% | 1 | 1 | 0% | 1,037 | 3,981 | +284% | 0 | 0 | — |
case-22 | fail→fail | 3,371 | 10,279 | +205% | 1 | 1 | 0% | 550 | 4,194 | +663% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 11 counted toward the lift figure. The other 11 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +23 percentage points is the difference between those two pass rates over the 11 comparable cases. 6 cases got worse with the skill loaded, and they are included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.