Brain · Decisions

Keep the reasoning behind a call

The decision log is one markdown file in your repository: .claude/brain/decisions.md. RepoOps renders it, proposes entries for it, and loads the ones your next session is likely to need. Nothing the machine proposes reaches the file without an accept, and nothing it declines is deleted.

For: the engineer who has to reopen a settled question, and the owner who decides what the nightly pass may write

What it does, and why it helps

The Decisions tab is a render of .claude/brain/decisions.md, done on each request, so editing the markdown is the whole update. An entry reaches the file three ways. You write one and it lands through a pull request like any other file. The nightly reflector reads the last seven days of commits and session entries and proposes one, which you accept on the Brain reflection tab. Or an MCP client calls propose_brain_entry, which holds the entry for approval and writes an attestation row. Every accept goes through one function, and it inserts the new entry after the header block and the --- separator, so the file stays newest first.

The nightly pass also drains its own queue, under caps. High-confidence typed cards accept up to twenty a run, medium up to eight, low never. A card nobody has decided on after fourteen days is bulk-rejected, which writes the full body to proposed/rejected/ rather than removing it. A rejection you made by hand is never overruled by the machine. The only structure anything reads back out of the file is the ## heading: it is the title the duplicate check compares, and the decision kind in taxonomy.json carries no template and no authoring skill.

The pain. A call gets made, shipped and forgotten. Six months later the reasoning is in a merged pull request nobody reopens, so the question is argued again and the second answer is different.

The point of view. A decision log is worth reading only if you can tell who wrote each line. So the machine proposes rather than writes, every accepted entry is stamped with the tier that took it, and every card the machine declines keeps its body on disk.

What gets easier. Finding the call. The SessionStart briefing loads the top entries by file overlap and recency into the next session. Brain links shows what references the file. Decision diff surfaces pairs across repositories that look like opposites.

When it helps. A repository whose brain has a decisions.md, on a machine that runs the capture daemon if you want the nightly proposals, and an ANTHROPIC_API_KEY if you want the reflector to synthesize them.

Its limits. It is prose. Nothing validates an entry's shape, and the kind carries no template. The detector is five patterns over active session rows, so a decision phrased any other way is not proposed. An entry in the log is not evidence that it is still the answer: Decision diff produces candidates for a person to judge, not a verdict.

Understand it in 30 seconds

30.1 s, captions on. Narration: Microsoft Zira Desktop (provisional voice; an approved narration source is pending).Transcript
Read the narration
  1. 0:00 Six months on, nobody remembers why.
  2. 0:03 The reasoning died in a merge.
  3. 0:06 A log is trustworthy only if nothing writes to it unseen.
  4. 0:10 Machine entries arrive as cards.
  5. 0:13 High and medium cards drain nightly, capped and logged.
  6. 0:16 A card nobody decides is archived, never deleted, and your rejection stands.
  7. 0:23 Read the call, then the reasoning.
  8. 0:25 The log says who wrote each line.

Synthetic example. Read the guide

Where to find it

Where to find it

  • Desktop: localhost:4000. It has no sidebar row: open it from the palette, or go straight to its address.
  • Hosted: repoops.ai/team/docs/decisions.md. It has no sidebar row: open it from the search box, or go straight to its address.
  • Keyboard: ⌘ K, then type “Decisions”.

When to use it

A settled question comes back up

Situation. Someone proposes rebuilding a path that was decided months ago. Nobody in the room was in that discussion.

What you do. Open Memory, then Brain library, and read decisions.md, or open the file in your editor. Follow it to Relationships, under All tools on Memory, to see which sessions and pull requests reference it.

What you see. The entry, at its date, with whatever reasoning the author wrote. Brain links lists inbound and outbound links across the brain root, pull-requests/ and sessions/, and says so when there are none.

What it establishes. You know what was decided and when. Whether it still holds is a judgement you make; the log records the call, not its continued correctness.

The nightly pass proposes a decision you did not write

Situation. The 02:00 reflector read the week's commits and sessions, and the detector matched a turn that carried an explicit decision tag.

What you do. Open Brain reflection. Cards are grouped by file and sorted new first, then by confidence. Press Accept, Edit or Reject. Accept all high-confidence asks you to type the repository id first.

What you see. Each card shows its confidence badge, its signal line, and its status pill once decided. A reject moves the body to proposed/rejected/ and records the id. Duplicate decisions on the same tab lists entry pairs whose tokens overlap by seventy percent or more.

What it establishes. Accepted text lands in decisions.md, which your agents read as instructions. That is why the bulk accept asks for the repository id and why low confidence never drains on its own.

Two repositories reached opposite conclusions

Situation. Your account tracks several repositories and their decision logs disagree about the same topic.

What you do. Open Decision diff. It reads the account rollup that projects each repository's dated entries into decisions-rollup.md, then pairs entries with high token overlap where one side carries a negation.

What you see. Candidate pairs with the two headings and their repositories. The match is token overlap plus negation polarity, with no model call, so it is a shortlist rather than a finding.

What it establishes. You have the pairs worth reading. Reconciling them is a new decision entry in whichever log should carry the account-wide answer.

Before you start

Supported versions
RepoOps desktop v0.3.1, the release this guide was read against. A repository with no .claude/brain/decisions.md renders the tab's registered zero state instead of a log.
Where it runs
Local: Memory, then Brain library, where decisions.md is listed as a decision, rendered from the file on each request. Hosted: repoops.ai/team/docs/decisions.md, rendered from your team's published brain snapshot, redacted and scoped to the repositories you may see.
Permissions
Writing the file is whatever your checkout allows; there is no in-app editor for it. Accepting a proposal is a click on this machine. Hosted reads are session-authed, the team comes from your membership rather than a parameter, and a scoped member sees only their own repositories.
Connections
ANTHROPIC_API_KEY on this machine for the reflector, which makes one call per knowledge file per run. Brain snapshot publishing turned on and a bound device if the team page should show the log.
Plan
No plan gate on the local file or the tab. Publishing a brain snapshot needs a paid plan: the ingest route refuses below Solo Hosted with HTTP 402 and stores nothing.

Configure it

  1. Write the file.

    Entries live in .claude/brain/decisions.md, newest first, one per `##` heading. There is no template and no authoring skill, so the shape of an entry is your convention. The heading is the part the tooling reads: it is the title the duplicate check and the accept path compare.

  2. Decide whether the nightly pass runs at all.

    Settings, then Nightly brain dreaming: Run the nightly dream pass. It is on by default. REPOOPS_BRAIN_DREAM=0 in this server's environment overrides the toggle and the panel says so, which is a different state from the toggle being off.

  3. Decide what that pass may accept on its own.

    By default it accepts high-confidence typed cards up to twenty a run and medium up to eight. REPOOPS_BRAIN_AUTO_DRAIN_OFF=1 stops it accepting anything, and the two caps are separate keys so a busy high night cannot spend the medium budget.

  4. Decide how long an undecided card waits.

    The same pass bulk-rejects typed cards older than fourteen days, up to forty a run, and archives each body under proposed/rejected/. REPOOPS_BRAIN_STALE_REJECT_OFF=1 leaves them on the queue instead.

  5. Review the rest by hand.

    Brain reflection carries Reflect now, Accept, Edit, Reject and Accept all high-confidence. The bulk accept asks you to type the repository id, because the text it appends is read by your agents as instructions.

  6. Set how many entries a new session loads.

    Session briefing, the Session-load depth (top-N errors/decisions) field, default 5 and clamped between 0 and 50. The SessionStart hook ranks entries by open-file overlap at weight 0.7 and recency at weight 0.3, on a sixty-day half-life.

  7. Publish it to the team, if the team should read it.

    Settings, then What this machine publishes to your team, then Brain snapshot. It is off by default, needs a bound device, and sends every top-level brain markdown file redacted at egress. Turning it on is what fills repoops.ai/team/docs/decisions.md.

SettingWhereA sensible choiceWhy it matters
brain.dream.autoSettings, Nightly brain dreaming, Run the nightly dream passon (the default)The 02:00 pass is what writes tonight's proposals; it is also the heaviest nightly job on the machine.
REPOOPS_BRAIN_DREAMthe data directory's .envunset0 hard-disables the pass and overrides the Settings toggle, which the panel reports rather than showing a plain off.
REPOOPS_BRAIN_AUTO_DRAIN_OFFthe data directory's .envunset1 means nothing is accepted without a click; every card waits on Brain reflection.
REPOOPS_BRAIN_AUTO_DRAIN_CAPthe data directory's .env20 (the default)The most new high-confidence entries one run may write. An idempotent re-accept spends no slot.
REPOOPS_BRAIN_MEDIUM_DRAIN_CAPthe data directory's .env8 (the default)Medium has a softer bar, so it drains at a smaller cap and a bad night is easier to spot.
REPOOPS_BRAIN_STALE_PROPOSAL_DAYSthe data directory's .env14 (the default)How old an undecided typed card gets before the nightly sweep rejects it unread. The body is archived, so the card can still be accepted later.
REPOOPS_BRAIN_STALE_REJECT_CAPthe data directory's .env40 (the default)Bounds one night's sweep so a backlog drains over several nights and a wrong setting is noticed first.
REPOOPS_BRAIN_STALE_REJECT_OFFthe data directory's .envunset1 leaves old cards on the queue. Only cards whose status is new are ever swept.
REPOOPS_BRAIN_PRODUCE_CAPthe data directory's .env10 (the default)The most candidates one producer writes per night per kind. Keep it at or below the nightly drain rate or the queue grows whatever the drain policy says.
briefingDepthSession briefing, Session-load depth (top-N errors/decisions)5 (the default)How many decisions and errors the next session loads. Values are clamped between 0 and 50; 0 is a real answer.
brainpublish.enabledSettings, What this machine publishes to your team, Brain snapshotoff until the team should read the logThe one switch behind the hosted copy. Off means the log never leaves the machine.
ⓘ
To stop or undo
Four independent levers: untick Run the nightly dream pass to stop proposals being written; set REPOOPS_BRAIN_AUTO_DRAIN_OFF=1 so nothing is accepted without a click; set REPOOPS_BRAIN_STALE_REJECT_OFF=1 so nothing is rejected without one; turn Brain snapshot off to stop the team copy. Removing an entry that is already in the log is a hand edit to decisions.md, because no route deletes one.

What you should see

The normal night

Configuration. Dreaming on, no drain flags set, ANTHROPIC_API_KEY present, a repository with recent commits and session entries.

Expect. The 02:00 pass writes a dated proposals file into .claude/brain/proposed/. High and medium typed cards accept into decisions.md up to their caps. Low confidence and the untyped snapshots stay on the queue.

Verify. The new entry sits at the top of decisions.md, above the first existing one. Its id is on the accepted ledger with auto true and a reason naming the tier. A row is appended to proposed/drain-runs.jsonl on every run, including the nights that accept nothing.

No key, or nothing to propose

Configuration. Same, with no ANTHROPIC_API_KEY on this machine, or a week with no commits and no session entries.

Expect. Reflect now answers with an error saying no BYOK Anthropic key is configured. With a key but no signals, the pass writes no proposals. Either way decisions.md is unchanged.

Verify. The tab still renders the existing log. No proposals file exists for that date. The drain run row for the night reads outcome ok with nothing accepted, which is a different fact from no row at all.

The hosted copy is short

Configuration. Brain snapshot publishing on, a bound device, a paid plan, and a brain whose files together exceed the snapshot cap.

Expect. The publisher cuts the largest files to a shared ceiling and appends a line saying so, rather than dropping the tail. The hosted page leads with a Partial file notice and the number of bytes not published.

Verify. repoops.ai/team/docs/decisions.md shows the notice above the prose. The full text is on the desktop. Caps are 1 MiB per file, 5 MiB per snapshot and 500 files, and the server rejects the whole snapshot if one is broken.

Data and cost

What is captured
The log itself, .claude/brain/decisions.md, a tracked file in your repository. Beside it: the dated proposals under .claude/brain/proposed/, the accepted, rejected and duplicate ledgers keyed by a hash of the entry body, the archived bodies under proposed/rejected/, and one row per nightly drain tick in proposed/drain-runs.jsonl.
Who can see it
Local by default. With Brain snapshot publishing on and a bound device, every top-level brain markdown file is redacted at egress and sent to the team store, keyed by device binding and repository. Hosted readers see it through their team membership, narrowed by per-repository scope; a scope that resolves to nothing returns the empty state rather than another team's file.
How long it is kept
None on the log. Nothing trims decisions.md and no purge route exists, so it grows; this repository's own copy was 526 KB at the read. A pending proposal is bulk-rejected after fourteen days and archived, not deleted. Hosted rows are replaced per publish: version N upserts every file, then rows below N for that device and repository are deleted.
What leaves the machine
The reflector makes one call to Anthropic per knowledge file per run on your own key. Decisions run at the synthesize tier, which is the Sonnet model in lib/llm-router.mjs, capped at 1500 response tokens. The brain snapshot is the only other egress, and only with publishing on.
What it costs
The reflector's five calls a run, on your key, at the tier each file is mapped to. Reading the tab, accepting a card and the nightly drain make no model call at all: the detector, the duplicate check and the cross-repository comparison are token overlap and pattern matching.

When the result differs

SymptomLikely causeNext action
The tab shows a zero state instead of a log.That repository's brain has no decisions.md.Record your first decision in the brain's decisions file. It renders on the next request.
Reflect now reports no BYOK Anthropic key configured.ANTHROPIC_API_KEY is not set on this machine.Add it to the data directory's .env and restart the app.
Cards pile up on Brain reflection and nothing drains.REPOOPS_BRAIN_AUTO_DRAIN_OFF is set, or the cards are low confidence or untyped snapshots, which never auto-accept.Clear the flag, or decide them by hand. Accept all high-confidence takes the whole high tier for the visible date.
A card you meant to keep is no longer on the queue.The stale sweep rejected it after fourteen days.Its full body is under proposed/rejected/. Accept it again, or raise REPOOPS_BRAIN_STALE_PROPOSAL_DAYS.
Brain reflection lists a pair under Duplicate decisions.Two entries share at least seventy percent of their tokens.Read the pair and merge them by hand. Nothing rewrites the file for you.
The hosted page says no snapshot for this file yet.Brain snapshot publishing is off, the device is not bound, or the team is below a paid plan and the ingest returned 402.Turn on Brain snapshot in Settings, bind the device, and check the plan.
The hosted page leads with Partial file.The brain is larger than the snapshot cap, so the publisher cut this file to the shared ceiling.Read the full text in the desktop app. The notice names how many bytes were not published.
Disable
Untick Run the nightly dream pass, or set REPOOPS_BRAIN_DREAM=0 for a machine-wide stop the toggle cannot undo. The three drain flags are separate: one stops accepts, one stops the stale sweep, one bounds inflow. Turning Brain snapshot off stops the team copy.
Roll back
Not provided. RepoOps does not revert an accepted entry. decisions.md is a tracked file, so revert it in git. Before an accept, Reject is the only in-loop reversal, and it archives the body rather than discarding it.
Revoke access
Hosted reads follow team membership and per-repository scope, so removing a member or narrowing their repositories is the revocation. Disconnect in the desktop app forgets the binding and revokes the device token on the server.
Delete
Not provided. No route deletes an entry; the file is .claude/brain/decisions.md and you edit it. A rejected proposal's body stays under .claude/brain/proposed/rejected/. On the hosted side, a publish deletes that device and repository's rows below the new version, so republishing a brain that no longer holds the file removes it there.

Maintenance evidence

Feature id
decisions (spine leaf decisions)
Owner
Brain reflection and review-inbox program (the reflector PR-A to PR-C, the K2.F2 decision detector, and the 2026-08-16 drain-policy decision). Guide: LDG-0717.
Supported product version
RepoOps v0.3.1
Last verified
2026-09-15, read against origin/main at 52366bb6d; labels read from the served tab source. The Decisions tab carries no controls of its own, so its labels come from lib/zero-states.mjs and lib/workspace-prose.mjs, and the controls quoted here were read in public/brain-reflection.html, public/settings.html and public/session-briefing.html. Caps and defaults read from lib/brain-acceptor.mjs, lib/brain-drain-policy.mjs and lib/brain-publisher.mjs, and cross-checked against the rows in .claude/brain/config.md.
Example fixtures
No fixture file; the cases are inline in lib/decision-detector.test.mjs (the patterns, the per-session cap, the rendered body), lib/brain-acceptor.test.mjs (which writes its own decisions.md and exercises the insertion point, the id and the title duplicate), lib/brain-drain-policy.test.mjs (the caps and the stale sweep), lib/brain-cleanup.test.mjs (the duplicate pairs) and lib/routes/brain-proposals.test.mjs.
Source references
lib/canonical-spine.json, lib/canonical-tabs.mjs, lib/routes/mirror-files.mjs, lib/md-renderer.mjs, lib/brain-reflector.mjs, lib/decision-detector.mjs, lib/brain-acceptor.mjs, lib/brain-drain-policy.mjs, lib/brain-cron.mjs, lib/brain-cleanup.mjs, lib/brain-mcp-write.mjs, lib/brain-publisher.mjs, lib/brain/session-briefing.mjs, lib/brain/account-rollup.mjs, lib/brain/decision-diff.mjs, public/brain-reflection.html, public/settings.html, public/session-briefing.html
Documentation review
Independent review requested on the slice pull request; not yet recorded.
Video review
Narrated story rendered and published 2026-09-26 (render 0bebddd03393, LDG-1012) with the breadcrumb Memory, checked against main at b0bb02812. Six frames, the captions and the transcript were reviewed by the authoring agent, not an independent reviewer; the audio was not listened to by a person. Narration is the provisional Windows voice until LDG-0721.

Last updated