vt-c-domain-dashboard¶
Aggregate spec status across all projects in a PM domain (e.g. VisiMatch, VisiFair) and render a meeting-ready Markdown dashboard. Reads each registered project's .design-state.yaml + per-spec state.yaml, applies an owner resolution chain (assignee → git author → "—"), and writes
- .md to Obsidian or docs/pm-dashboards/. Use before daily/weekly PM standups when you need a single view across multiple repos in your domain.
Plugin: core-standards
Category: Other
Command: /vt-c-domain-dashboard
/vt-c-domain-dashboard — PM Domain Dashboard¶
A PM manages a domain (e.g. VisiMatch) that spans multiple projects/repos. This skill aggregates spec status across all those repos into one Markdown view suitable for team standups.
When to Use¶
- Before a daily/weekly PM round with a team that owns multiple repos in one product domain.
- When you need a snapshot of "what is in flight, what is ready, what shipped this month" without flipping between project folders.
- As the first beat in
/vt-c-project-status-syncwhen domain-level grouping matters (this skill is the reader; that skill aggregates further upstream).
Not for: single-project reporting (use /vt-c-activate --status instead), proposal aggregation (use /vt-c-project-sync), or weekly planning (use /vt-c-weekly-planning).
Prerequisites¶
intake/projects.yamlexists in the toolkit and lists at least one project with either an explicitdomain:field or a recognised path prefix (04-VisiMatch*,04-VisiFair*,04-VisiArea*,03-VisiTrans*).- Each listed project has a checked-out working copy reachable via its
path:entry. - Optional:
OBSIDIAN_VAULT_PATHenvironment variable points at an Obsidian vault — the dashboard lands in<vault>/PM-Dashboards/. Falls back toTOOLKIT_ROOT/docs/pm-dashboards/.
Execution¶
The skill delegates the deterministic aggregation work (filter → walk → render) to a helper script. The skill's job is to interpret the user's request, invoke the script with the right arguments, and present the result.
Step 1: Resolve the domain argument¶
Read the argument passed to the skill (e.g. VisiMatch). If empty, ask the user which domain (offer the set of distinct domain: values from intake/projects.yaml).
Step 2: Invoke the aggregation script¶
Run the helper script scripts/aggregate.sh (sibling of this SKILL.md) with the required flags:
bash plugins/core-standards/skills/domain-dashboard/scripts/aggregate.sh \
--projects-yaml "$TOOLKIT_ROOT/intake/projects.yaml" \
--domain "$DomainName"
The script prints the path of the written dashboard to stdout. The output filename is always <DomainName>-<YYYY-MM-DD>.md — passing --date YYYY-MM-DD overrides the date (used for deterministic regeneration; tests rely on this).
Verbose mode (inline bug bodies)¶
When a PM is running the dashboard mid-meeting and wants the full bug body (repro steps, expected/actual behaviour) directly inline rather than opening each bugs/NNN-slug/report.md, pass --with-bug-bodies:
bash plugins/core-standards/skills/domain-dashboard/scripts/aggregate.sh \
--projects-yaml "$TOOLKIT_ROOT/intake/projects.yaml" \
--domain "$DomainName" \
--with-bug-bodies
Each row in the Open Bugs section is followed by a collapsible <details> block with the bug's body (frontmatter stripped, H1 demoted). Cross-cutting bugs are flagged with [cross-cutting] in the summary line. Flag-off output is byte-identical to the Wave 1 baseline — opt-in only.
Step 3: Output location¶
By default the script writes to:
$OBSIDIAN_VAULT_PATH/PM-Dashboards/<Domain>-<date>.mdifOBSIDIAN_VAULT_PATHis set and the dir exists, else$TOOLKIT_ROOT/docs/pm-dashboards/<Domain>-<date>.md
Override with --output-dir <path> when the PM wants the file elsewhere (e.g. attached to a Granola meeting note).
Step 4: Report the result¶
Echo the output path to the user, summarise the section counts ("In Progress: 4, Specified: 6, Completed this month: 2"), and offer next actions (open in Obsidian, paste into PM-Weekly transcript template).
Interactive Mode¶
SPEC-122 / W1.9. Lets a PM walk through every unconfirmed spec in a domain during a meeting and lock in priorities. Skill writes ONLY to
pm-priority-overrides/<Domain>.yaml—spec.mdand.design-state.yamlare never modified by this walk.
Invoke when the user asks to "confirm priorities" or "re-prioritize the {Domain} backlog". The walk is Claude-driven (orchestrates one AskUserQuestion per spec) and uses the --print-unconfirmed-specs script flag to enumerate the input list.
Step I-1: List unconfirmed specs¶
bash plugins/core-standards/skills/domain-dashboard/scripts/aggregate.sh \
--print-unconfirmed-specs \
--projects-yaml "$TOOLKIT_ROOT/intake/projects.yaml" \
--domain "$DomainName"
Each emitted line is IPC-delimited (\037) with three fields: SPEC-NNN<US>title<US>current_priority. The flag exits 0 with no rows when there's nothing to confirm.
Step I-2: Empty-domain branch¶
If stdout is empty (zero non-completed specs in the domain), tell the user:
Keine zu priorisierenden Specs in {Domain}.
Then stop — no walk, no override file changes, no dashboard render.
Step I-3: Walk loop¶
For each emitted line, present the spec with AskUserQuestion and a fixed option set: P0/P1/P2/P3/skip.
AskUserQuestion:
question: "{SPEC-NNN}: {title} — currently {priority}. Confirm or change?"
options: [P0, P1, P2, P3, skip]
Answer routing:
- P0 / P1 / P2 / P3 — record the answer by invoking the T10 helper:
bash plugins/core-standards/skills/domain-dashboard/scripts/write_override.sh --domain "$DomainName" --spec-id "$SID" --priority "$Answer". The helper applies Decision-4 cleanup automatically (if answer equals the spec.md priority, the entry is removed and the helper emits a visible signal). - skip — do nothing. No file is touched. This is a no-op in both states (override present AND override absent): the override file ends byte-identical to its pre-walk state. Skip is the right answer when the PM hasn't formed an opinion yet — the spec stays unconfirmed for the next walk.
Step I-4: Wrap up¶
After the walk completes, optionally render the updated dashboard:
The drift markers (P0 ↑ (date), P2 ↓ (date)) in the rendered priority column show which entries the PM just confirmed and how they differ from each spec's original priority:.
How the helper script works¶
- Parse
projects.yaml— extract(id, path, domain)per project. - Filter by domain — explicit
domain:field wins; otherwise apply path-prefix heuristic (see Prerequisites). - Walk each matching project — read
.design-state.yamlspecs_status:block, then read each spec'sstate.yamlto override status and pick upassignee+completed_at. - Resolve owner — chain: per-spec
assignee→ most recentgit logauthor onfeature/spec-N-*branches → "—". Authors starting withClaudeare filtered (co-authored commits often have Claude as first author). - Group + sort —
in_progressfirst (active work), thenspecified(ready), thencompletedfiltered to the current month (so the file stays meeting-short). Within each group: P0 → P1 → P2, then numeric SPEC ID. - Render — three Markdown tables with section headers; empty sections are omitted to avoid filler.
- Write —
<output-dir>/<Domain>-<date>.mdand echo the path.
Edge Cases¶
- Project listed in
projects.yamlbut path doesn't exist → warning to stderr, project skipped, other projects still rendered. .design-state.yamlmissing in a listed project → warning, skip.- Malformed YAML in
.design-state.yaml→ warning, skip (does not crash). - Spec listed in
.design-state.yamlbut its per-specstate.yamlis missing → use the status from.design-state.yamlas fallback. - No projects match the domain → header-only dashboard (no rows, no section headers).
OBSIDIAN_VAULT_PATHpoints at a non-existent dir → fall back todocs/pm-dashboards/silently.
Integration Points¶
intake/projects.yaml— source of truth for project paths +domain:field. Add a new project there to include it in domain dashboards./vt-c-project-sync— different concern (intake proposals back to toolkit). This skill does not call it./vt-c-project-status-sync— can consume this dashboard as one of its inputs when building Asana status updates per project.
Non-Goals (v1)¶
- Hook / cron auto-refresh — manual invocation only in v1. Deferred to a follow-up spec.
- Cross-domain dashboards — one domain per invocation.
- Web UI / interactive filtering — Markdown file only; PMs paste into Obsidian or Granola.
- Azure DevOps integration — out of scope; this skill operates on local repo state.
Examples¶
Run on demand before a Tuesday VisiMatch standup:
→ writes docs/pm-dashboards/VisiMatch-2026-05-18.md (or $OBSIDIAN_VAULT_PATH/PM-Dashboards/VisiMatch-2026-05-18.md if Obsidian is configured).
Regenerate yesterday's file for an audit trail:
bash plugins/core-standards/skills/domain-dashboard/scripts/aggregate.sh \
--projects-yaml intake/projects.yaml \
--domain VisiMatch \
--date 2026-05-17
Drop the output into a meeting note location:
bash plugins/core-standards/skills/domain-dashboard/scripts/aggregate.sh \
--projects-yaml intake/projects.yaml \
--domain VisiFair \
--output-dir ~/Documents/Granola/PM-VisiFair/
Success Criteria¶
- One Markdown file written per invocation, filename
<Domain>-<date>.md. - File contains only specs from projects whose resolved domain equals the argument.
- Empty sections are omitted (PMs see only what's actually there).
- Owner column never contains "Claude*" — the Claude-author filter is non-negotiable; commit attribution should reflect the human.