Memory and measurement in BMAD

Two questions this page answers. How does BMAD remember anything across sessions, given that a chat's context window is gone the moment you close it? And how do you tell whether the method is earning its overhead, rather than becoming ceremony? The first is about state; the second is about metrics. Both come down to files.

On this page

The one principle: externalized state

BMAD's design rule is that every result that must affect a later phase becomes a file. The conversation is a control channel, never the store. A fresh chat then becomes a quality feature (clean context, no stale residue) rather than a reset, because everything that matters was written down. This is why the docs insist on a fresh chat per workflow: the cost of losing the conversation is zero when the state is on disk.

Concretely, here is what survives a fresh chat and what does not:

StateHomeSurvives fresh chat?In git?
install / module state_bmad/_config/manifest.yamlyesusually
team + personal config_bmad/config*.toml, _bmad/custom/*yesteam yes, personal no
project rules_bmad-output/project-context.mdyesyes
workflow progressartifact frontmatter, spec statusyesif committed
product decisionsPRD, architecture, .memlog.mdyesyes
sprint progress_bmad-output/implementation-artifacts/sprint-status.yamlyesyes
the conversationthe host context windownono
subagent scratcha run folder / digestonly if writtensometimes

Four kinds of memory

BMAD keeps memory in four distinct places, and confusing them is the root of most "the agent forgot" complaints.

1. The memlog: process memory for one piece of work. Skills that run a long session (PRD, brainstorm, deep-recon) keep a .memlog.md: an append-only, chronological log written through a shared script (_bmad/scripts/memlog.py). Every decision, idea, question, and assumption is one line, recorded in the order it happened; the chronology itself is the structure. It is not a deliverable, it is working memory that persists across sessions, so a fresh session can read the last few lines and continue. Downstream artifacts (a brief, a PRD, a report) are derived from it on demand. Three invariants make it trustworthy: it is append-only (history is never rewritten), write-only (each command echoes state so the caller never re-reads the file mid-session), and status-free (whether work is done, blocked, or paused is itself just another logged event, so the log never has to mutate).

2. project-context.md: durable memory for the whole project. The constitution from the anatomy page. It is not session memory; it is standing memory that every implementation workflow reloads, so a convention you record once ("all API calls go through the apiClient singleton") is enforced across every future story, forever, without re-explaining. Treat it as a living file: when you catch an agent repeating a mistake, the fix is usually a line here.

3. The artifact chain: memory between phases. research.md, brief.md, prd.md, ARCHITECTURE-SPINE.md, and each story-*.md are typed, reviewable messages from one context to the next. Winston (the architect) can run in a fresh chat weeks after John (the PM) because John's decisions are in the PRD, not in a scrollback John no longer has. The artifact metadata (frontmatter with type, dates, source, status) is what lets a downstream skill trust an upstream one without reprocessing it. Deep Recon's staleness map is a specialized form of this: a per-claim record of when evidence needs re-checking, so research becomes a thing you maintain rather than redo.

4. Config and roster: memory of how the team works. The _bmad/custom/*.toml overrides and the agent roster in central config are standing memory of your org's conventions, applied on every activation. Party Mode adds a fifth, narrow form: each saved party keeps its own memory of past sessions (dynamics, open threads, where a conversation landed), which is "memory, not a transcript," carrying only the few things worth remembering.

Resuming: how work picks back up

Because state is on disk, resuming is reading, not remembering. A few concrete mechanisms:

  • Any workflow re-reads its inputs and its own .memlog.md on activation, so you can close a PRD session and reopen it days later.
  • bmad-dev-auto resumes from a spec's frontmatter status (draft -> plan, ready-for-dev/in-progress -> implement, in-review -> review, blocked -> halt). An orchestrator reads status, the blocking condition, and baseline_revision..final_revision to know exactly what a run produced, rather than inferring success from chat output.
  • bmad-sprint-planning writes sprint-status.yaml, the single ledger the whole cycle (and the BMad Loop orchestrator) reads to know which stories are done, in review, or pending.
  • Deep Recon writes every digest to its run folder the moment it lands, so a run that dies mid-flight resumes from disk with nothing lost.

The practical takeaway: if you want something to be remembered, make sure a skill wrote it to a file. If a decision lives only in a chat you closed, BMAD did not externalize it, and the next agent will not know it.

Measuring whether BMAD helps

A method that is never measured drifts into ceremony: more documents, not better decisions. The honest question is not "did we follow the process" but "did the process change outcomes." A scorecard worth tracking:

MeasureWhat it tells you
time from idea to first falsifiable experiment or shipped slicerewards useful analysis over document volume
share of PRD claims that carry an evidence or assumption labeltests epistemic traceability, not confident guessing
readiness-gate defects caught before any codemeasures how much error is caught while it is cheap
story clarification and rework ratetests whether the artifact handoff was actually clear
acceptance criteria rejected during code reviewreveals upstream ambiguity that leaked downstream
research sources read per decision actually changeddetects browsing theater (reading that changed nothing)
token and wall-clock cost per workflow and modesupports the Quick vs Full vs Loop choice on real numbers
stale claims refreshed before a decision relied on themtests lifecycle discipline (the staleness map, used)
production reversals traced to a wrong upstream assumptionthe ultimate signal: did the spec chain prevent the expensive mistake

Two of these have mechanical support already. Deep Recon's recon_kit.py tally counts claims by verification status straight from the memlog, so "share of claims verified" is a script, not a vibe. And bmad-dev-auto's baseline_revision..final_revision bracket gives you exact per-run diffs to measure rework against. The rest you instrument yourself, but the discipline is simply to write the numbers down rather than allocate effort by enthusiasm.

The anti-metric to avoid is "number of artifacts produced." A two-page PRD that prevents a wrong database schema is worth more than fifty polished pages nobody reads. Optimize for decisions changed and mistakes prevented, not pages shipped.

Improving the workflow over time

BMAD gives you four levers to tune the method to your team, each backed by a file:

  • Retrospectives. bmad-retrospective after an epic captures what the process got right and wrong. Feed its lessons back into project-context.md and your overrides so the next epic starts smarter.
  • Course correction. When reality diverges from the plan, bmad-correct-course reconciles the artifacts instead of letting documents quietly contradict each other. Do not patch downstream files by hand; fix the upstream owner and let it propagate.
  • Deferred work. Quick Dev and the loop write incidental findings to deferred-work.md rather than flooding a review, and bmad-loop-sweep triages that ledger later. The workflow optimizes for signal quality over exhaustive recall on purpose: it is usually better to defer some findings than to bury a human in low-value comments.
  • Customization. Every recurring correction you make by hand is a candidate for a _bmad/custom/*.toml override (see team collaboration and extending). A rule you state once in an override is a rule you never re-type.

And one dial worth naming: gates.mode sets how much you stay in the loop, per-story-spec-approval, per-epic, or none. Start careful and loosen it as your trust in the pipeline (measured, per the scorecard above) grows. That is the shift from human in the loop to human on the loop, earned with evidence rather than assumed.

Hands-on: write a project-context.md, then watch memory work

This exercise separates the two memories that get conflated: project-context.md (durable, reloaded every workflow) and .memlog.md (per-run, append-only). You author the first by hand, let a dev story populate the second, then feed a lesson back up.

1. Author the durable file. Keep it lean. Record only rules an agent could not infer from the code in front of it: the queue rule, the tenancy rule, the no-ad-hoc-threads rule, the naming convention. Obvious conventions are noise.

# Project context: billing-svc

## Rules (non-obvious only; obvious ones omitted)
- Async work goes through the single RQ queue `bill.default`. No raw `Thread`, no `asyncio.create_task` in request handlers.
- Every table carries `tenant_id`; every query filters on it. There is no global read.
- Money is `Decimal` stored as integer cents. Never `float`.
- Module naming: services are `verb_noun.py`; RQ jobs are `noun.verb` (`invoice.finalize`).
- Idempotency keys are required on every mutating endpoint; replay returns the stored result.
- Stripe webhooks are the source of truth for payment state, not our own writes.

Write it to _bmad-output/project-context.md and commit it. From now, every implementation workflow reloads these, so you never re-explain them.

2. Or let BMAD draft one. To start from the codebase instead, the skill scans it and proposes rules for you to prune:

# In the BMAD agent chat, invoke the workflow:
bmad-generate-project-context

Illustrative (run it in your own repo; not machine-verified here).

Scanned 214 files. Proposed project-context.md (7 rules):
1. Async work uses RQ, not raw threads (rq imported in 9 handlers)
2. All models include tenant_id (present on 18/18 tables)
3. Money stored as integer cents (Decimal in ledger.py)
4. Service modules follow verb_noun.py naming
5. Idempotency keys on POST/PUT (found on 11/14 routes; 3 missing, flagged)
6. Stripe webhooks drive payment state
7. Config via pydantic Settings, not direct os.environ reads
Wrote draft to _bmad-output/project-context.md. Review and prune.

Treat the draft as a candidate list. Delete anything obvious; the value is the four or five rules that are not.

3. Run a dev story; watch per-run memory fill. Kick off bmad-dev-auto on a spec. As the dev agent makes choices it appends one line each to that run's .memlog.md through the shared script (the real logger is dissected on page 11):

bmad-dev-auto story-042
tail -f _bmad-output/implementation-artifacts/story-042/.memlog.md

Illustrative (run it in your own repo; not machine-verified here).

- (decision by dev) all async work goes through the single RQ queue `bill.default`; rejected a per-request thread
- (assumption by dev) the Stripe webhook lands before the client polls; retry covers the gap
- (question by dev) does `invoice.finalize` need its own idempotency key, or reuse the request's?

This is working memory for one story. It resumes a paused run; it is not a standing rule.

4. Feed a lesson back. After the epic, bmad-retrospective surfaces what recurred. Turn each durable lesson into one project-context line so it never repeats:

bmad-retrospective

Then append the distilled rule (not the story) to project-context.md:

- Webhook handlers must be idempotent by event id; a re-delivery double-charged once.

The memlog line was about one story; the project-context line changes every future story. That is the loop: per-run memory records what happened, the retrospective distills it, durable memory enforces it forever.

Under Claude Code: CLAUDE.md, compaction, and where BMAD's files fit

Claude Code has its own memory layers, and BMAD's externalized state maps onto them cleanly. CLAUDE.md is the always-on constitution: a managed policy file, then user (~/.claude/CLAUDE.md), project (./CLAUDE.md or .claude/CLAUDE.md), local (CLAUDE.local.md, gitignored), and nested per-subdirectory files, all loaded at session start. That is the slot BMAD's project-context.md plays (see the anatomy page): standing rules reloaded every session, no re-explaining. You extend it with @path imports (resolved relative to the file, up to 4 levels deep), append a single line with #, or edit through /memory.

Auto memory is a separate store at ~/.claude/projects/<slug>/memory/, indexed by MEMORY.md (only its first 200 lines or 25KB load at session start) with topic files pulled on demand. That is the closest native analog to BMAD's .memlog.md: process notes that carry across sessions, except Claude Code decides what to write, whereas the memlog is append-only and script-driven.

/context shows the live budget by category (system prompt, CLAUDE.md, loaded files, conversation, skills). As the window nears roughly 95%, Claude Code auto-compacts: it drops older tool outputs first, then summarizes earlier conversation, keeping CLAUDE.md, skills, and recent messages. /compact [focus] does the same on demand, and a PreCompact hook can fire first.

The load-bearing point matches this chapter exactly. BMAD's artifacts, memlog, and project-context.md live on disk and are re-read at the start of each workflow, so they survive compaction and /clear; anything living only in the conversation does not. --resume carries a window forward, a fresh session drops it, both by design.

Memory and measurement are what make BMAD a team practice rather than a solo one. The next page is about the team itself: shared config, who runs which phase, and how BMAD keeps several people (and several agents) from stepping on each other. 👉