| name | daily-standup-prep |
| description | 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. |
| related-agents | ["scrum-master","project-manager"] |
| allowed-tools | ["Read","Write","Glob","Bash","AskUserQuestion","Skill","mcp__atlassian__jira_search","mcp__atlassian__jira_get_issue","mcp__atlassian__jira_get_changelog","mcp__atlassian__jira_get_comments","mcp__atlassian__confluence_search","mcp__atlassian__confluence_get_page","mcp__gitlab-mcp__list_merge_requests","mcp__gitlab-mcp__mr_discussions","mcp__gitlab-mcp__list_pipelines","mcp__gitlab-mcp__get_pipeline","mcp__gitlab-mcp__list_group_projects"] |
| related-skills | ["sprint-snapshot","clarity-council"] |
| loop-eligible | true |
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
| Param | Default | Maps to PS |
|---|
Teams | ["Pyrite"] | -Teams (string[]) |
DaysToLookBack | 2 | -DaysToLookBack |
JQL | auto-built | -JQL |
GitRepoPath | D:\paas\ | -GitRepoPath |
Inc | 25 | -Inc |
Sprint | 1 | -Sprint |
IncludeJiraIssues / IncludeGitCommits / IncludeGitLabActivity / IncludeConfluenceActivity / IncludeKanbanDiagram / IncludeStandupOrder | all true | same |
IncludeSprintPulse | true | new — 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)
| Placeholder | Memory file | Default 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.md | PP — 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 table | If absent, prompt and add a row: bessemer → bessemer (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:
- Look for
{{rosters_dir}}\<Team>.csv (case-insensitive). If present, use it.
- 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.
- On
Copy: mkdir -p "{{rosters_dir}}", then copy the file. Tell the user the new path is the canonical location going forward.
- 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):
list_group_projects(group_id="{{gitlab.bessemer}}") to get all project IDs in the group (subgroups included).
- For each project:
list_merge_requests(project_id, updated_after=<since_iso>, per_page=100).
- 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):
- 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.
- 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.
- 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.
- Build the actual done series. Same logic as scope, but using
done_points. Day 0 defaults to 0 if no sample exists.
- 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.)
- Build the pinned done series. Same logic as pinned scope, but using
done_points.
- Build the capacity reference series. Constant
Capacity across all len(x_axis) days.
- 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.
- Title. None at the chart level (the markdown heading carries it). Set the surrounding section heading to
### Burn-up.
- 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
Read {{template_path}}. The template is the user's master Standup template — never modify it.
- 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}}).
- 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.
mkdir -p the parent directory.
- Never overwrite silently. If the file exists,
Read it, then AskUserQuestion: Overwrite / Append as ## Re-run HH:MM section / Skip save.
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.
pyrite → Pyrite (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 missing —
sprint-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.
| Skill | Use it for |
|---|
daily-briefing | Personal (Outlook-driven) morning prep. Sibling skill — both can run on the same morning. Same {{vault_root}} resolution pattern. |
sprint-snapshot | Owns 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-council | Owns 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-component | Pattern reference for memory-driven default Jira project + bulk AskUserQuestion pacing if the multi-team loop ever grows beyond a handful of teams. |
issue-feature-breakdown | Pattern reference for Jira+Confluence context-gathering depth. |
obsidian-markdown | Canonical reference for Obsidian Flavored Markdown. Consult before extending the standup template with new constructs (callouts, embeds, dataview, block IDs, frontmatter properties). |
obsidian-vault | Use 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-cli | Use for property/task queries, frontmatter inspection, and any CLI-driven vault operation that Read + Glob cannot do cheaply. |
obsidian-bases | Use 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-canvas | Use if the user wants a visual board summarizing the standup (e.g. a sprint-overview canvas with linked standup notes as nodes). |