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
- Four kinds of memory
- Resuming: how work picks back up
- Measuring whether BMAD helps
- Improving the workflow over time
- Hands-on: write a project-context.md, then watch memory work
- Under Claude Code: CLAUDE.md, compaction, and where BMAD’s files fit
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:
| State | Home | Survives fresh chat? | In git? |
|---|---|---|---|
| install / module state | _bmad/_config/manifest.yaml | yes | usually |
| team + personal config | _bmad/config*.toml, _bmad/custom/* | yes | team yes, personal no |
| project rules | _bmad-output/project-context.md | yes | yes |
| workflow progress | artifact frontmatter, spec status | yes | if committed |
| product decisions | PRD, architecture, .memlog.md | yes | yes |
| sprint progress | _bmad-output/implementation-artifacts/sprint-status.yaml | yes | yes |
| the conversation | the host context window | no | no |
| subagent scratch | a run folder / digest | only if written | sometimes |
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.mdon activation, so you can close a PRD session and reopen it days later. bmad-dev-autoresumes from a spec's frontmatterstatus(draft-> plan,ready-for-dev/in-progress-> implement,in-review-> review,blocked-> halt). An orchestrator readsstatus, the blocking condition, andbaseline_revision..final_revisionto know exactly what a run produced, rather than inferring success from chat output.bmad-sprint-planningwritessprint-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:
| Measure | What it tells you |
|---|---|
| time from idea to first falsifiable experiment or shipped slice | rewards useful analysis over document volume |
| share of PRD claims that carry an evidence or assumption label | tests epistemic traceability, not confident guessing |
| readiness-gate defects caught before any code | measures how much error is caught while it is cheap |
| story clarification and rework rate | tests whether the artifact handoff was actually clear |
| acceptance criteria rejected during code review | reveals upstream ambiguity that leaked downstream |
| research sources read per decision actually changed | detects browsing theater (reading that changed nothing) |
| token and wall-clock cost per workflow and mode | supports the Quick vs Full vs Loop choice on real numbers |
| stale claims refreshed before a decision relied on them | tests lifecycle discipline (the staleness map, used) |
| production reversals traced to a wrong upstream assumption | the 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-retrospectiveafter an epic captures what the process got right and wrong. Feed its lessons back intoproject-context.mdand your overrides so the next epic starts smarter. - Course correction. When reality diverges from the plan,
bmad-correct-coursereconciles 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.mdrather than flooding a review, andbmad-loop-sweeptriages 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/*.tomloverride (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. 👉