From ed5827cbdcc8f78ebc39eaedb1760add6b0c5f22 Mon Sep 17 00:00:00 2001 From: Brian Madison Date: Tue, 9 Jun 2026 00:04:11 -0500 Subject: [PATCH] bmad-spec: make the memlog canonical, SPEC.md a derived view Replace the bespoke .decision-log.md with the shared memlog script (_bmad/scripts/memlog.py, same location as resolve_customization.py). The append-only memlog becomes the single source of truth; SPEC.md and spec-authored companions are re-derived from it (plus cited sources for raw content) on each run instead of hand-patched. This makes bmad-spec the sole writer of the spec and lets the surrounding steps (PRD, UX, architecture, epics) feed one spec in any order without merge drift. - New "Memory and derivation" section: memlog canonical, SPEC.md a projection, single-writer rule, append/init via the shared script, no status field (terminal moments are event entries). - Operation reads the prior memlog (not the rendered SPEC.md) as the authority on decisions and capability IDs on update. - Conflict-surfacing: live sources/companions that disagree on a field are raised to the user, resolution logged as a new entry. - Rename .decision-log.md -> .memlog.md across SKILL.md and assets. --- src/core-skills/bmad-spec/SKILL.md | 30 ++++++++++++++----- .../bmad-spec/assets/headless-schemas.md | 6 ++-- .../bmad-spec/assets/spec-template.md | 2 +- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/core-skills/bmad-spec/SKILL.md b/src/core-skills/bmad-spec/SKILL.md index 97baefed3..bd8d92235 100644 --- a/src/core-skills/bmad-spec/SKILL.md +++ b/src/core-skills/bmad-spec/SKILL.md @@ -43,15 +43,27 @@ Inside the spec folder: ``` / - SPEC.md ← uppercase, the kernel - .md ← optional, content-typed (e.g. glossary.md) + SPEC.md ← uppercase, the kernel — DERIVED from .memlog.md, never hand-edited + .md ← optional, content-typed (e.g. glossary.md); spec-authored ones are derived too .md - .decision-log.md ← canonical memory for this spec + .memlog.md ← canonical, append-only memory; what SPEC.md is distilled from ``` +## Memory and derivation + +`.memlog.md` is canonical — an append-only, chronological record of every decision, constraint, capability (with its stable `CAP-N`), assumption, open question, and bit of user direction, one line each in the order it happened, never edited or reordered. `SPEC.md` and every spec-authored companion are **derived on each run** from the memlog (the decision-of-record) plus the sources it cites for raw content — never hand-patched. + +Deriving the contract from a living log instead of editing the contract in place is what lets the steps around the spec (PRD, UX, architecture, epics) run in any order and feed the same spec without merge drift: the log only accumulates, the artifact is re-rendered. So the spec is updated *only* by re-deriving it here — bmad-spec is its single writer; a hand-edit to `SPEC.md` from outside is unsupported and is overwritten on the next derive. + +Writes go through the shared script — `{project-root}/_bmad/scripts/memlog.py`, the same location as `resolve_customization.py` (atomic; never read it back except to resume): + +- `python3 {project-root}/_bmad/scripts/memlog.py init --workspace {spec-folder} --field topic=""` — once, at create. +- `python3 {project-root}/_bmad/scripts/memlog.py append --workspace {spec-folder} --type --text ""` — as each lands. +- Terminal moments (a validation verdict, "spec finalized") are `--type event` entries; the memlog carries no status field. + ## The Operation -Read the input and its ancillary linked materials. If there is no input, follow the no-input branch in **Workspace** (ask or block). If a prior `SPEC.md` exists at the target folder, read it too — the operation becomes an update. Preserve capability IDs; new capabilities get the next unused `CAP-N`; never reuse retired IDs. Otherwise this is a create. +Read the input and its ancillary linked materials. If there is no input, follow the no-input branch in **Workspace** (ask or block). If a prior `.memlog.md` exists at the target folder, read it — the operation becomes an update, and the memlog (not the rendered `SPEC.md`) is the authority on what was decided and on capability IDs. Preserve those IDs; new capabilities get the next unused `CAP-N`; never reuse retired IDs. Otherwise this is a create, and the first move is `memlog.py init`. When the input is structured and pre-sorted (a PRD with an addendum, a GDD, a brief produced by an upstream BMad skill), trust the authored separation: lift kernel-fitting content into SPEC.md, lift overflow into appropriately-named companions. When the input is mixed (a brain dump, a transcript, an RFC, a customer email), do the sorting yourself: walk each claim, apply the three-lens load-bearing test (Spec Law rule 7), and route to the kernel field or a companion. @@ -59,6 +71,8 @@ Distill the input into the five-field kernel using `{workflow.spec_template}` as Write lean from the first pass: every sentence must earn its place. Decoration costs tokens and dilutes downstream readers. +Log each decision, capability, constraint, and accepted change to `.memlog.md` as it is made — that running record is what the render reads. Because the log is append-only, a later entry supersedes an earlier one on the same point while the history stays intact. When two currently-live sources or companions disagree on the same field, or an either/or never got resolved, surface it to the user rather than silently choosing — the resolution is itself a new memlog entry. + If the input is genuinely too thin to distill (e.g. "an app for hikers" with no surrounding context), stop and suggest `bmad-prd` (or sibling ceremony skill). This skill distills; it does not coach. ## Load-bearing @@ -94,7 +108,7 @@ Every spec must satisfy these eight rules. The operation aims for them; the self 5. **Success signal is concrete enough to test or demonstrate against.** "Users love it" doesn't qualify. 6. **Capability IDs are stable and unique.** Never reused, never renumbered. 7. **Preservation.** Every load-bearing source claim lands in SPEC.md or a companion. Wrapper ceremony does not. -8. **Lean prose.** Every sentence carries load-bearing content. Cut decoration, hedges, backstory, throat-clearing. Applies to SPEC.md, companions, and `.decision-log.md`. +8. **Lean prose.** Every sentence carries load-bearing content. Cut decoration, hedges, backstory, throat-clearing. Applies to SPEC.md, companions, and `.memlog.md`. ## Self-Validate @@ -104,7 +118,7 @@ After every create or update, sweep the resulting artifact in **two passes** bef **Pass 2 — Preservation.** Walk the source claim by claim. Confirm each load-bearing claim landed in SPEC.md or a companion. Wrapper-ceremony drops are logged under "Wrapper-only content" so the drop is on the record, not silent. -Append a one-paragraph verdict to `.decision-log.md` covering both passes. In interactive mode, review the verdict with the user. In headless mode, `.decision-log.md` is one of the files returned, so the caller (or its downstream LLM) reads the verdict there. +Record the verdict for each pass to `.memlog.md` (`append --type event`). In interactive mode, review it with the user. In headless mode, `.memlog.md` is one of the files returned, so the caller (or its downstream LLM) reads the verdict there. ## Spec with no change signal @@ -120,10 +134,10 @@ Run `{workflow.on_complete}` if set. ## After Spec is Output -Any update to spec regarding assumptions, open questions, or other changes should be appended to that source's decision log also and offer to update the source. +Any update to the spec — resolved assumptions, answered open questions, other changes — is appended to `.memlog.md` as it happens. When a change overrides something that came from a source input, offer to update that source too, so upstream and the spec don't silently diverge. ## Frontmatter conventions - `companions:` array of `.md` files downstream MUST read alongside SPEC.md to have the full contract. Paths may point inside the spec folder (spec-authored companions like `glossary.md`) or outside it (adopted companions like `../planning-artifacts/ux-designs/ux-foo-bar-2026-05-23/DESIGN.md`). The split between spec-authored and adopted is implicit by path; downstream treats both the same. - `sources:` array of paths to files that were **fully absorbed** into the SPEC, with no remaining downstream value (e.g., a PRD whose every load-bearing claim is now in the kernel). Listed for audit and for bmad-spec to re-read on update. Downstream does NOT read these. Files that downstream still needs to read belong in `companions:`, not here. -- **Do not list** decision logs, README files, organizational artifacts, or any operational record of how upstream skills produced their artifacts. Those are not source content; they are process metadata that downstream consumers don't need. +- **Do not list** the memlog, README files, organizational artifacts, or any operational record of how upstream skills produced their artifacts. Those are not source content; they are process metadata that downstream consumers don't need. diff --git a/src/core-skills/bmad-spec/assets/headless-schemas.md b/src/core-skills/bmad-spec/assets/headless-schemas.md index 096b15803..8e2093bec 100644 --- a/src/core-skills/bmad-spec/assets/headless-schemas.md +++ b/src/core-skills/bmad-spec/assets/headless-schemas.md @@ -1,6 +1,6 @@ # Headless JSON Response -The default invocation is headless: input goes in, JSON comes out. The contract is intentionally tiny — return the outcome and the files touched. Anything else a caller needs is inside those files (SPEC.md, companions, `.decision-log.md`). +The default invocation is headless: input goes in, JSON comes out. The contract is intentionally tiny — return the outcome and the files touched. Anything else a caller needs is inside those files (SPEC.md, companions, `.memlog.md`). ## Success @@ -10,12 +10,12 @@ The default invocation is headless: input goes in, JSON comes out. The contract "files": [ "_bmad-output/specs/spec-quarter-drop/SPEC.md", "_bmad-output/specs/spec-quarter-drop/glossary.md", - "_bmad-output/specs/spec-quarter-drop/.decision-log.md" + "_bmad-output/specs/spec-quarter-drop/.memlog.md" ] } ``` -`files` lists every file written or modified in this run, in any order. The spec folder, kernel filename, decision log location, capabilities, companions, and verdict are all readable from those files; no need to re-encode them in the response. +`files` lists every file written or modified in this run, in any order. The spec folder, kernel filename, memlog location, capabilities, companions, and verdict are all readable from those files; no need to re-encode them in the response. ## Blocked diff --git a/src/core-skills/bmad-spec/assets/spec-template.md b/src/core-skills/bmad-spec/assets/spec-template.md index f8127204c..9c2868be1 100644 --- a/src/core-skills/bmad-spec/assets/spec-template.md +++ b/src/core-skills/bmad-spec/assets/spec-template.md @@ -1,7 +1,7 @@ --- id: SPEC-{slug} companions: [] # files downstream MUST read alongside SPEC.md. Paths may point inside the spec folder (spec-authored) or outside it (adopted from an upstream skill). -sources: [] # files fully absorbed into the SPEC (audit only; downstream does NOT read these). Never decision logs. +sources: [] # files fully absorbed into the SPEC (audit only; downstream does NOT read these). Never the memlog. --- > **Canonical contract.** This SPEC and the files in `companions:` are the complete, preservation-validated contract for what to build, test, and validate. Source documents listed in frontmatter are for traceability only — consult them only if you need narrative rationale or prose color this contract intentionally omits.