# bmad-plus mem

> Recall past decisions and events, journal what an agent did, reinforce a pattern with reward signals and tie lessons to accepted Nexus work. Flags, files, exit codes, output and errors.

Canonical: https://bmad-plus.rochetta.fr/docs/reference/cli-mem/
Language: en
BMAD+ version: 0.23.1
Documentation reviewed: 2026-10-19
Author: Laurent Rochetta
License: MIT

BMAD+ documentation › [Reference](https://bmad-plus.rochetta.fr/docs/reference/) › bmad-plus mem

The memory pack stores what a project has learned in Markdown files: decisions, lessons and patterns. `bmad-plus mem` is the small, deterministic toolbox that lets any assistant use those files the same way, whether it runs in Claude Code, Gemini CLI, Codex CLI, Cursor, OpenCode, Aider or Antigravity. It has five actions: `recall` finds relevant past notes and events, `write` appends an event to a journal, `reinforce` raises or lowers the score of a pattern, `observe` ties a lesson to work that was independently verified and accepted, and `outcomes` lists those ties. It needs no terminal prompts and never calls a model, so an agent can run it and parse the result. This page is for anyone who wants an agent to remember with evidence, and for people who audit that memory.

<a id="synopsis"></a>
## Synopsis

**In your project terminal**

```sh
npx bmad-plus mem recall <query...> [--scope project|portfolio] [--portfolio <path>] [--limit <n>] [--ranking lexical|evidence] [--context-scope <paths>] [--json]
npx bmad-plus mem write --agent <name> [--cli <name>] [--model <id>] [--task <text>] [--outcome <outcome>] [--eval <0-1>] [--accept <bool>] [--ci <result>] [--json]
npx bmad-plus mem reinforce --pattern <id> [--eval <0-1>] [--accept <bool>] [--ci <result>] [--evidence <ids>] [--json]
npx bmad-plus mem observe --input <file> [--json]
npx bmad-plus mem outcomes [--json]
```

**Arguments and flags of mem**

| Flag | Argument | Default | What it does |
| --- | --- | --- | --- |
| `<action>` | `recall`, `write`, `reinforce`, `observe`, `outcomes` | required | Which action to run. |
| `[query...]` | words | none | The search text of `recall`. Several words are joined with spaces. |
| `-d, --directory <path>` | path | current directory | Project folder holding `.agents/memory/` and `.bmad/memory/`. |
| `--scope <scope>` | `project` or `portfolio` | `project` | `recall` only. `portfolio` also searches the memory folder of a portfolio brain. |
| `--portfolio <path>` | path | none | Portfolio brain folder; its `memory/` subfolder is searched with `--scope portfolio`. |
| `--limit <n>` | number | `8` | `recall`: how many matches to keep. |
| `--ranking <mode>` | `lexical` or `evidence` | `lexical` | `recall`: `evidence` boosts notes backed by an accepted outcome. Project scope only. |
| `--context-scope <paths>` | comma-separated relative paths | none | Required with `--ranking evidence`: the project paths the question is about. |
| `--input <file>` | project-relative path | none | `observe`: JSON file describing the outcome. |
| `--agent <name>` | text | none | `write`: the agent that produced the event. Required. |
| `--cli <name>` | text | none | `write`: the assistant that drove it (for example `claude-code`, `gemini-cli`, `codex-cli`, `cursor`, `opencode`, `aider`, `antigravity`). Stored as given. |
| `--model <id>` | text | none | `write`: model identifier, stored as given. |
| `--task <text>` | text | empty | `write`: what was attempted. |
| `--outcome <outcome>` | `success`, `failure`, `partial`, `abandoned` | none | `write`: result of the attempt. |
| `--pattern <id>` | text | none | `reinforce`: the pattern heading in `patterns.md`. Required. |
| `--eval <score>` | number from 0 to 1 | none | Reward signal: score of an evaluation suite. |
| `--accept <bool>` | `true`, `false` (or `yes`, `no`), or a number from 0 to 1 | none | Reward signal: whether the person accepted the result. |
| `--ci <result>` | `pass`, `fail`, or a number from 0 to 1 | none | Reward signal: continuous-integration outcome. |
| `--evidence <ids>` | comma-separated event ids | none | `reinforce`: journal events backing the reinforcement; copied into a promotion proposal. |
| `--json` | none | off | Print JSON instead of text. Errors become `{"error": "..."}`. |

<a id="reads-writes"></a>
## What it reads and writes

**Files used by mem**

| File | Role | Written by |
| --- | --- | --- |
| `.bmad/memory/journal.ndjson` | Append-only journal of events, one JSON object per line. | `write` |
| `.bmad/memory/pattern-scores.json` | Score of each reinforced pattern (an Elo rating and a Beta distribution). | `reinforce` |
| `.bmad/memory/promotions.ndjson` | Promotion proposals. Always status `PROPOSED`. | `reinforce` |
| `.bmad/memory/outcomes.ndjson` | Receipts that tie a memory section to accepted Nexus work. | `observe` |
| `.bmad/memory/writer.lock` | Short-lived lock that serialises writers. | every writing action |
| `.agents/memory/` and `.bmad/memory/` `decisions.md`, `lessons.md`, `patterns.md` | Human notes, split into sections at each `### ` heading. Read only. | you and your agents |

Every store is limited to 2 MiB, the outcome store to 1000 receipts, and paths must stay inside the project without following symbolic links. A damaged line in the journal is skipped when reading, never fatal.

<a id="actions"></a>
## The five actions

<a id="recall"></a>
### recall

Searches the journal events and the `### ` sections of `decisions.md`, `lessons.md` and `patterns.md`, in both `.agents/memory/` and `.bmad/memory/`. Ranking is lexical: words of the query found in an entry, with diminishing returns for repeats, a bonus for how much of the query matched and a length normalisation. Journal events lose half their weight every 30 days. No search service or Python is needed. With `--scope portfolio --portfolio <path>` the `memory/` folder of a portfolio brain is searched too. With `--ranking evidence` (project scope only, and `--context-scope` is then mandatory) a note that has a valid accepted outcome receipt for the given paths has its score multiplied by 1.25; a note whose receipts are all stale, superseded or contradicted is dropped instead of silently falling back; notes without any receipt stay, marked `unverified`.

<a id="write"></a>
### write

Appends one event to `.bmad/memory/journal.ndjson` with the time of the call, the agent, the optional assistant, model, task, outcome and the reward signals you passed. The event id is derived from the time, the agent and the task, so it is reproducible. Nothing in the event is a measurement made by BMAD+: the signals are what the caller reports.

<a id="reinforce"></a>
### reinforce

Folds the signals into one reward between 0 and 1: `--eval` weighs 0.5, `--accept` 0.3 and `--ci` 0.2, and signals you leave out are ignored with the weights renormalised, so a CI-only call still gives a usable reward. The reward moves the pattern’s Elo rating (starting at 1200, K factor 32) and its Beta distribution (starting at 1 and 1, with decay so old evidence fades). When the Beta mean reaches 0.7 over at least 3 updates, a promotion from `candidate` to `validated` is written to `promotions.ndjson`, always with status `PROPOSED`. Applying it needs a human or Shield approval that this command can never record. The result says `evidenceStatus: self-reported` and `rankingEligible: false`: a reinforcement is the caller’s claim, not accepted evidence.

<a id="observe"></a>
### observe and outcomes

`observe` is the only way a lesson gets evidence. It reads a JSON file and writes a receipt only when the Nexus task it names is accepted, its latest attempt completed, its independent verification passed and its evidence still current, and only when the memory section it names exists exactly once. The receipt records the hash of that section and the task, and states `lessonCausality: unmeasured`: BMAD+ does not claim the lesson caused the success. `outcomes` re-checks every receipt against today’s files and prints `accepted-current` or the reason it no longer counts: `superseded`, `contradictory`, `stale-memory-section` (the section text changed), `stale-outcome-source` (the Nexus task changed) or `unavailable-or-ineligible-source`.

**Input file of observe**

```json
{
  "runId": "<nexus run id>",
  "taskId": "<accepted task id>",
  "memory": { "file": ".agents/memory/lessons.md", "heading": "<exact ### heading>" },
  "scope": ["src/auth"],
  "interpretation": "Why this accepted work supports the lesson.",
  "supersedes": [],
  "contradicts": []
}
```

`memory.file` must be `decisions.md`, `lessons.md` or `patterns.md` under `.agents/memory/` or `.bmad/memory/`. `scope` lists 1 to 30 relative paths and must stay inside the scope of the accepted task. `supersedes` and `contradicts` name earlier receipt ids that overlap the same scope; no id can be in both. A task attempt can produce only one receipt.

<a id="exit-codes"></a>
## Exit codes

**Exit codes of mem**

| Code | Meaning |
| --- | --- |
| 0 | The action ran. A `recall` without matches is still 0. |
| 1 | Unknown action, missing required flag, invalid value, locked store or any other failure. With `--json` the error is printed on standard output as `{"error": "..."}`; otherwise on the error stream as `mem <action>: <message>`. |

<a id="real-output"></a>
## Reading the output

**recall (scores and note illustrative)** (Simulated)

```text
$ npx bmad-plus mem recall auth strategy
mem recall: 1 match(es) for "auth strategy" (scope: project)
  1. [0.412] note decisions.md § Auth strategy
     Use short-lived sessions with server-side revocation.
```

Illustrative transcript, not captured from a real run. Source: tools/cli/commands/memory-journal-cmd.js (runRecall message templates); scores and text are made up

**write, then reinforce (computed from the formulas, ids illustrative)** (Simulated)

```text
$ npx bmad-plus mem write --agent forge --cli claude-code --task "Add login rate limit" --outcome success --ci pass
mem write: event 3f9a1c7b02de appended (2026-10-18T09:30:00.000Z)
  agent=forge cli=claude-code model=- outcome=success
  task: Add login rate limit
$ npx bmad-plus mem reinforce --pattern "Rate limit on auth routes" --accept true --ci pass
mem reinforce: pattern "Rate limit on auth routes"
  reward   1.000 (from {"acceptance":true,"ci":"pass"})
  elo      1200.0 -> 1216.0
  mean     0.667 (alpha=2.00, beta=1.00, updates=1)
  promotion: none proposed (needs mean >= 0.7 and >= 3 updates)
```

Illustrative transcript, not captured from a real run. Source: tools/cli/commands/memory-journal-cmd.js (runWrite, runReinforce) and lib/memory-journal.js (computeReward, updatePatternScore); event id and time are made up

<a id="errors"></a>
## Errors and what to do

**Messages printed by mem**

| Message | Cause | What to do |
| --- | --- | --- |
| `mem: unknown action '<x>' — expected recall \| write \| reinforce \| observe \| outcomes` | The first word is not one of the five actions. | Fix the action name. |
| `mem recall: recall: query must be a non-empty string` | `recall` was called without words to search. | Add the search words after `recall`. |
| `mem recall: Evidence ranking supports project-local lexical recall only.` | `--ranking evidence` combined with `--scope portfolio`. | Use project scope for evidence ranking. |
| `mem recall: An explicit non-empty project scope is required.` | `--ranking evidence` without `--context-scope`. | Pass `--context-scope src/auth,src/session` (1 to 30 relative paths). |
| `mem write: appendEvent: event.agent is required` | `write` without `--agent`. | Pass `--agent <name>`. |
| `mem write: appendEvent: event.outcome must be one of success\|failure\|partial\|abandoned` | Invalid `--outcome`. | Use one of the four values. |
| `mem reinforce: mem reinforce: --pattern <id> is required (the pattern heading in patterns.md)` | `reinforce` without `--pattern`. | Pass the exact `### ` heading of the pattern. |
| `mem observe: Outcome source is not an accepted task with current independently verified evidence.` | The Nexus task is not accepted, its verification did not pass, or its evidence is stale. | Finish `nexus verify` and `nexus accept` first, then observe again. |
| `mem observe: Memory heading must identify exactly one section.` | The heading is absent or appears twice in the file. | Use the exact, unique `### ` heading text. |
| `mem observe: Duplicate outcome: this task attempt already supplied a receipt.` | A receipt exists for this run, task and attempt. | Nothing to do; use `supersedes` on a later attempt if the lesson changed. |
| `mem observe: Outcome scope exceeds the accepted task scope.` | A `scope` path is outside the task’s declared scope. | Narrow `scope` to paths the task owns. |
| `... Memory writer lock is occupied. Inspect writer.lock and its owner; do not remove a live lock.` | Another process holds `.bmad/memory/writer.lock` for more than about two seconds, or a crash left it behind. | Wait for the other writer. Remove the file only when you are sure no `mem` process is running. |
| `... Memory store is full; archive it explicitly before adding records.` | A store reached 2 MiB. | Archive or trim the file by hand, then retry. |

<a id="examples"></a>
## Examples

<a id="example-cli-mem-recall"></a>
### Remember a past decision

Before touching authentication you want the agent to check what the project already decided.

**In your AI assistant**

```text
Run `bmad-plus mem recall auth strategy --json` and quote the best three matches with their source file and section.
```

**What you should get** The command prints a JSON object with `query`, `scope`, `ranking`, `count` and a `results` array sorted by score. Each result is either a `note` (with `source` such as `decisions.md`, `ref` set to the `### ` heading and the section text) or an `event` from the journal. With no match, `count` is 0 and the exit code is still 0.

<a id="example-cli-mem-journal"></a>
### Journal a result and reinforce a pattern

A change was accepted and CI is green. You want the memory to record that and nudge the pattern that guided it.

**In your AI assistant**

```text
Write a journal event for agent forge, task "Add login rate limit", outcome success, CI pass, then reinforce the pattern "Rate limit on auth routes" with acceptance true and CI pass.
```

**What you should get** `mem write` appends one line to `.bmad/memory/journal.ndjson` and prints its id. `mem reinforce` computes a reward of 1.000 (acceptance 0.3 and CI 0.2, renormalised), moves the pattern’s Elo from 1200.0 to 1216.0 on its first update, and shows a mean of 0.667. No promotion is proposed until the mean reaches 0.7 over at least 3 updates, and a proposal is only ever stored as `PROPOSED`.

<a id="example-cli-mem-observe"></a>
### Tie a lesson to accepted work

A Nexus task that adds a rate limit has been verified and accepted. You want the matching lesson to carry that evidence.

**In your AI assistant**

```text
Write the outcome file for the accepted Nexus task T-12 of run <run id>, attached to the lesson "Rate limit on auth routes" in .agents/memory/lessons.md with scope src/auth, then run `bmad-plus mem observe --input` on it and `bmad-plus mem outcomes`.
```

**What you should get** `mem observe` prints `mem observe: <receipt id> recorded; lesson causality remains unmeasured.` and appends the receipt to `.bmad/memory/outcomes.ndjson`. `mem outcomes` then prints `<receipt id>: accepted-current`. If the task is not accepted, the section is missing or ambiguous, or the scope leaves the task’s scope, `observe` refuses with the message listed in the errors table and writes nothing.

**See also**

- [memory: health report and export](https://bmad-plus.rochetta.fr/docs/reference/cli-memory/)
- [nexus: where accepted tasks come from](https://bmad-plus.rochetta.fr/docs/reference/cli-nexus/)
- [scan: index your projects](https://bmad-plus.rochetta.fr/docs/reference/cli-scan/)
- [Project layout](https://bmad-plus.rochetta.fr/docs/reference/project-layout/)
- [Troubleshooting](https://bmad-plus.rochetta.fr/docs/faq/troubleshooting/)

[BMAD+ documentation](https://bmad-plus.rochetta.fr/docs/) · [Reference](https://bmad-plus.rochetta.fr/docs/reference/)

[Source on GitHub](https://github.com/lrochetta/BMAD-PLUS)
