basic BMAD setup

This commit is contained in:
Ebbe Baß
2026-10-15 08:57:23 +02:00
parent 44029127dc
commit 5e747654b9
438 changed files with 41818 additions and 0 deletions
@@ -0,0 +1,52 @@
# Decide: Routing and the Acceptance Verdict
Phase 4. Turn the consolidated findings into two outputs: routed action items the human can act on, and an honest verdict on whether the epic met its acceptance criteria. This skill proposes; it does not auto-apply fixes or edit the project spec. The human decides what executes.
## Route each finding
Give every finding two independent dispositions:
- **What to do about this instance** — *fix now*, *defer*, or *accept as-is*. Fix-now findings become action items. Deferred findings carry enough context to be acted on later without re-investigation. Accepted deviations are recorded so later retros stop re-flagging them.
- **What would prevent the next one** — the upstream lesson: spec wording, story sizing, a missing convention or gate, or nothing. This is where a recurring finding becomes a process change rather than a one-off fix.
Findings from sub-agents or the team discussion are unverified reports, not established facts. Before an action item relies on one, re-check it against the primary source — reopen the file, the commit, the spec. A finding whose source does not hold up is dropped, not routed.
## Action items
Compile fix-now findings and process lessons into specific, owned action items. Each names what to change and who owns it. Two kinds are *proposed, not applied* in this version:
- **Remediation** — code fixes are written up as action items (or story-shaped work) for the normal dev loop to execute later. The retrospective does not run the dev loop itself.
- **Spec reconciliation** — where the as-built diverges from the spec, propose the reconciliation as an action item with the evidence attached. The human applies it to the project contract; an uncertain interpretation is never written into the spec automatically.
## Previous-retro follow-through
When the previous epic's retrospective file exists, check whether the action items it committed to were completed. Read its Action items section, and its Previous-retro follow-through section for the items recorded there as not landed, and for every item, record one line in the retrospective document's Previous-retro follow-through section:
- **The item** — its action text as the previous file spells it, and its owner.
- **Whether it landed** — with the source that shows it: the commit, the file and line, the test. An item you cannot point at is "no evidence found", not "not done" — the reader must be able to tell a checked item from an unchecked one.
No status is written anywhere; the record is the follow-through. A run with no previous retrospective file, or one whose file has no Action items section, records that there was nothing to follow through on — and which of those it was, so a missing file is never mistaken for "no outstanding items."
## The verdict
Judge the final state against the epic file's Done when. If the epic file has none, profile the criteria from the diff and plans and mark the verdict as **profiled** rather than declared. Weigh verification results (the Phase 2 behavior check) and unresolved findings. Render one of:
- **Accepted** — criteria demonstrably met in the evidence, no blocking findings open, and **no unfinished tickets** for this epic.
- **Accepted-with-open-items** — criteria met, but named findings remain deferred and tracked — still only when every ticket of this epic is finished.
- **Rejected** — criteria not met, a blocking finding stands unresolved, **or any of this epic's tickets is still unfinished**.
### Unfinished tickets
`pending_tickets` is authoritative for this epic's incomplete work: the `ref`s of the `tickets.py status <folder>` rows that are unfinished — `status` not `built` and `state` not `done` or `dropped` — in build order. When that list is non-empty:
- The **machine** verdict is **rejected**. Name every unfinished ticket in the Acceptance verdict section as the evidence. Do not soften this to accepted-with-open-items: unfinished delivery is not an open finding about a finished epic — the epic itself is incomplete.
If the completeness check did not run (`tickets.py status` failed), do **not** render a rejected or accepted verdict from the absence of data — say the check was unavailable and weigh only the criteria and findings you have.
Three hard rules:
1. A human decision always overrides the machine verdict.
2. An epic that fails its criteria with **no** human decision is recorded as **not accepted** — never as silently accepted.
3. A non-empty `pending_tickets` list makes the machine verdict **rejected**, including in headless mode.
The verdict and its evidence carry into the Phase 5 document.
@@ -0,0 +1,17 @@
# Aggregate Views
Phase 2. An epic is many coding sessions, each validated in isolation; the defects that matter are the ones no single session — and no single diff hunk — could see. Nine sessions each added three hundred lines and none ever saw the 3,000-line class they collectively built. These views are properties of the *whole* change, derived across the full diff range from Phase 1.
Prefer deterministic derivation: a script that measures the codebase is evidence; a model's impression is not. Where you compute a view inline instead of by script, record the narrowed scope. Every observation that becomes a finding carries a source reference — the file, the symbol, the commits. `{{ rendered("references/evidence-gathering.md") }}` is authoritative for what every `git_evidence.py` key means, including the commit-level `is_merge` and `stories` — read it there before deriving anything from the numbers.
## The catalog
- **Architecture delta** — how the dependency structure changed across the epic. Where a language-native dependency tool exists (dependency-cruiser, madge, pydeps, and the like), run it before and after the range and diff the graphs; otherwise derive the module/import graph from the changed files. Look for new cross-cutting dependencies, layering violations, and cycles introduced — structure the code's own conventions would forbid but no single ticket tripped.
- **Duplication map** — the same problem solved more than one way across tickets. Two sessions independently writing near-identical logic, or a helper reimplemented because the second session did not know the first existed.
- **God-class / size growth** — files that grew past a healthy size *over the epic*, invisible per-commit because each session added only a little. The `git_evidence.py` pre-pass (Phase 1) reports `added` / `deleted` / `net` per path in `files` — *change volume*, not a file's absolute size or a per-commit growth rate. Those sums cover the range's **non-merge** commits only, and they are always integers: an unmeasurable revision is left out of them rather than nulling them. Rank on `files`, then open the top of the ranking and read each file's real current size and structure before calling anything a god-class — high net churn makes a file a candidate to inspect, not a verdict on its own. Three qualifiers say how far the ranking can be trusted: `binary_revisions` counts that path's revisions whose churn could not be measured, so its true volume is *at least* what the sums report; `merges_measured` short of `merge_count` means some merges were never measured at all, which caps how complete the ranking can be; and `merge_files` mostly restates churn `files` already counted, so summing the two double counts — but it is not redundant, because a merge's first-parent diff also carries whatever the conflict resolution itself added, code that lives in no non-merge commit and therefore appears in `files` nowhere. So read `merge_files` separately, for the paths whose churn shows up only there, rather than discarding it as double counting. Whether a flagged file is genuinely a god-class or legitimately large stays your judgment.
- **Pattern divergence** — where the epic's code diverges from the conventions the surrounding codebase already established: naming, error handling, test structure, module boundaries. Agents learn conventions by pattern-matching the code, so divergence compounds.
- **Spec-to-implementation reconciliation** — where the as-built diverges from the epic file's Done when and the initiative Requirements each ticket's `covers` names, with PRD/architecture as context. Requirements silently dropped, added behavior nobody specified, intent reinterpreted between tickets. Each divergence is either a defect (fix), an accepted deviation (record so later runs stop re-flagging it), or a spec that should be reconciled to reality (propose in Phase 4).
## Delegation
When sub-agents are available, delegate the derivation: each returns evidence with source refs and checked scope, never a verdict — the parent consolidates and decides. Give each a narrow view and an explicit return format. When sub-agents are unavailable, compute the highest-value views inline (architecture delta and spec reconciliation first) and record which views were narrowed or skipped.
@@ -0,0 +1,30 @@
# Evidence Gathering
Phase 1 of the retrospective. Enumerate what the completed epic produced, so every later analysis works from real artifacts instead of memory. Output is an inventory: what exists, what is missing, and the diff ranges the rest of the retro will read.
## Inventory checklist
Collect what the epic produced and note the source path or range of each:
- **Epic file** — `epic-<slug>.md` in the epic folder, the folder's name plus `.md`: Description, Outcome, Done when, Boundaries, and Notes. Done when governs Phase 4; when the file has none, note that the verdict will be profiled from the diff.
- **Initiative requirements** — the Requirements section of the initiative file in the epic folder's parent. Each ticket's `covers` names ids there.
- **Entries** — the `tickets` rows of `tickets.py status <folder>`, and for each, `tickets.py find <folder> <ref>` with the row's `ref` (same command form as the workflow): its `description`, `verify`, and `covers` are what the build was given. `description` and `verify` are empty once the entry was pulled: the story file holds them.
- **Story files** — `find`'s `story_file` when it is not null: the intent of a ticket a person reviewed or refined.
- **Plans** — `find`'s `plan` for each ticket: its frontmatter (`status`, `baseline_revision`) and the sections Review Triage Log, Verification, Plan Change Log, and the dated `### <date>` blocks under `## Code Review`, absent when no review ran. These mark the boundaries between build sessions.
- **Diff ranges and commits** — the full set of changes the epic introduced, one range per plan (see Ranges from the plans below). For each range, run `uv run --no-cache {skill-root}/scripts/git_evidence.py --repo {project-root} --range <range> --stories <story-ids>` to get, as JSON, the commits in the range and the per-file change volume — added / deleted / net across the range — that Phase 2 reads. Record each range explicitly; Phase 2's aggregate views and the `bmad-review` pass both read them. When a range cannot be established, say so and narrow the scope rather than guessing. Read the output keys precisely: each commit carries `is_merge` and `stories` — *every* id its subject names, so a commit spanning two stories counts for both. `files` sums non-merge commits only. `merge_files` is each measured merge's diff against its first parent, so it *restates* the churn that merge brought in plus whatever the conflict resolution added — never add it into `files`, and never read it as merge-introduced work on its own. `merges_measured` counts the merges on the range head's first-parent spine; `merge_count` counts every merge in the range, so a gap between the two means merges went unmeasured. `binary_revisions` is unmeasured churn, not zero churn.
- **Previous retrospective** — `<folder name>-retrospective.md` in the previous epic's folder, if one exists, located as the workflow's Inputs say, so Phase 4 can check whether last epic's action items landed.
- **Session logs** — conversation or session records for the epic's tickets, when available. They are the only record of *why* a session took an unexpected turn — what was tried and abandoned. They are also the evidence most likely to be deleted or expire, so capture references now.
## Ranges from the plans
Each plan records its own `baseline_revision`, the commit its build started from, so there is no single epic-wide range. Order the plans by their baselines' place in history, oldest first (`git merge-base --is-ancestor A B` says A is older) — the order the builds started, which need not be the row order. A plan's range runs from its baseline to the next baseline in that order; the last plan's range runs to `HEAD`, marked inferred rather than recorded. When later work has landed since, end it at the last commit that belongs to this epic's tickets, judged from the plans and commit subjects, and record the cut. A plan whose `baseline_revision` is missing or `NO_VCS` gets no commit or diff evidence — record that too. Two plans sharing a baseline give the earlier one an empty range: that ticket simply has no commits of its own. Group the tickets sharing an identical range and run `git_evidence.py` once per distinct range, passing that group's `ref`s (`3.4`, as `status` spells them) as one comma-separated `--stories` value. A commit's `stories` is usually empty, since subjects rarely name a ref; the range is the attribution, and an empty list is not missing evidence. Ranges may overlap or diverge; count a shared commit or file change once in the aggregate views while keeping each ticket's range as its provenance.
## Missing evidence
Evidence availability varies; never hide a gap. Each later analysis declares what it needs and, when that input is absent, records a narrowed scope rather than guessing. A reader of the final retro must always be able to tell **"checked and clean"** from **"never checked."**
- Missing session logs → process-lesson analysis is skipped, and the retro says so.
- No Done when in the epic file → the verdict is profiled from the diff and plans, flagged as profiled rather than declared.
- Sub-agents unavailable → analyses that would delegate run inline over a narrowed scope, and the narrowing is recorded.
Carry the inventory forward into Phase 2 as the authoritative list of what is available to read.
@@ -0,0 +1,44 @@
# Finalize: Retrospective Document
Phase 5. Finalize the retrospective document.
## The retrospective document
This document is the run's working artifact: it is created as a skeleton once the epic is fixed and filled as each phase completes, so Phase 5 finalizes rather than writes it from scratch. It lives at `<epic folder>/epic-<slug>-retrospective.md`, as readable markdown — a fixed name, so a resumed run finds it.
Open the document with YAML frontmatter a machine can read without parsing the prose — an epic gate or orchestrator keys off `verdict` to decide whether to hold the next epic:
```
---
epic: epic-<slug>
date: {date}
verdict: accepted | accepted-with-open-items | rejected
criteria: declared | profiled
headless: true | false
---
```
`epic` is the folder's name, as `tickets.py` spells the epic. Keep `verdict` in sync with the Acceptance verdict section below. Never write a `type` or `ticket` field into this frontmatter: `tickets.py` reads a markdown file in the epic folder as a ticket when `type` is a ticket type and as a plan when `ticket` is present. This frontmatter is the only machine-readable verdict; nothing in the tree records it, so a gate or orchestrator that acts on the verdict **must** read this file.
Sections:
- **Epic summary** — which epic, its tickets with their statuses, the tickets still at `built`, any tickets still unfinished (`pending_tickets`) that the user accepted retro-ing over, each plan's range, the evidence inventory (what was available, what was missing). Unfinished tickets force the machine acceptance verdict to **rejected** (see `{{ rendered("references/acceptance-verdict.md") }}`).
- **Findings** — grouped by aggregate view and by lens, each with its source reference and disposition (fix now / defer / accept). This is the record; do not summarize away the provenance.
- **Behavior verification** — what was exercised end to end and what was observed, or an explicit note that runtime behavior was not exercised.
- **Previous-retro follow-through** — if a prior retro exists, whether its action items landed, with evidence (`{{ rendered("references/acceptance-verdict.md") }}` specifies what to record).
- **Action items** — the routed fix-now items and process lessons, each with an owner. Note which are proposed remediation or spec reconciliations awaiting human application.
- **Acceptance verdict** — accepted / accepted-with-open-items / rejected, whether the criteria were declared or profiled, and the evidence behind the call.
- **Open questions** — what a human answer would materially change, and anything the analyses could not resolve.
- **Assumptions** — in headless runs, every choice made without the user: how the epic reference resolved to its folder, any non-empty `pending_tickets`, a machine **rejected** verdict forced by unfinished tickets or rendered with no human decision, each proposed item. Omit in interactive runs — an interactive run records the same facts where the user confirmed them, in Epic summary.
Do not state time estimates anywhere in the document.
## Finish
Report the document's path, the verdict, and the action-item count. Nothing else was written: no status changed, and no tree file was edited.
## On Complete
If anything appears below, follow it as the final terminal instruction before exiting; otherwise exit normally.
{{ workflow.on_complete }}
@@ -0,0 +1,22 @@
# Team Discussion (opt-in)
An optional discussion layer over Phase 2's findings, off by default. It exists for users who want the retrospective discussed from multiple perspectives, the way a team would. One rule: **the team discusses evidence, never invention.** Agents speak only to findings that carry source references. No agent may describe an event that did not happen or report a pattern the diff does not show.
## When to run it
Only when asked — "discuss it as a team," "run party mode," or similar. A default run never enters this phase.
## How to run it
Invoke **`bmad-party-mode`**, seeded with the consolidated Phase 2 findings and the epic context, so the installed agents react as real subagents with independent thinking rather than a scripted dialogue. Seed it with:
- The findings, each with its source reference, grouped by the aggregate view or lens that produced it.
- The improvements the evidence confirms — real gains, patterns that worked — so positive observations are grounded in fact.
- The epic's acceptance criteria (or the profiled stand-in), so the discussion can weigh the verdict.
- The previous epic's action items and whether they landed, when a prior retro exists, so accountability is grounded in fact.
If `bmad-party-mode` is unavailable, a discussion the user asked for must not silently fail to happen. Run it inline over the same seed — take each perspective yourself, hold every perspective to sourced findings — and record in the retrospective document that the discussion ran inline rather than through the installed agents. Record it as the narrowing it is: one model playing every role loses the independent disagreement that surfaces missed findings. State that in the document rather than omitting it.
Keep the user an active participant and steer toward systemic understanding over blame — the point is which process or convention would have prevented a finding, not who wrote the line. Capture anything the discussion surfaces that the analyses missed; a genuinely new observation becomes a finding only once you can tie it to a source, otherwise it is a question for Phase 4, not a conclusion.
The discussion does not replace Phase 4. Its output feeds the action items and the verdict; it does not render them.