Repository navigation
Brain
bin/brain is a local list of what went wrong and is not fixed yet. It is one sqlite file, ${LEAN_BRAIN_DB:-~/.local/share/lean/brain.db}, shared by every session on the machine. Nothing leaves the machine. Output is plain text, one line per item.
bin/brain --self-testState that changes has to survive a context compaction. Test failures, flaky classes, deferred minors, open questions, blockers and running agents all have a status that moves. A markdown ledger is a poor place for that. So brain holds the state, and the markdown ledgers keep rulings only: decisions with the cost if wrong, task complete lines and the person's decisions. A ledger points at open work with one line:
open items: brain list --project X --status open
Memory files keep standing preferences. Run logs are scratch and can expire once their failures are in brain.
Every item has a project, a kind and a ref. Kinds in use:
| Kind | What it holds |
|---|---|
test-fail |
A failing test class, written by test-phase. |
flaky |
A class that failed, then passed on rerun. |
minor |
A deferred fix. |
question |
Something the person must answer. |
ticket |
An unfiled or filed ticket. |
security |
A security finding. |
pending |
The next step, so it survives a compaction. |
blocker |
Waiting on the person, or a denied action that must not be worked around. |
agent |
A running subagent. Put the id, task and worktree in the title or body. Close it when it reports back. |
Other kinds are allowed.
bin/brain add --project app --kind minor --ref OrderTests.Rounding --title "rounding in totals" \
--severity minor --body "seen in review, not blocking"
bin/brain list --open
bin/brain list --project app --kind test-fail --tag db
bin/brain show 12
bin/brain close 12 --resolution fixed --commit abc1234 --note "fixed in abc1234"
bin/brain close 13 --wontfix --resolution not-a-bug
bin/brain reopen 13--body-file F reads a body from a file, and --body-file - reads it from stdin.
Values brain accepts:
| Field | Values |
|---|---|
| Status |
open, closed, wontfix
|
| Resolution |
fixed, flaky, not-a-bug, duplicate, answered, filed
|
| Severity |
critical, important, minor, info
|
| Phase |
code, test, fix, review
|
| Source |
test-phase, agent, review, user
|
| Model |
haiku, sonnet, opus, or empty |
A close note is appended to the body as closed: NOTE. Closing an item that is not open is an error. Reopening refuses when an open item with the same project, kind and ref already exists.
Adding an open item with the same project, kind and ref does not make a new row. It raises occurrences, moves last_seen, merges tags, and keeps any field the repeat leaves empty. A failure seen in ten runs is one line. A closed item never absorbs a new sighting, so a failure that comes back after a fix is a new item.
bin/brain resume [--project P] [--max N]resume prints the open items of one project as a short digest: blockers, agents, queued and running test jobs, pending, questions, then the rest, newest first, titles only. At most --max lines (default 40). The project defaults to the main repository's name in the current directory, so a worktree and its repository are one project. It prints nothing and exits 0 when there is no database or nothing is open.
The SessionStart hook hooks/brain-resume.py runs it on startup and after a compaction and adds the digest to the session's context, with a reminder not to work around a blocker. LEAN_BRAIN_RESUME=off turns it off. It never fails the session. See Hooks.
A question is an item of kind question. The title is the question. The body holds the options and a recommendation. File it and end the turn. Do not wait in the session.
bin/brain add --project app --kind question --ref port --title "Which port for the API?" \
--body "Options: 8080 or 5000. I recommend 8080."Brain stores the Claude session that filed the item and its folder. --session and --session-cwd default to $LEAN_SESSION_ID and $LEAN_SESSION_CWD. The session-env hook (hooks/session-env.py) sets both:
- SessionStart writes the two variables to
$CLAUDE_ENV_FILEand runsbrain session start ID --cwd DIR, so the session is recorded as open. - SessionEnd runs
brain session end ID. - UserPromptSubmit runs
brain answers --session IDand adds any new answers to the prompt's context.
brain session status ID prints open DIR, ended DIR or unknown. A tool that resumes a session can use that to avoid starting a second copy of a live one.
To answer, close the question as answered with the answer as the note:
bin/brain close 21 --resolution answered --note "8080"brain answers --session ID prints #21 Which port for the API?: 8080 for each answered question that session filed and has not had yet, then marks it delivered, so an answer arrives once. close --delivered marks it delivered at once, for when the answer already reached the session. The Lean Brain VS Code extension in vscode/ does this from an answer box and resumes an ended session with the answer. See its README.
LEAN_SESSION_ENV=off turns the session-env hook off. A session id takes letters, digits and dashes only.
bin/brain stats # counts by kind and status, open by project, median time to close, suites, slowest runs
bin/brain stats --json
bin/brain export --format md --project app --status open
bin/brain export --format jsonstats also reports, per test project, the run count, flaky items, flaky rate, mean lane wait and mean duration. Runs come from test-phase (brain run-add).
Never put secrets, tokens or passwords in brain. test-phase masks test output before it reaches brain: password= and pwd= values, api key values, Bearer tokens and JWT-shaped strings (eyJ...) become ***. Masking is a safety net for test output. It does not make it safe to paste a secret into a body yourself.
The orchestrator dispatches a subagent and files it:
bin/brain add --project app --kind agent --ref reviewer-1 \
--title "reviewer-1: review PR 42 in worktree /tmp/wt-42"The context compacts. The SessionStart hook prints the digest, and the line #31 agent reviewer-1: review PR 42 ... is still there. The agent reports back:
bin/brain close 31 --resolution fixed --note "reported, two findings"The review needs a decision, so the orchestrator files a question and ends the turn:
bin/brain add --project app --kind question --ref merge-order \
--title "Merge PR 42 before PR 43?" --body "Options: yes or no. I recommend yes, 43 depends on it."The person answers later with brain close 32 --resolution answered --note "yes". The next prompt in that session carries #32 Merge PR 42 before PR 43?: yes.
The same database holds the test queue. Sessions add jobs with brain queue add and end the turn, and one bin/test-phase drains them. Never write a sleep or pgrep loop to wait for it. See Test Queue.
The file has a schema version (table meta) that is migrated forward on open. A database written by a newer brain is refused, not guessed at.
Start
The method
- 4-4a. Scripts, not instructions
- 5-6. Rework and concurrency
- 14a-14h. Field notes from parallel agents
Brain and the test queue
How the plugin runs it
- Shaping a Ticket
- Models and the Cascade
- Adversarial Review
- Review Rules
- Holdout Check
- Measuring a Batch
- Retro
Reference