brain

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 2, 2026 License: MIT Imports: 14 Imported by: 0

README

Logos

When one coding agent stops, the next one continues the work. Logos is a local-first memory and continuity layer that Claude Code, Cursor, Codex and your own agents share over MCP. It runs on your machine, against a vault of markdown files you own, and uploads nothing unless you say so.

On a handoff suite built for this — 32 scenarios, nine memory systems, one machine — Logos passes 84.4% and the next best system passes 46.9%. Every real system retrieves about equally well. What separates them is whether the agent that resumes gets the current answer, or gets it sitting next to the stale one it replaced.

Claude Code  ──▶  checkpoint  ──▶  Logos  ──▶  resume  ──▶  Cursor
                                (your vault)

Memory is the product, and continuity is the proof. Chat assistants forget you the moment a session ends. Logos doesn't — and the test of that is not whether it can find an old note, it is whether an agent that has never seen your project can continue one that did.

Markdown is truth. .brain/index.db is a cache you can delete and rebuild. If this project dies, you keep a vault.

On the two names. Logos is the product — the repository, the npm packages, the MCP server hosts see. brain is the development name and stays one internally: the Go module github.com/Coder8124/brain, the brain command, BRAIN_VAULT, and .brain/. The npm wrapper installs logos and brain as the same command, so either spelling works wherever you meet it.


Install

Claude Code — two commands, and this is the version to prefer:

/plugin marketplace add Coder8124/logos
/plugin install logos@logos

The plugin is not just the MCP server. It also installs a SessionStart hook that puts the last handoff in front of the model before it does anything, which is the difference between continuity that works and continuity that works when the model remembers to ask for it. Plus a /handoff command and a skill that teaches it to check before_you_try before proposing.

One click, for the other hosts:

Add to Cursor Add to VS Code

Or one command, for everything else:

npx -y @noeton/logos setup

No Go toolchain, no clone, no build — the npm package carries a prebuilt binary for your platform (~5 MB over the wire: the platform packages are gated on os and cpu, so you fetch one of the five, not all of them).

Other ways in
# From source, if you have Go
git clone https://github.com/Coder8124/logos && cd logos
go build -o bin/brain ./cmd/brain && ./bin/brain setup

# Or a release binary — no runtime at all
# github.com/Coder8124/logos/releases

Wiring a host by hand needs no install whatsoever, because npx resolves the binary on demand:

{
  "mcpServers": {
    "logos": {
      "command": "npx",
      "args": ["-y", "@noeton/logos", "mcp", "serve"]
    }
  }
}

That config is portable between machines, which an absolute binary path is not.

setup picks a vault (~/brain unless you say otherwise), finds your local model runtime and offers to pull anything missing, runs the first index, then shows you which agents it would wire and asks before touching any of them:

$ brain setup

  vault      /Users/you/brain   (created)
  runtime    Ollama at http://localhost:11434/v1
  embedding  nomic-embed-text ✓
  model      gemma3:4b ✓

  index      0 notes, 0 edges

  hosts
    each of these will be pointed at:
      /Users/you/go/bin/brain mcp serve
      BRAIN_VAULT=/Users/you/brain

    Claude Code      →  claude mcp add --scope user
    Claude Desktop   →  ~/Library/Application Support/Claude/…
    Cursor           →  ~/.cursor/mcp.json
    Codex            →  codex mcp add

  wire 4 host(s)? [Y/n] y

    Claude Code      ✓  registered
    Claude Desktop   ✓  registered
    Cursor           ✓  registered
    Codex            ✓  registered

  checking it works
    handshake        ✓  server answered initialize
    tools            ✓  continuity tools advertised
    round trip       ✓  checkpoint written and recovered through resume
    vault            ✓  written to /Users/you/brain, and cleaned up

That last block is the point: registering a server and having a working integration are not the same thing. Setup becomes the host for one round trip — writes a checkpoint, reads it back through resume, confirms the markdown landed in the vault it just configured, then deletes it. A host pointed at the wrong vault passes a handshake perfectly while knowing nothing, and that is the failure worth catching.

brain doctor --integration re-runs it any time.

--host cursor wires exactly one; --dry-run prints the plan and writes nothing; --vault ~/notes points elsewhere; brain mcp install re-runs just the wiring. All safe to run twice — an existing entry is updated, never duplicated, other MCP servers in those files are left alone, and anything edited gets a .brain-backup beside it.

Where a host ships its own registration command (Claude Code, Codex) brain uses it, so their config format stays their problem. Only Claude Desktop and Cursor get hand-written JSON.

No model runtime is required. Every continuity tool — checkpoint, resume, note_progress, before_you_try — is markdown and SQL, and works with nothing installed. Retrieval falls back to BM25, which for code (identifiers, error strings, paths) is the right tool rather than a consolation.

A 274 MB embedding model adds paraphrase-tolerant search if you want it. The chat tiers are only for brain ask, voice and the nightly rollup — nothing an MCP host calls ever touches them, so a coding agent needs none of it. Ollama, LM Studio, Jan and Msty are auto-discovered if present.

brain doctor --probe                # which models load, and honour JSON schemas
brain index                         # re-sync after editing the vault by hand
brain ask "what did I decide about pricing?"

Want something to point it at? ./scripts/seed-demo-vault.sh builds a synthetic vault (~/vaults/kestrel) with interlocking constraints — a BOM that doesn't close, a factory missing yield, a schedule with a critical path — so you can ask hard questions that have findable answers and tell retrieval from autocomplete.

The desktop app is Wails v2:

cd app && wails dev        # or: wails build

Does it actually work?

Two benchmarks, both reproducible from this repo, both run entirely locally.

Retrieval. 96.0% recall@5 / 99.2% recall@10 on the full 500-question LongMemEval-S. Hybrid beats vector-only by 8.9 points.

Continuity. A suite built here, because nothing existing measured handoff: 32 hand-authored scenarios, nine memory systems, one machine, same embedding model throughout.

system                pass  fidelity  carry   leak  signal
brain                84.4%    85.9%   89.1%  16.7%   88.9%
mempalace            46.9%    71.9%   82.8%  58.3%   22.2%
recency-window       46.9%    68.8%   84.4%  83.3%   22.2%
full-dump            46.9%    68.8%   84.4%  83.3%   22.2%
letta                43.8%    67.2%   82.8%  83.3%   22.2%
mem0                 43.8%    67.2%   82.8%  83.3%   22.2%
vector-rag           43.8%    67.2%   82.8%  83.3%   22.2%
static-file           6.2%    22.7%   22.7%   0.0%    0.0%
none                  0.0%     6.2%    6.2%   0.0%    0.0%

Retrieval is not the differentiator — every real system carries 82–89% of the required facts. The gap is leakage (returning the superseded price next to the current one) and signal (saying this was tried, this changed, nothing on record covers that). A scenario passes only when it clears all three bars, because a system that returns the right fact and the stale one it replaced has handed the next agent a coin flip.

On the durability family — write, delete every rebuildable artifact, read again — brain scores 100% and every other system scores 0%.

It loses too: arithmetic, recency-conflict and multi-hop are 0%, and temporal ordering is 0% for every system measured — retrieval is not computation, and no amount of it turns "which came first" into an answer. Full numbers, method and caveats in docs/continuity-benchmark.md.

go run ./cmd/brain bench continuity --brain-only

Lending the memory to other agents

brain mcp serve exposes the memory over the Model Context Protocol — the same protocol Claude Desktop, Claude Code, and Cursor speak, and one any application can build on. Newline-delimited JSON-RPC 2.0 over stdio.

Which agents work today

brain setup detects and wires the first group automatically. Everything in the second group speaks MCP, so brain should work once pointed at it — but nobody has confirmed it, and "should work" is not a claim this project makes about itself.

Agent Wired by brain setup How Verified
Claude Code yes claude mcp add --scope user ✅ handshake + round trip
Codex yes codex mcp add ✅ handshake + round trip
Cursor yes merges ~/.cursor/mcp.json ✅ handshake + round trip
Claude Desktop yes merges claude_desktop_config.json ✅ handshake + round trip
Windsurf not yet manual JSON below ❓ help wanted
Cline / Roo Code not yet manual JSON below ❓ help wanted
Zed not yet manual JSON below ❓ help wanted
VS Code Copilot not yet manual JSON below ❓ help wanted
Gemini CLI not yet manual JSON below ❓ help wanted
OpenCode not yet manual JSON below ❓ help wanted
JetBrains AI not yet manual JSON below ❓ help wanted
Continue.dev not yet manual JSON below ❓ help wanted

"Verified" means brain doctor --integration passes against it: the host launches the server, completes the MCP handshake, writes a checkpoint, reads it back through resume, and the markdown lands in the vault that was configured. Anything less is registration, not integration — and a host pointed at the wrong vault passes a handshake perfectly while knowing nothing.

Adding an agent

This is the most useful contribution to the project, and it is genuinely small. A host is four fields in internal/setup/hosts.go:

{
    Name:   "Windsurf",
    Detect: func() bool { return exists(inHome(".codeium", "windsurf")) },
    Where:  func() string { return inHome(".codeium", "windsurf", "mcp_config.json") },
    Register: func(s Server) (Outcome, error) {
        return mergeJSON(inHome(".codeium", "windsurf", "mcp_config.json"), s)
    },
}

mergeJSON already handles the hazards — it parses before writing, refuses a malformed file rather than replacing it, backs up to .brain-backup, preserves every other MCP server in the file, and writes atomically. If the host ships its own registration command, prefer viaCLI so its config format stays its problem.

Then run brain doctor --integration and open a PR with the output. If it passes, the row moves up. internal/setup/setup_test.go has the fixtures.

If your host is not listed at all: brain talks plain MCP over stdio, so the manual config below works anywhere, and a report that it did is worth as much as a patch.

{
  "mcpServers": {
    "brain": {
      "command": "/absolute/path/to/bin/brain",
      "args": ["mcp", "serve"],
      "env": { "BRAIN_VAULT": "/absolute/path/to/vault" }
    }
  }
}

Both paths must be absolute. A host launches the server from a directory nobody chose, so a relative BRAIN_VAULT resolves somewhere you will never look — and brain will appear to work while knowing nothing.

No model runtime is required. Every continuity tool below — checkpoint, resume, note_progress, before_you_try — is markdown and SQL, and works with nothing installed. Retrieval falls back to BM25, which for code (identifiers, error strings, paths) is the right tool rather than a consolation. A 274 MB embedding model adds paraphrase-tolerant search if you want it.

Thirteen tools in two families:

Memory — what do you know about X. remember (returns a receipt saying whether it created a fact or corroborated one it already had), recall, list_memories, forget, memory_diff, list_projects.

Continuity — where were we. context, resume, note_progress, checkpoint, handoff, before_you_try, why.

The intercept

resume hands an arriving agent the last checkpoint. That covers the dead end from yesterday, on the project it is already working on. It does nothing for the one from March, on a project nobody mentioned, recorded by an agent that no longer exists — because nobody thinks to search for the thing they are about to suggest.

before_you_try is the other direction. The agent is about to propose something, and the tool interrupts:

$ brain tried "switch to a plastic frame to save weight"

## This has been tried

One recorded dead end already bears on "switch to a plastic frame to save weight".

- **Switching to a plastic frame — fails the drop test at 1.2m** — tried by
  claude, 3mo ago · `sessions/kestrel-one/20260521-142207-claude`

Before proposing this, say that it has been tried and what happened. If you still
think it is right, say what is different now — a dead end recorded under other
constraints is evidence, not a verdict.

It searches every dead end in the vault, across all projects, including findings left in working notes by an agent that died before it could check in. A recorded failure is evidence, never a veto, and rulings from a different project are flagged as possibly not transferring.

The mechanism is a morning's work. The two years of accumulated we tried that is not — which is the part that compounds.

Why is this code like this?

before_you_try fires on a proposal. why fires on a file — the other moment an agent is about to act on history it cannot see.

git blame answers who changed a line and when. It structurally cannot answer why, because the reasoning was in a pull request nobody kept, a thread that scrolled away, or the head of someone who left. So the same three approaches get re-attempted every eighteen months by people with no way of knowing they were attempted before.

$ brain why internal/memory/vaultstore.go

internal/memory/vaultstore.go — 1 checkpoint(s)

─── 14 Mar 2026 · claude · memory-store
    while: make the vault write durable
    ruled out:  keeping vectors in the markdown — the file stops being human-editable
    decided:    flush() returns an error now, because a memory that reached
                SQLite and not the vault reported success
    → sessions/memory-store/20260314-091120-claude

Every checkpoint already records which files were touched, right next to the decisions and dead ends. Nothing was querying it — the join existed in the data and not in the code.

Path matching is deliberately loose: an agent writes whatever path it had in hand, a person asks with whatever their shell completed, and requiring those to match exactly would mean the lookup almost never fires. vaultstore.go, ./internal/memory/vaultstore.go and an absolute path all resolve.

The claim is deliberately modest, and the output says so: this reports what was written down while the file was touched, not an explanation of the code. A decision nobody recorded is not here, and a file with no history is reported as "nothing was recorded" rather than as evidence the code is arbitrary.

The handoff

This is the thesis made mechanical. An agent works, checkpoints, and shuts down; a different agent — a different product — calls resume and continues without anyone re-explaining anything.

brain note kestrel-one "re-quoted the waveguide; no movement under 10k units"
brain checkpoint kestrel-one --agent claude --next "quote the single-mic line"
brain resume kestrel-one            # from Cursor, from Codex, from anywhere

The organising idea is working tree = SQLite, commits = vault. A running agent scribbles working notes into the cache — cheap, frequent, disposable, lost on rebuild by design. checkpoint commits that state to a markdown note in sessions/<project>/, which the indexer then embeds and edges into the graph for free. Delete .brain/ and the checkpoints survive, because the file is the record.

The field that earns its keep is "didn't work." Anyone can restate the goal; the expensive knowledge is the three approaches already ruled out, and it is exactly what dies with a session.

context(task, project, budget) assembles everything bearing on a task — the last checkpoint, uncommitted working notes, the project dossier, the actual prose of relevant notes, notes reached one hop through your own links, memories with provenance, and open commitments — spent against a token ceiling, cited by source, and honest about what it had to leave out.


Embedding it in your own agent

MCP is for hosts you don't control. If you're writing the agent yourself, import the engine directly — same vault, same files, no subprocess and no protocol.

go get github.com/Coder8124/logos@latest

The module path and the repository agree, so the proxy can resolve it. Working against a local checkout instead:

git clone https://github.com/Coder8124/logos
# then, in your go.mod:
#   require github.com/Coder8124/logos v0.0.0
#   replace github.com/Coder8124/logos => ../brain
b, err := brain.Open("/path/to/vault", brain.WithAgent("my-agent"))
if err != nil {
    log.Fatal(err)
}
defer b.Close()

// Starting a task: what did the last agent leave behind?
c, _ := b.Resume("kestrel-one")
fmt.Println(c.Render())        // drop straight into a system prompt

// About to propose something: has it already been ruled out?
approach := "re-quoting the waveguide to bring the BOM down"
if ruled, _ := b.Tried(approach, "kestrel-one"); len(ruled) > 0 {
    fmt.Println(brain.Explain(approach, ruled))
}

// Finishing: commit where you stopped. Failed is the field that earns its keep.
b.Note("kestrel-one", "re-quoted the waveguide; no movement under 10k units")
b.Checkpoint(brain.Checkpoint{
    Project: "kestrel-one",
    Failed:  []string{"re-quoting the waveguide — no movement under 10k units"},
    Next:    "quote the display driver alternatives",
})

The rest of the surface is Context, Remember/Recall/Forget, Search, Ask, History, Projects, Index, and ServeMCP if you'd rather serve the tools than call them. examples/handoff is the whole thing end to end: one agent works and stops, another opens the same vault and continues.

brain.WithoutEmbedding() skips model discovery outright, which is what you want in CI.

Everything else stays under internal/ on purpose. The exported surface is what an agent actually uses, so the retrieval, budgeting and consolidation internals can change without breaking you; the domain types are aliases for their internal definitions, which makes them part of the contract rather than a copy that drifts.


The command surface

brain setup [--vault DIR] [--yes]               connect brain to every agent here
brain mcp serve | mcp install                   serve the memory; wire up the hosts
brain ask <q> | search <q> | timeline           query what it knows
brain brief                                     what the secretary thinks you should know now
brain replay [--peek]                           what changed since you were last here
brain reflect | weekly                          stats over your memory; the Sunday review
brain voice | listen | say <text>               talk to it, hear it back (local STT/TTS)
brain name [<name>] | presence [--wake]         the ambient, named assistant
brain jot <thought>                             braindump: capture and auto-file
brain memory [add|forget|log|history|graph|diff] persistent memory and its timeline
brain projects | project <name>                 auto-detected projects and dossiers
brain loop [add|done|drop]                      open commitments
brain graph [focus] [--hops N] [--similar]      the note graph around a note
brain context <task> [--project p] [--budget n] everything bearing on a task, budgeted
brain note <project> <what you did>             record progress; uncommitted until checkpoint
brain checkpoint <project> [--handoff who]      commit where you stopped, into the vault
brain resume <project> | sessions <project>     pick up; read the checkpoint log
brain tried <approach> [--project p]            has this already been ruled out?
brain bench continuity [--brain-only]           the handoff suite, against every system installed
brain index [--watch] | rollup | review | prune cache sync, proposals, retention
brain capture [--daemon]                        pull episodic events
brain dream [--phase nrem|rem]                  nightly consolidation
brain doctor [--probe] | key set|rm <ref>       runtimes and tiers; API keys

Environment: BRAIN_VAULT (default ~/brain), BRAIN_MODEL, BRAIN_EMBED, BRAIN_REPOS (colon-separated repos to mine for commits), BRAIN_AGENT (the name recorded in the session trail, default cli).


How it works

Two tiers. Episodic memory is SQLite — app focus, URLs, files, commits, calendar, ~50k rows a day, rolled up and pruned. Semantic memory is the vault — people, projects, topics, routines, ~5 notes a day, permanent.

The pipeline is events → rollup → proposed notes → review → vault. Raw events never become markdown directly; a vault that grows 400 files a day is landfill. Nothing is written that you haven't accepted, until you raise the auto-accept threshold yourself.

Retrieval is hybrid: BM25 and vectors fused by reciprocal rank fusion, then expanded one hop through the graph — because the note your own link says is relevant is often the one whose words never match your query.

vault/
  daily/  people/  projects/  topics/  routines/  sources/
  sessions/<project>/<timestamp>-<agent>.md      # checkpoints
  memories/<kind>.md                             # what it knows about you
  .brain/                                        # index.db, config — do not sync

Everything above .brain/ is the record, including the memories:

$ brain memory add "I prefer terse replies with no preamble"
$ rm -rf $BRAIN_VAULT/.brain && brain index
+1 ~0 -0 =0 · embedded 1 · 1 notes, 0 edges, 2 memories
$ brain memory
  [1] (fact  sal 0.70 · conf █████ 0.90) I prefer terse replies with no preamble

Same ids, same confidence. memories/<kind>.md is a plain bullet list — edit a line to correct a fact, delete one to forget it, then reindex.

Model tiers run T0 embeddings (137M) through T2 synthesis (8–24B) locally; T3 is cloud, BYOK, opt-in, off by default. Extraction uses constrained decoding rather than tool-calling — small local models are unreliable at tool schemas and near-perfect with a JSON schema enforced at the sampler.


Repository

brain.go         the public API — what an embedding agent imports
examples/        runnable embeddings, starting with the handoff
cmd/brain/       the CLI — one engine, two front ends
internal/        index, memory, session, contextpack, deadend, graph, setup,
                 capture, dream, rollup, secretary, router, voice, mcpserver
chaos/           fault injection: SIGKILL mid-write, full disks, racing processes
app/             Wails v2 desktop app (menubar orb, panel, graph canvas)
bench/           Python adapters for the systems brain is scored against
docs/            the benchmark, plus per-subsystem notes
scripts/         demo vault seeding, voice-engine fetch, icon build

Tests run with go test ./.... The chaos tier is opt-in and slower:

go test -tags chaos ./chaos

It kills the binary mid-checkpoint forty times, fills a real disk image to ENOSPC, and races processes on one vault — the failures that only appear when the kernel is involved.

Further reading: CREDITS.md for prior work that shaped the ideas, and DESIGN.md / PRODUCT.md for principles, architecture and the full product surface.

Documentation

Overview

Package brain is a local-first memory and continuity layer for AI agents.

It is the same engine behind the `brain` CLI, the desktop app and the MCP server, exposed for embedding directly in your own agent. Memory lives in an Obsidian-compatible vault on disk that the user owns; nothing is uploaded.

b, err := brain.Open("/path/to/vault")
if err != nil {
	log.Fatal(err)
}
defer b.Close()

// What did the last agent — possibly a different product — leave behind?
c, _ := b.Resume("kestrel-one")
fmt.Println(c.Render())   // ready to drop into a system prompt

// Before proposing something, check nobody has already ruled it out.
if ruled, _ := b.Tried("switch to a plastic frame", "kestrel-one"); len(ruled) > 0 {
	fmt.Println(brain.Explain("switch to a plastic frame", ruled))
}

// Record progress as you go, then commit where you stopped.
b.Note("kestrel-one", "re-quoted the waveguide; no movement under 10k units")
b.Checkpoint(brain.Checkpoint{
	Project: "kestrel-one",
	Failed:  []string{"re-quoting the waveguide — no movement under 10k units"},
	Next:    "quote the display driver alternatives",
})

What this package is, and is not

This is a deliberately small facade over a much larger engine. The implementation lives under internal/ and stays there: keeping it private is what lets the retrieval, budgeting and consolidation internals change without breaking anyone. What is exported here is the surface an agent actually needs, which is roughly the same surface the MCP server exposes — that server having been the forcing function for working out what an external consumer genuinely uses.

The domain types (Memory, Checkpoint, Note, Hit, Ruling, Context) are aliases for their internal definitions rather than copies. That makes them part of this package's contract: they are stable, and changing them is a breaking change. The alternative — parallel structs and a translation layer — buys freedom nobody asked for at the cost of conversions in every call.

Models

Open discovers a local model runtime (Ollama, LM Studio, Jan, Msty) and uses it for embeddings. If none is running, everything still works: retrieval falls back to lexical and graph traversal, which needs no model at all. Pass WithoutEmbedding to skip discovery entirely — useful in tests and CI.

Index

Constants

View Source
const (
	Preference = memory.Preference
	Person     = memory.Person
	Fact       = memory.Fact
	Standing   = memory.Context
)

Memory kinds, re-exported so callers need not reach into internal packages.

Variables

This section is empty.

Functions

func Explain

func Explain(approach string, rulings []Ruling) string

Explain renders the result of Tried as prose to put in front of a model, taking the same approach string so the output can quote what was proposed. A recorded failure is evidence, not a veto, and the wording says so. An empty slice renders as an explicit "no record", which is worth showing: silence and approval are different answers.

Types

type Brain

type Brain struct {
	// contains filtered or unexported fields
}

Brain is an open vault. It is safe to keep for the life of a process and must be closed when done. Not safe for concurrent use across goroutines: the underlying SQLite handle is single-writer by design.

func Open

func Open(vaultPath string, opts ...Option) (*Brain, error)

Open loads the vault at path, creating its cache if absent.

The vault directory itself must exist; brain will not invent one, because pointing this at a typo and silently creating an empty knowledge base is a worse failure than an error.

func (*Brain) Ask

func (b *Brain) Ask(question string, k int) (string, []Hit, error)

Ask retrieves and then answers in prose, citing what it used. Requires a chat model; without one it returns an error rather than a guess.

func (*Brain) Checkpoint

func (b *Brain) Checkpoint(c Checkpoint) (string, error)

Checkpoint commits where you stopped to a markdown note in the vault and returns its slug.

Call it before finishing a session, not after. Anything omitted is lost, and the field that matters most is Failed: approaches that did not work are the expensive knowledge, and without them the next agent repeats them.

func (*Brain) Close

func (b *Brain) Close() error

Close releases the vault.

func (*Brain) Context

func (b *Brain) Context(req Request) (*Context, error)

Context assembles everything bearing on a task: where the last agent stopped, what it ruled out, uncommitted progress since, the project dossier, the prose of relevant notes, notes reached one hop through the user's own links, memories with their provenance, and open commitments — spent against a token budget and cited by source.

This is the call to make at the start of a task, in preference to Recall. Recall answers "what do you know about X"; this answers "give me what I need to do X", which is not a longer version of the same question.

func (*Brain) Embedded

func (b *Brain) Embedded() bool

Embedded reports whether a model runtime was found. When false, retrieval is lexical and graph-only — still useful, measurably weaker.

func (*Brain) Forget

func (b *Brain) Forget(id int64) error

Forget deletes a memory by id.

func (*Brain) History

func (b *Brain) History(project string, n int) ([]Checkpoint, error)

History returns a project's checkpoints, newest first.

func (*Brain) Index

func (b *Brain) Index() (SyncReport, error)

Index reconciles the vault into the cache: notes, embeddings and memories. Call it after writing files into the vault by other means, or on a watcher.

func (*Brain) Memories

func (b *Brain) Memories() ([]Memory, error)

Memories returns everything currently held.

func (*Brain) Note

func (b *Brain) Note(project, text string) error

Note records one line of progress. Cheap and meant to be called often — after a decision, a dead end, a surprising discovery. Notes stay uncommitted until Checkpoint folds them into a durable record, so use them freely rather than saving everything for the end.

func (*Brain) Notes

func (b *Brain) Notes(project string) ([]Note, error)

Notes returns a project's uncommitted progress — work that happened but was never written down properly, including anything left by an agent that died mid-task.

func (*Brain) Projects

func (b *Brain) Projects() ([]string, error)

Projects lists the projects that have at least one checkpoint.

func (*Brain) Recall

func (b *Brain) Recall(query string, k int) ([]Memory, error)

Recall retrieves what is known about the user relevant to a query.

func (*Brain) Remember

func (b *Brain) Remember(text string, kind Kind) (Receipt, error)

Remember stores something durable about the user and reports what happened: whether it created a fact or corroborated one already held. Near-identical statements reinforce rather than duplicate.

func (*Brain) Resume

func (b *Brain) Resume(project string) (*Context, error)

Resume picks up a project where the last agent left off. Equivalent to Context with a continuation task, and named separately because that is how people think about it.

func (*Brain) Search

func (b *Brain) Search(query string, k int) ([]Hit, error)

Search retrieves vault notes, fusing lexical and vector rankings.

func (*Brain) ServeMCP

func (b *Brain) ServeMCP(in io.Reader, out io.Writer) error

ServeMCP speaks the Model Context Protocol over the given streams, exposing this vault's tools to any MCP host. Use it to put your own product in front of brain's memory rather than reimplementing the tool surface.

A missing model runtime is not an error, matching Open: retrieval degrades to lexical and every continuity tool works untouched. Refusing to serve would have contradicted the rest of this API, which is built to keep working on a machine with no models on it.

It blocks until the input stream closes.

func (*Brain) Tried

func (b *Brain) Tried(approach, project string) ([]Ruling, error)

Tried reports whether an approach has already been ruled out, searching every dead end recorded across the whole vault — other projects included, and findings left in working notes by agents that no longer exist.

Call this before proposing a solution, especially when it seems obvious: obvious approaches are the ones already attempted. Pass the project being worked on so rulings from elsewhere can be flagged as possibly not transferring. An empty result means no record, which is not the same as approval.

func (*Brain) Vault

func (b *Brain) Vault() string

Vault is the path this Brain was opened on.

func (*Brain) Why

func (b *Brain) Why(file string, limit int) ([]Mention, error)

Why reports what was being decided when a file was worked on: the decisions taken and the approaches ruled out while it was being touched, newest first.

The complement to `git blame`, which answers who and when and cannot answer why. Matching on the path is deliberately loose — an agent records whatever path it had in hand and a caller asks with whatever they have — so a bare filename or a partial path both resolve.

It reads markdown from the vault, so it needs no model and no index. limit of 0 means every match.

type Checkpoint

type Checkpoint = session.Checkpoint

Checkpoint is where an agent stopped, written well enough that a different agent can start. Failed is the field that earns its keep.

type Context

type Context = contextpack.Pack

Context is everything bearing on a task, budgeted. Call Render for the markdown to put in a model's context window.

type Hit

type Hit = index.Hit

Hit is a retrieved vault note, with its provenance.

type Kind

type Kind = memory.Kind

Kind classifies a memory: Preference, Person, Fact or Context.

type Memory

type Memory = memory.Memory

Memory is one durable thing the store knows about the user.

type Mention

type Mention = session.Mention

Mention is a checkpoint that touched a file, and what was being worked out at the time. Returned by Why.

type Note

type Note = session.Note

Note is one line of uncommitted progress.

type Option

type Option func(*config)

An Option configures Open.

func WithAgent

func WithAgent(name string) Option

WithAgent sets the name recorded against notes and checkpoints — "claude", "cursor", your own product's name. A handoff is meaningless without knowing who is handing off, so this is worth setting.

func WithEmbeddingModel

func WithEmbeddingModel(name string) Option

WithEmbeddingModel names the embedding model instead of taking the detected default.

func WithoutEmbedding

func WithoutEmbedding() Option

WithoutEmbedding skips model discovery. Retrieval then uses lexical search and graph traversal only — no model process required, which is what you want in tests and CI.

type Receipt

type Receipt = memory.Receipt

Receipt reports what a write actually did — created a fact, or corroborated one already held.

type Request

type Request struct {
	// Task is what you are about to do, in a sentence. Required.
	Task string
	// Project narrows to one piece of work. Optional — when empty, the task
	// text is matched against known projects.
	Project string
	// Budget is the approximate token ceiling. Zero means 4000.
	Budget int
}

A Request describes what you are about to do. Task is the important field: "continue the MCP implementation" retrieves differently from a project name alone, because it says which corner of the project matters right now.

type Ruling

type Ruling = deadend.Ruling

Ruling is something already tried that did not work.

type SyncReport

type SyncReport = index.SyncReport

SyncReport counts what an Index call changed.

Directories

Path Synopsis
Package main is the Wails desktop app.
Package main is the Wails desktop app.
cmd
brain command
Command brain is the CLI front end.
Command brain is the CLI front end.
examples
handoff command
Command handoff is the smallest useful embedding of brain: two agents, one vault, no shared process.
Command handoff is the smallest useful embedding of brain: two agents, one vault, no shared process.
internal
agent
Package agent is the conversational assistant.
Package agent is the conversational assistant.
capture
Package capture is the episodic tier: sampling, coalescing, storage and retention.
Package capture is the episodic tier: sampling, coalescing, storage and retention.
capture/sources
Package sources pulls episodic events off the machine.
Package sources pulls episodic events off the machine.
contextpack
Package contextpack assembles everything needed to work on something into one bundle.
Package contextpack assembles everything needed to work on something into one bundle.
deadend
Package deadend answers one question: has this been tried before?
Package deadend answers one question: has this been tried before?
dream
Package dream is the nightly consolidation pass — brain sleeping on the day.
Package dream is the nightly consolidation pass — brain sleeping on the day.
eval
Package eval is a benchmark for agentic memory and handoff.
Package eval is a benchmark for agentic memory and handoff.
eval/adapters
Package adapters holds one implementation of eval.Adapter per memory system under test.
Package adapters holds one implementation of eval.Adapter per memory system under test.
event
Package event defines the episodic record shared by capture and its sources.
Package event defines the episodic record shared by capture and its sources.
flavor
Package flavor holds the assistant's identity and how present it makes itself.
Package flavor holds the assistant's identity and how present it makes itself.
gitstate
Package gitstate reads what the repository was, so a checkpoint does not have to rely on being told.
Package gitstate reads what the repository was, so a checkpoint does not have to rely on being told.
graph
Package graph builds the memory graph the widget renders.
Package graph builds the memory graph the widget renders.
health
Package health answers "is this actually working", and is careful about the difference between a thing that is fine and a thing nobody looked at.
Package health answers "is this actually working", and is careful about the difference between a thing that is fine and a thing nobody looked at.
index
Package index is the rebuildable cache.
Package index is the rebuildable cache.
mcpserver
Package mcpserver exposes brain's memory layer as an MCP server.
Package mcpserver exposes brain's memory layer as an MCP server.
memory
Package memory is the assistant's persistent memory.
Package memory is the assistant's persistent memory.
presence
Package presence is the Secretary as a presence — the ambient, conversational layer that speaks up about your calendar, your agenda, and the things you meant to remember but never quite do.
Package presence is the Secretary as a presence — the ambient, conversational layer that speaks up about your calendar, your agenda, and the things you meant to remember but never quite do.
project
Package project auto-detects the pieces of work a life is organised around and assembles a dossier for each — its notes, the people involved, the files it touches, its goals, and recent progress — without the user filing anything.
Package project auto-detects the pieces of work a life is organised around and assembles a dossier for each — its notes, the people involved, the files it touches, its goals, and recent progress — without the user filing anything.
provider
Package provider is one client for every model runtime.
Package provider is one client for every model runtime.
reflection
Package reflection is descriptive statistics over long-term memory.
Package reflection is descriptive statistics over long-term memory.
replay
Package replay is "catch me up since I've been away."
Package replay is "catch me up since I've been away."
rollup
Package rollup turns episodic events into proposed vault notes.
Package rollup turns episodic events into proposed vault notes.
router
Package router decides which model does which job.
Package router decides which model does which job.
routine
Package routine finds recurring structure in the episodic tier.
Package routine finds recurring structure in the episodic tier.
secretary
Package secretary turns what brain knows into what brain says first.
Package secretary turns what brain knows into what brain says first.
session
Package session records what an agent was doing, so a different agent can pick it up.
Package session records what an agent was doing, so a different agent can pick it up.
setup
Package setup connects brain to the agents that will use it.
Package setup connects brain to the agents that will use it.
textmatch
Package textmatch is the small lexical toolkit two subsystems needed at once.
Package textmatch is the small lexical toolkit two subsystems needed at once.
vault
Package vault reads and writes notes in the Obsidian vault.
Package vault reads and writes notes in the Obsidian vault.
voice
Package voice gives the assistant ears and a mouth, locally.
Package voice gives the assistant ears and a mouth, locally.
when
Package when resolves the time expressions people put in questions.
Package when resolves the time expressions people put in questions.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL