agentsclimarketplace

Daily standup prep

Skill risadams/skills/daily-standup-prep

An opinionated library of reusable agent skills. Contains practical skills for writing, planning, triage, architecture, and workspace workflows

Install
npx -y skills add risadams/skills --skill daily-standup-prep

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Generate a per-team standup markdown report by gathering activity over the last N days from Jira, GitLab, Confluence, and a local Git repo. Maps activity to team members from a roster CSV, renders a Mermaid kanban + randomized talking order, captures a `daily`-tagged sprint snapshot, and runs a clarity-council (infographics-expert burndown chart + statistics-expert forecast + scrum-master suggestions) for sprint pulse. Writes one file per team into the Obsidian vault. Use when the user says "daily standup prep", "standup report", "generate standup", "scrum prep", or invokes /daily-standup-prep.

SKILL.md

30.6 KB, as published. Nobody here has run it

Daily Standup Prep

Per-team standup report. Read-only across Jira, GitLab, Confluence, and Git. Writes one markdown file per team to the Obsidian vault.

This skill is a Claude Code port of D:\powershell-scripting\src\bin\Get-Standup-Report.ps1 — same inputs, same template placeholders, same output path layout, same identity-matching rules. See REFERENCE.md for the algorithm and per-section formatter contracts. See EXAMPLES.md for invocation parity with the PS script.

Quick start

/daily-standup-prep                                 → Pyrite, last 2 days, INC 25 / Sprint 1
/daily-standup-prep Onyx                            → single team
/daily-standup-prep Pyrite,Onyx --days 3 --inc 26   → multi-team, custom window
/daily-standup-prep --no-gitlab --no-confluence     → toggle sections off

Parameters

ParamDefaultMaps to PS
Teams["Pyrite"]-Teams (string[])
DaysToLookBack2-DaysToLookBack
JQLauto-built-JQL
GitRepoPathD:\paas\-GitRepoPath
Inc25-Inc
Sprint1-Sprint
IncludeJiraIssues / IncludeGitCommits / IncludeGitLabActivity / IncludeConfluenceActivity / IncludeKanbanDiagram / IncludeStandupOrderall truesame
IncludeSprintPulsetruenew — runs Phase 4.5 (daily snapshot + council burndown/forecast/suggestions). Toggle off with --no-sprint-pulse

JIRA base, Confluence base, GitLab base + group, vault root, and template path are all resolved from memory — never accept them as args. See Config resolution below.

Config resolution (run once at the start of every invocation)

PlaceholderMemory fileDefault content / how to populate
{{vault_root}}reference_obsidian_vault.md (**Vault root:** line)C:\Users\chris.adams\dev\gd-pkms\ — already populated
{{jira_project}}reference_jira_default_project.md (**Default Jira project key:** line)SC2 — already populated
{{confluence_space}}reference_confluence_default_space.mdPP — already populated
{{gitlab_base_url}}reference_gitlab_config.md (**GitLab base URL:** line)If <unset>, prompt and persist https://gdgitlab01.gd-ms.us (the PS-script default)
{{gitlab.bessemer}}same memory, Common project paths tableIf absent, prompt and add a row: bessemerbessemer (group path)
{{template_path}}derived{{vault_root}}\🗃Templates\Standup.md (no separate memory)
{{rosters_dir}}derived{{vault_root}}\Scrum Teams\_rosters\
{{output_root}}derived{{vault_root}}\Scrum Teams\ (per-team subfolder appended later)

If a memory file is missing or its value is <unset>, prompt once via AskUserQuestion with the PS-script default as the recommended option, then write the answer back so the next run skips the prompt. Same pattern as daily-briefing.

Roster bootstrap (first-run only)

The PS script reads D:\powershell-scripting\src\bin\Teams\<Team>.csv. We move ownership of those CSVs into the vault so the user maintains them in one place going forward.

For each team in the run:

  1. Look for {{rosters_dir}}\<Team>.csv (case-insensitive). If present, use it.
  2. If missing and D:\powershell-scripting\src\bin\Teams\<Team>.csv exists, prompt via AskUserQuestion: "No roster found at {{rosters_dir}}\<Team>.csv. Copy from the powershell-scripting repo?" — options: Copy (recommended), Use repo path this run only, Skip team.
  3. On Copy: mkdir -p "{{rosters_dir}}", then copy the file. Tell the user the new path is the canonical location going forward.
  4. If neither path exists, skip the team and warn — do not invent a roster.

CSV format is the same headerless layout the PS Team-Helpers module uses: FullName,Email,Alias,Role,Flags. Lines starting with // and blanks are ignored. Alias and Flags accept ;-separated values. See REFERENCE.md.

Workflow (per team)

Loop the steps below for each team in Teams. Each iteration is independent — one file per team, matching the PS script's $teamsToProcess | ForEach-Object block.

Per-team progress:
- [ ] Phase 1: Resolve config + load roster
- [ ] Phase 2: Compute window + auto-build JQL
- [ ] Phase 3: Gather data (Jira, Git, GitLab, Confluence) — parallel
- [ ] Phase 4: Match activity to team members + flag HasActivity
- [ ] Phase 4.5: Sprint pulse — daily snapshot + council (burndown / forecast / suggestions)
- [ ] Phase 5: Render section markdown + Mermaid kanban + talking order
- [ ] Phase 6: Substitute template placeholders + write to vault
- [ ] Phase 7: Console summary

Phase 1 — Config + roster

Resolve every {{placeholder}} per the table above. Load the roster CSV into a list of {FullName, FirstName, LastName, JiraName, Email, Alias[], DisplayFirstName, Role, Flags[]} records — derive JiraName = "{Last}, {First}" and DisplayFirstName = Alias[0] ?? FirstName. Tag each member with HasActivity = false and empty Issues / Commits / GitLabActivities / ConfluenceActivities lists.

Phase 2 — Window + JQL

  • activity_since = midnight (Pittsburgh local) DaysToLookBack days ago.
  • since_iso = YYYY-MM-DDTHH:mm:ssZ for GitLab/Confluence cutoffs.
  • since_date = YYYY-MM-DD for git log --since.
  • If JQL arg is empty: build project = {{jira_project}} AND updated >= startOfDay(-{N}d) where N = DaysToLookBack.

State the chosen window in one short sentence: "Gathering Pyrite standup for window 2026-05-11 → 2026-05-13 (2-day lookback)."

Phase 3 — Gather data (parallel)

Issue these MCP/Bash calls in a single response when section toggles allow:

  • Jira issues (IncludeJiraIssues or IncludeKanbanDiagram): jira_search(jql=<jql>, fields="summary,status,assignee,issuetype,updated") with pagination to a sane cap. For each result, follow up with jira_get_changelog and jira_get_comments only when the issue's updated is within the window — skip the fetch otherwise to save tokens.
  • Jira kanban (IncludeKanbanDiagram only): second jira_search with project = {{jira_project}} AND sprint in openSprints() AND labels in ({lowercase team names}). Capture key, summary, status, assignee.displayName, issuetype.name.
  • GitLab MRs + discussions (IncludeGitLabActivity):
    1. list_group_projects(group_id="{{gitlab.bessemer}}") to get all project IDs in the group (subgroups included).
    2. For each project: list_merge_requests(project_id, updated_after=<since_iso>, per_page=100).
    3. For each MR: mr_discussions(project_id, merge_request_iid) capped at 100 notes.
  • GitLab pipelines (IncludeGitLabActivity): for each project, list_pipelines(project_id, updated_after=<since_iso>, per_page=100). For each, get_pipeline(project_id, pipeline_id) to read the triggering user.
  • Confluence pages (IncludeConfluenceActivity): confluence_search(cql="lastModified >= '{since_date}' AND space = {{confluence_space}}"). For each, confluence_get_page(page_id, expand="history.lastUpdated,version,space,body.view").
  • Git commits (IncludeGitCommits): Bash sequence — confirm {{git_repo}}\.git exists; git -C "{{git_repo}}" fetch --all; git -C "{{git_repo}}" log --all --since="{since_date}" --pretty=format:"%H|%an|%ae|%aI|%s". Parse pipe-delimited lines.

If any external system fails to respond, log a warning and continue with empty results for that section — never fabricate. If IncludeKanbanDiagram is on but Jira fails, render _No kanban data — Jira unavailable._ rather than skipping the placeholder.

Phase 4 — Match activity to team members

Use the cascading 8-strategy matcher described in REFERENCE.md. For every activity record, attempt to match by (email, displayName, username) — Jira gives email + displayName; GitLab gives email + name + username; Confluence gives email + displayName; Git gives email + author name only.

Filter rules:

  • Jira issue inclusion — keep an issue iff its assignee matches a team member OR any comment/changelog entry within the window was authored by a team member. (Direct port of the PS $isAssignedToTeamMember -or $hasRecentActivity filter.)
  • Git/GitLab/Confluence inclusion — keep an activity iff its author matches a team member.
  • Set member.HasActivity = true for any matched member, and append the activity to the member's Issues / Commits / GitLabActivities / ConfluenceActivities lists for the talking-order/per-member sections.

Phase 4.5 — Sprint pulse (daily snapshot + council)

Skip entirely if IncludeSprintPulse is off — substitute empty strings for the three pulse placeholders in Phase 6.

Step 1 — Daily sprint snapshot. Invoke the sprint-snapshot skill via Skill for the current team with --phase "daily". This writes daily.canvas + daily.md to the team's current sprint folder (overwriting yesterday's daily.* is fine — the trend record lives in _snapshots.jsonl) and appends a row to that JSONL trend log. The JSONL is the burndown's data source. If sprint-snapshot fails (Jira down, sprint config missing, etc.), surface the failure in the console summary, render _Sprint pulse unavailable — daily snapshot failed._ for {{burndown_chart}}, leave the other two pulse placeholders empty, and continue. Never fabricate trend data.

Step 2 — Read trend data. Read the team's _snapshots.jsonl from {{output_root}}\<TeamTitleCase>\Scrum 📅\INC {Inc}\Sprint {Sprint}\_snapshots.jsonl. Parse the rows for the current sprint only (filter by inc + sprint). Extract (snapshot_at, remaining, totals.points, by_status.done.points) per row. Also pull capacity, velocity.last, and velocity.avg3 from the most recent row. If the JSONL has fewer than 2 rows for this sprint, the burndown will be a single point — note this in the rendered output, do not fake additional data points.

Step 3 — Run clarity-council. Invoke the clarity-council skill via Skill with three personas: infographics-expert, statistics-expert, scrum-master. Pass the parsed JSONL trend rows, sprint config (StartDate, EndDate, Capacity, LastSprintVelocity, AvgVelocityLast3), the day count (day X of 21), and the current matched-activity summary from Phase 4 as the council's shared context. Ask each persona for a tightly scoped artifact:

  • infographics-expert → render an Obsidian Charts plugin burn-up chart following the exact shape below. The chart uses a chart code fence (Chart.js backend via the obsidian-charts community plugin, which must be installed in the vault). Burn-up (not burn-down) is the canonical shape because it visualizes scope changes explicitly — your sprints regularly take +20–40 pts of scope creep, which burn-down folds into a misleading "remaining" line.

    Burn-up chart contract (must be followed verbatim; no creative reinterpretation):

    1. Determine actual data points. From the JSONL trend rows, build a list samples = [(day_n, scope_points, done_points), …] where day_n is integer days since StartDate (Pittsburgh local, day_0 = StartDate), scope_points = totals.points, done_points = by_status.done.points. Sort by day_n. De-duplicate by day_n keeping the latest snapshot_at per row.
    2. Build the x-axis. Full sprint range — x_axis = list(range(0, sprint_length_days + 1)) where sprint_length_days = (EndDate - StartDate).days. The x-axis always spans day 0 → day sprint_length_days, regardless of how far into the sprint we are.
    3. Build the actual scope series. For each day_n in x_axis:
      • If day_n ≤ today_n AND a sample exists for day_n: use the sample's scope_points.
      • If day_n ≤ today_n AND no sample exists (weekend/holiday/gap): carry forward the previous day's scope_points value (last-known wins).
      • If day_n > today_n (future): emit null.
    4. Build the actual done series. Same logic as scope, but using done_points. Day 0 defaults to 0 if no sample exists.
    5. Build the pinned scope series (visually distinct future segment). For each day_n in x_axis:
      • If day_n < today_n: emit null.
      • If day_n ≥ today_n: emit today's actual scope_points. (The series starts at today's point so the line connects visually from the actual series.)
    6. Build the pinned done series. Same logic as pinned scope, but using done_points.
    7. Build the capacity reference series. Constant Capacity across all len(x_axis) days.
    8. Y-axis bounds. y_min = 0, y_max = ceil(max(all actual scope values + [Capacity]) * 1.1) so the highest point isn't flush with the top edge.
    9. Title. None at the chart level (the markdown heading carries it). Set the surrounding section heading to ### Burn-up.
    10. Validate before emitting. Confirm all five series have length len(x_axis); confirm null is used (not None / NaN / empty string) for future-day gaps in the "actual" series and past-day gaps in the "pinned" series; confirm every non-null value is finite and inside [y_min, y_max]. If any check fails, do not emit the chart — emit a one-line markdown note explaining what failed, and surface it so the run can be debugged.

    Reference template (substitute the computed values; this is the only acceptable shape):

    ### Burn-up
    
    ```chart
    type: line
    labels: ["0","1","2",...,"<sprint_length_days>"]
    series:
      - title: "Scope (actual)"
        data: [<scope values for days 0..today_n; null for days today_n+1..end>]
      - title: "Done (actual)"
        data: [<done values for days 0..today_n; null for days today_n+1..end>]
      - title: "Scope (pinned — no future data)"
        data: [<null for days 0..today_n-1; today's scope repeated for days today_n..end>]
      - title: "Done (pinned — no future data)"
        data: [<null for days 0..today_n-1; today's done repeated for days today_n..end>]
      - title: "Capacity (<Capacity> pts)"
        data: [<Capacity repeated len(x_axis) times>]
    tension: 0.2
    width: 100%
    labelColors: false
    fill: false
    beginAtZero: true
    bestFit: false
    yTitle: "Points"
    xTitle: "Sprint day (0 = <StartDate>, <sprint_length_days> = <EndDate> close)"
    yMin: 0
    yMax: <y_max>
    ```
    
    **Reading the chart**:
    
    - **Solid lines (days 0–<today_n>)** = actual snapshot data. <One-sentence summary of scope trajectory: trim, creep, what drove changes>. Done climbs ~<observed pts/day> pts/day average.
    - **Past gaps** (if any: weekend/holiday days with no snapshot) are carry-forward — value held from the previous day.
    - **Pinned lines (days <today_n>–<sprint_length_days>)** = today's values held flat, NOT a forecast. The visible gap between Scope (<today_scope>) and Done (<today_done>) at day <sprint_length_days> = ~<gap> pts that would land in next sprint at observed cadence.
    - **Capacity (<Capacity> pts)** = horizontal reference; scope is currently <+/-N> vs capacity.
    - **What it would take to close the sprint**: done line would need to climb +<gap> pts in <days_remaining> days (~<required pts/day> pts/day) — <compare to historical velocity>. <Sprint N+1 carry-over recommendation if gap > observed-cadence × days-remaining>.
    

    Chart.js (via the obsidian-charts plugin) renders each series in a distinct color, so the "actual" and "pinned" segments are visually different even though they share the chart. The null values create true gaps in the line, so past/future are visually separate. Do not add chartjs: style overrides unless the user explicitly asks — the default rendering is the canonical shape.

    Plugin dependency. The chart code fence requires the obsidian-charts community plugin enabled in the vault (folder: {{vault_root}}/.obsidian/plugins/obsidian-charts/). On first run, verify via Glob that the plugin folder exists. If missing, surface a one-line warning in the console summary and emit the chart anyway — Obsidian will render the raw YAML as a code block until the plugin is installed, which is recoverable. Do not fall back to Mermaid xychart-beta — the historical shape is inferior and the user has explicitly chosen Charts plugin going forward.

    Single-sample case. If only one trend row exists, day 0 acts as the implicit second point: Scope (actual) = [<sample.scope>, ..., null after sample.day_n], Done (actual) = [0, ..., <sample.done>, ..., null after sample.day_n]. The pinned series start at sample.day_n. Caption appends: _First snapshot at day <N> — trend will fill in over coming days._

  • statistics-expert → produce a single-paragraph forecast: project end-of-sprint completed points using simple linear extrapolation from the trend, compare against Capacity and velocity.avg3, and state a confidence band (e.g. "tracking 5pts under commit, ±3pts based on 3-sprint variance"). Hard cap: ≤4 sentences. No charts — words only. Must explicitly call out if the trend data is too sparse to forecast (≤2 rows).

  • scrum-master → 1–3 actionable suggestions for the team based on the day's matched activity (Phase 4) + the snapshot bucket counts. Examples: "two tickets in In Review for >3 days — chase reviewers", "Ada has no activity tracked in 2 days — confirm not blocked", "WIP at 8 vs limit 5 — pull from Ready before starting new". Bullet list. No vague platitudes — each suggestion names a ticket, person, or measurable signal.

Step 4 — Capture artifacts. Store the three council outputs as the strings {{burndown_chart}} (the Obsidian Charts chart code fence including its ```chart opening and closing ``` fences, followed by the "Reading the chart" markdown block — see infographics-expert contract above), {{forecast_note}} (the statistics-expert paragraph, plain markdown), and {{scrum_suggestions}} (the bullet list, plain markdown). These feed Phase 6. The placeholder name {{burndown_chart}} is retained for template-backward-compatibility — its content is a burn-up chart per the v2 contract. The vault-side Standup template at {{vault_root}}/🗃Templates/Standup.md does not need to change; the substitution drops the new chart shape into the existing slot.

Phase 5 — Render sections

Each placeholder in the template gets a string built from the matched data. Formatter contracts (exact markdown shape) live in REFERENCE.md:

  • {{talking_order}} — randomized active members () first, inactive (🧽) last. Each line - [ ] [[@First Last]] - ✅ (or 🧽). Multi-team runs append (TeamName) after the wikilink. If IncludeStandupOrder is off, leave the placeholder empty.
  • {{jira_state}} — Mermaid flowchart with five status columns (Blocked / Ready / In Progress / In Review / Done). Spec in REFERENCE.md. If IncludeKanbanDiagram is off, empty.
  • {{jira_issues}} — per-issue blocks with ### KEY - Summary, type/status/assignee line, then a bulleted activity log of (date) WHO / WHAT / WHY plus text code fences for details.
  • {{git_updates}} — per-member blocks ### [[@First Last]] then - (date) hash7 - message lines, sorted desc by date.
  • {{gitlab_updates}} — three subsections (## Merge Request Activity, ## Comment Activity, ## Pipeline Activity) only if non-empty; otherwise the placeholder line _No GitLab activity found in the specified time period._.
  • {{confluence_updates}} — per-page blocks with title + space tag, type/last-modified/author line, link, and a content snippet (first 200 chars of stripped HTML in a text code fence).

Phase 6 — Substitute and write

  1. Read {{template_path}}. The template is the user's master Standup template — never modify it.
  2. Replace placeholders in this exact set (matches the PS ConvertTo-TemplateMarkdown function plus the three Phase 4.5 additions): {{date}}, {{team}}, {{sprint}}, {{increment}}, {{talking_order}}, {{jira_state}}, {{jira_issues}}, {{git_updates}}, {{confluence_updates}}, {{gitlab_updates}}, {{burndown_chart}}, {{forecast_note}}, {{scrum_suggestions}}. Date format YYYY-MM-DD (Pittsburgh local). Team name written TitleCase (first char upper, rest lower) to match the PS $formattedTeam line. The three pulse placeholders are no-ops if the user's template doesn't reference them — the substitution still runs cleanly. Note this once when a template lacks them so the user knows to add them if they want the pulse rendered (e.g. under a ## Sprint Pulse heading containing {{burndown_chart}}, then ### Forecast {{forecast_note}}, then ### Suggestions {{scrum_suggestions}}).
  3. Compute output path: {{vault_root}}\Scrum Teams\<TeamTitleCase>\Scrum 📅\INC {Inc}\Sprint {Sprint}\YYYY-MM-DD.md — note the 📅 emoji is preserved literally; forward slashes work fine in bash on Windows.
  4. mkdir -p the parent directory.
  5. Never overwrite silently. If the file exists, Read it, then AskUserQuestion: Overwrite / Append as ## Re-run HH:MM section / Skip save.
  6. Write the file. Print the saved path back as a clickable markdown link.

Sibling-skill delegation in Phase 4.5 / Phase 6:

  • The daily snapshot is always delegated to sprint-snapshot via Skill with --phase "daily". Never reimplement Jira sprint fetching inline — sprint-snapshot owns the JQL, identity matching, capacity math, and the JSONL trend schema. If its phase derivation logic doesn't recognize daily, pass it through as an explicit --phase override (the skill already supports arbitrary phase strings via that flag).

  • The pulse council is always delegated to clarity-council via Skill with personas pinned to infographics-expert + statistics-expert + scrum-master. Do not author burndown SVG/Mermaid, forecast paragraphs, or suggestions inline — let each persona produce its own artifact under its own constraints.

  • If extending the template with new Obsidian Flavored Markdown constructs (callouts, embeds, dataview, block IDs, frontmatter properties beyond Increment/Sprint/Date), invoke obsidian-markdown via Skill rather than authoring the syntax inline — it's the canonical reference and stays in sync with vault conventions.

  • For wikilink target verification (the [[@First Last]] rule in talking_order / git_updates), prefer delegating the lookup to obsidian-vault if the run will need to verify many person notes — its search is more efficient than repeated Glob calls. For a single team run (≤15 lookups) the inline Glob is fine.

  • If the user later wants a dashboard .base file that aggregates team standups (e.g. "all standups for Pyrite this sprint"), invoke obsidian-bases rather than hand-authoring the YAML.

  • For CLI-driven vault inspection (e.g. checking note frontmatter, running a vault-wide property query before deciding whether to overwrite), invoke obsidian-cli — it has direct property/task access that Read+Glob cannot replicate cheaply.

Phase 7 — Console summary

Print a brief block per team (matches the PS === REPORT GENERATION SUMMARY === block):

=== <Team> standup report ===
Team members loaded: N
Jira issues included: N (of M scanned)
Git commits matched: N
GitLab activities matched: N
Confluence activities matched: N
Sprint pulse: snapshot=<ok|failed|skipped> · trend rows=N · council=<ok|failed|skipped>
Saved: <markdown link>

Rules

  • Read-only across Jira, GitLab, Confluence. Never transition issues, post comments, approve MRs, edit pages, or modify any external state.
  • Read-only on the Git repo. fetch and log only — never checkout, pull, or merge.
  • No vault writes outside Scrum Teams/. The template at 🗃Templates/Standup.md is read-only too.
  • Never overwrite an existing standup file silently. Always confirm via AskUserQuestion.
  • Confirm before persisting to memory. When populating an <unset> value (GitLab base URL, etc.), use the PS-script default as the recommended option but let the user override before writing.
  • Wikilinks for team members only when the vault person note exists. Use Glob("{{vault_root}}/🤼 Team/**/@*.md") to verify before writing [[@First Last]]. If the vault has no canonical note for a roster member, render plain text — don't pollute the graph with broken links.
  • TitleCase team names in output. pyritePyrite (first char upper, rest lower) — matches the PS $formattedTeam line so vault paths and frontmatter stay consistent.
  • Pittsburgh local time. All Date columns and the filename use America/New_York. The git log %aI and ISO timestamps from Jira/GitLab/Confluence are converted before display.
  • Section toggle semantics match the PS script. Skipping a section (e.g., --no-gitlab) means: don't gather, don't fetch, and substitute an empty string for the placeholder — the template still resolves cleanly.
  • No fabricated data. If an MCP fails, surface the failure in the console summary and put a _<system> unavailable_ note in the corresponding section. Do not invent.
  • Sprint pulse is delegated, never inlined. The daily snapshot must come from sprint-snapshot and the burndown/forecast/suggestions must come from clarity-council's three pinned personas. Do not author burndown charts, forecasts, or scrum-master suggestions inline — that bypasses the persona constraints (infographics-expert's chartjunk rules, statistics-expert's confidence-band requirement, etc.) that make these artifacts trustworthy.
  • Burndown trend data is read-only and append-only. Phase 4.5 reads _snapshots.jsonl to feed the chart but never edits past rows. Past daily.canvas / daily.md are allowed to be overwritten — the trend record lives in the JSONL.

Edge cases

  • No team members loaded — warn and skip the team. Don't render an empty report (matches PS if ($teamMembers.Count -eq 0) guard).
  • Roster CSV missing for one of N teams — process the others; warn for the missing one.
  • Vault 🤼 Team folder doesn't have a @First Last.md note for a roster member — render plain First Last instead of a wikilink in {{talking_order}} and {{git_updates}}.
  • Git repo not present at {{git_repo}} — skip git commit collection silently; render an empty {{git_updates}} section.
  • Jira sprint label missing for the team (kanban query returns 0) — render _No <Team> items found in current sprint._ for {{jira_state}}.
  • GitLab bessemer group returns 0 projects — surface a warning; the user may have lost group membership. Render _No GitLab activity found in the specified time period._.
  • Re-run on the same day — same overwrite/append/skip prompt as daily-briefing.
  • Multi-team run, partial failure — generate reports for the teams that succeeded; surface per-team status in the final summary block.
  • Sprint pulse with no prior snapshots — first daily run of a sprint will only have one trend row after Step 1 writes it. Render the burndown as a single point with a one-line caption (e.g. _First daily snapshot of Sprint N — trend will fill in over coming days._) and let the statistics-expert flag the data as too sparse to forecast.
  • Sprint config note missingsprint-snapshot will prompt to create one. If the user declines, skip the entire pulse phase rather than half-rendering it.

Related skills

This skill writes into and reads from the user's Obsidian vault. When any vault-related extension or refinement is needed, delegate to the relevant obsidian-* skill via Skill rather than reimplementing — they are the canonical references for vault conventions and stay in sync with Obsidian feature changes.

SkillUse it for
daily-briefingPersonal (Outlook-driven) morning prep. Sibling skill — both can run on the same morning. Same {{vault_root}} resolution pattern.
sprint-snapshotOwns the daily snapshot in Phase 4.5. Always invoke via Skill with --phase "daily"; never reimplement Jira sprint fetching, identity matching, or the JSONL trend schema inline. The _snapshots.jsonl it writes is the burndown's data source.
clarity-councilOwns the pulse council in Phase 4.5. Always invoke with the three pinned personas (infographics-expert, statistics-expert, scrum-master). Lets each persona enforce its own constraints on the burndown chart, forecast, and suggestions.
issue-suggest-componentPattern reference for memory-driven default Jira project + bulk AskUserQuestion pacing if the multi-team loop ever grows beyond a handful of teams.
issue-feature-breakdownPattern reference for Jira+Confluence context-gathering depth.
obsidian-markdownCanonical reference for Obsidian Flavored Markdown. Consult before extending the standup template with new constructs (callouts, embeds, dataview, block IDs, frontmatter properties).
obsidian-vaultUse for batch wikilink target verification, vault-wide note discovery, and managing the standup index notes. Prefer over repeated Glob calls when the run needs >15 lookups.
obsidian-cliUse for property/task queries, frontmatter inspection, and any CLI-driven vault operation that Read + Glob cannot do cheaply.
obsidian-basesUse when the user wants a dashboard .base file (e.g. "show me all standups for Pyrite this sprint", "which team members had no activity in the last 5 standups"). Don't hand-author .base YAML.
obsidian-canvasUse if the user wants a visual board summarizing the standup (e.g. a sprint-overview canvas with linked standup notes as nodes).

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.