Skip to main content

Context engineering for AI agents — persistent memory, knowledge graph, affect tracking, and MCP server. Single SQLite file, zero LLM cost.

Project description

brainctl

Your AI agent forgets everything between sessions. brainctl fixes that.

One SQLite file gives your agent persistent memory — what it learned, who it talked to, what decisions were made, and why. No server. No API keys. No LLM calls.

from agentmemory import Brain

brain = Brain(agent_id="my-agent")

# Start of session — get full context in one call
context = brain.orient(project="api-v2")
# → {'handoff': {...}, 'recent_events': [...], 'triggers': [...], 'memories': [...]}

# During work
brain.remember("API rate-limits at 100 req/15s", category="integration")
brain.decide("Use Retry-After for backoff", "Server controls timing", project="api-v2")
brain.entity("RateLimitAPI", "service", observations=["100 req/15s", "Retry-After header"])

# End of session — preserve state for next agent
brain.wrap_up("Documented rate limiting, auth module complete", project="api-v2")

Next session, a different agent (or the same one) picks up exactly where you left off.

Install

pip install brainctl

That's it. No dependencies beyond Python 3.11+ and SQLite (built-in). Optional extras:

pip install brainctl[mcp]         # MCP server for Claude Desktop / VS Code
pip install brainctl[vec]         # vector similarity search (sqlite-vec + Ollama)
pip install brainctl[all]         # everything

Upgrading

Fresh installs: nothing to do. pip install brainctl and your first Brain() call creates a brain.db with the full current schema.

Upgrading an existing brain.db: brainctl tracks schema migrations in a schema_versions table. After upgrading:

cp $BRAIN_DB $BRAIN_DB.pre-upgrade     # always back up first
brainctl doctor                         # diagnose migration state
brainctl migrate                        # apply anything pending

If brainctl doctor reports everything green, you're done.

Predating the tracker — "virgin tracker + schema drift"

If your brain.db existed before the migration tracking framework was introduced, schema_versions will be empty but your schema already has the effects of many migrations. Running brainctl migrate blindly in that state will crash on the first ALTER TABLE ADD COLUMN that collides with an existing column — SQLite has no IF NOT EXISTS for column adds.

brainctl doctor detects this state and prints:

  migrations: virgin tracker + 5 ad-hoc schema hits — DANGEROUS to run `brainctl migrate` directly
    1. brainctl migrate --status-verbose   (see which migrations are truly pending)
    2. apply truly-pending ones manually via sqlite3
    3. brainctl migrate --mark-applied-up-to N (backfill the rest)
    4. brainctl migrate   (run anything above N)

Full recovery workflow:

# 1. Back up. Always.
cp $BRAIN_DB $BRAIN_DB.pre-migrate

# 2. Get a per-migration heuristic report.
#    Each migration is classified as:
#      likely-applied → all expected columns/tables exist
#      partial        → some DDL applied, some missing (actual drift)
#      pending        → none of its DDL exists (genuinely needs to run)
#      unknown        → no introspectable DDL (UPDATE-only or DROP-only)
brainctl migrate --status-verbose

# 3. For each migration in 'pending' or 'partial', apply it manually.
#    This is the safe path because you see exactly what each statement does.
sqlite3 $BRAIN_DB < db/migrations/024_confidence_alpha_beta_wiring.sql
sqlite3 $BRAIN_DB < db/migrations/028_memory_quarantine.sql
# ... etc

# 4. Backfill the tracker so future `brainctl migrate` runs skip
#    what's already applied. Pick N = highest version you've verified.
brainctl migrate --mark-applied-up-to 31

# 5. Run anything above N (e.g. migration 032 drops dead tables)
brainctl migrate

--mark-applied-up-to N writes rows to schema_versions with a (backfilled) suffix on the name so you can tell them apart from "really ran" rows. It refuses to go below the current high-water mark (guards against rewriting tracker state you've already committed to).

Rollback: if a migration run breaks something, cp $BRAIN_DB.pre-migrate $BRAIN_DB gets you back. brain.db is a single SQLite file — no out-of-band state to worry about.

Quick Start

Python API

from agentmemory import Brain

brain = Brain()                    # creates ~/agentmemory/db/brain.db automatically

brain.remember("User prefers dark mode", category="preference")
brain.search("dark mode")          # FTS5 full-text search with stemming

brain.entity("Alice", "person", observations=["Engineer", "Likes Python"])
brain.relate("Alice", "works_at", "Acme")

brain.log("Deployed v2.0", event_type="result", project="myproject")
brain.decide("Keep JWT expiry at 24h", "Security vs UX balance")

brain.trigger("deploy fails", "deploy,failure,502", "Check rollback procedure")
brain.doctor()                     # {'healthy': True, 'active_memories': 5, ...}

CLI

brainctl memory add "Auth uses JWT with 24h expiry" -c convention
brainctl search "auth"
brainctl entity create "Alice" -t person -o "Engineer"
brainctl entity relate Alice works_at Acme
brainctl event add "Deployed v2.0" -t result -p myproject
brainctl trigger create "deploy issue" -k deploy,failure -a "Check rollback"
brainctl stats

MCP Server (Claude Desktop / VS Code / Cursor)

{
  "mcpServers": {
    "brainctl": {
      "command": "brainctl-mcp"
    }
  }
}

196 tools available. See MCP_SERVER.md for the full list and a decision tree showing which tools to use when.

The Drop-In Pattern

Any agent, any framework. Three lines:

context = brain.orient()           # session start: handoff + events + triggers + memories
# ... do work ...
brain.wrap_up("what I accomplished")  # session end: logs event + creates handoff

orient() returns a single dict with everything the agent needs: pending handoff from the last session, recent events, active triggers, relevant memories, and stats. wrap_up() creates a handoff packet so the next session can resume.

See examples/ for runnable scripts and docs/AGENT_ONBOARDING.md for the full agent integration guide.

Framework Integrations

LangChain

pip install brainctl langchain-core
from agentmemory.integrations.langchain import BrainctlChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory

chain_with_history = RunnableWithMessageHistory(
    runnable=my_chain,
    get_session_history=lambda sid: BrainctlChatMessageHistory(session_id=sid),
)

Chat messages persist in brain.db. The Brain instance is accessible via history.brain for knowledge operations beyond chat (entities, decisions, triggers, search).

CrewAI

pip install brainctl crewai
from crewai import Crew
from crewai.memory import ShortTermMemory, LongTermMemory, EntityMemory
from agentmemory.integrations.crewai import BrainctlStorage

crew = Crew(
    agents=[...], tasks=[...], memory=True,
    short_term_memory=ShortTermMemory(storage=BrainctlStorage("short-term")),
    long_term_memory=LongTermMemory(storage=BrainctlStorage("long-term")),
    entity_memory=EntityMemory(storage=BrainctlStorage("entity")),
)

All crew memory goes to a single brain.db. FTS5 search out of the box, optional vector search with pip install brainctl[vec].

Agent harness plugins

First-party plugins that drop brainctl into agent-runner environments as persistent memory:

Plugin Target What it does Install
plugins/claude-code/brainctl/ Claude Code Hooks into SessionStart / UserPromptSubmit / PostToolUse / SessionEnd — orient on start, wrap_up on end, capture events during work python3 plugins/claude-code/brainctl/install.py
plugins/codex/brainctl/ OpenAI Codex CLI Idempotent merge of [mcp_servers.brainctl] into ~/.codex/config.toml + AGENTS.md.template for session bookends. Exposes the full 196-tool surface python3 plugins/codex/brainctl/install.py
plugins/hermes/brainctl/ Hermes Agent Full MemoryProvider with auto-recall, auto-retain, orient/wrap_up bookends, and MEMORY.md/USER.md mirroring. Upstream bundling: NousResearch/hermes-agent#9246 hermes memory setup → brainctl
plugins/eliza/brainctl/ Eliza TypeScript plugin (@brainctl/eliza-plugin) — spawns brainctl-mcp as a subprocess, exposes six actions (BRAINCTL_REMEMBER / SEARCH / ORIENT / WRAP_UP / DECIDE / LOG) plus an auto-recall memory provider npm install @brainctl/eliza-plugin

Trading-strategy plugins

Strategy-mixin plugins that give algorithmic trading frameworks persistent memory across backtests and live runs:

Plugin Target What it does
plugins/freqtrade/brainctl/ Freqtrade StrategyBrain mixin — remembers indicator states, logs trade decisions, correlates backtest vs live outcomes
plugins/jesse/brainctl/ Jesse Same shape as the Freqtrade plugin, adapted to Jesse's strategy API

Python API (21 methods)

Method What it does
remember(content, category) Store a durable fact
search(query) FTS5 full-text search with stemming
vsearch(query) Vector similarity search (optional)
forget(memory_id) Soft-delete a memory
entity(name, type) Create or get an entity
relate(from, rel, to) Link two entities
log(summary, type) Log a timestamped event
decide(title, rationale) Record a decision with reasoning
trigger(condition, keywords, action) Set a future reminder
check_triggers(query) Match triggers against text
handoff(goal, state, loops, next) Save session state
resume() Fetch + consume latest handoff
orient(project) One-call session start
wrap_up(summary) One-call session end
doctor() Diagnostic health check
consolidate() Promote important memories
tier_stats() Write-tier distribution
stats() Database overview
affect(text) Classify emotional state
affect_log(text) Classify + store emotional state

Core Concepts

Memories — Durable facts with categories that control their natural decay rate. Identity lasts a year; integration details fade in a month. Recalled memories get reinforced.

Events — Timestamped logs of what happened. Append-only. Searchable by type and project.

Entities — Typed nodes (person, project, tool, service) with observations. Form a self-building knowledge graph — when a memory mentions a known entity, the link is created automatically.

Decisions — Title + rationale. The "why" record. Prevents future agents from unknowingly contradicting prior choices.

Triggers — Prospective memory. "When X comes up, remind me to do Y." Fire on keyword match during search.

Handoffs — Working state packets for session continuity. Goal, current state, open loops, next step.

What Makes It Different

Feature brainctl mem0 Zep MemGPT
Single file (SQLite) yes - - -
No server required yes yes - -
No LLM calls yes - yes -
MCP server included yes - - -
Full-text search (FTS5) yes - - -
Vector search yes yes yes yes
Knowledge graph yes - yes -
Self-building graph yes - - -
Confidence decay yes - - -
Duplicate suppression yes - - -
Write gate (surprise scoring) yes - - -
Consolidation engine yes - - -
Prospective memory (triggers) yes - - -
Session handoffs yes - - -
Multi-agent support yes - yes -
Affect tracking yes - - -
Model-agnostic yes - yes -

Multi-Agent

Every operation accepts agent_id for attribution. Agents share one brain.db. Search sees everything. The knowledge graph connects insights across agents automatically.

researcher = Brain(agent_id="researcher")
deployer = Brain(agent_id="deployer")

researcher.remember("Auth uses bcrypt cost=12", category="convention")
deployer.search("bcrypt")  # finds researcher's memory

Context Profiles

Context profiles are task-scoped search presets. Instead of manually specifying --tables and --category on every query, name the task and brainctl loads only what's relevant.

brainctl search "voice" --profile writing     # memories: preference, convention, lesson
brainctl search "Sarah" --profile meeting     # contacts + interaction history + project context
brainctl search "JWT" --profile research      # technical knowledge + integrations
brainctl search "deploys" --profile ops       # events + decisions + project memories
brainctl search "founders" --profile networking  # entities (person, org) only
brainctl search "Q1" --profile review         # retrospective: lessons, decisions, projects

Works in MCP too:

{ "tool": "memory_search", "query": "tone of voice", "profile": "writing" }
{ "tool": "search", "query": "auth system", "profile": "research" }

List all profiles, create your own, or delete custom ones:

brainctl profile list
brainctl profile show writing
brainctl profile create coderev \
  --categories convention,lesson \
  --tables memories,events \
  --description "Code review context"
brainctl profile delete coderev

Built-in profiles:

Profile Tables Categories
writing memories, entities preference, convention, lesson
meeting memories, events, entities user, project, preference
research memories, entities integration, convention, lesson, environment
ops memories, events, decisions project, decision, lesson
networking entities, memories user
review memories, events, decisions lesson, decision, project

Profiles never override explicit --tables or --category flags — they're defaults, not locks.

Obsidian Integration

Bidirectional sync between brain.db and an Obsidian vault:

pip install brainctl[obsidian]
brainctl obsidian export ~/Documents/MyVault    # brain → markdown + wikilinks
brainctl obsidian import ~/Documents/MyVault    # new notes → brain (through write gate)
brainctl obsidian watch ~/Documents/MyVault     # auto-sync on file changes
brainctl obsidian status ~/Documents/MyVault    # drift report

Memory Lifecycle

brainctl manages memories like biological memory:

  • Write gate — Surprise scoring rejects redundant writes. Bypass with force=True.
  • Three-tier routing — High-value memories get full indexing; low-value get lightweight storage.
  • Duplicate suppression — Near-duplicates reinforce existing memories instead of creating new ones.
  • Half-life decay — Unused memories fade based on category. Recalled memories get reinforced.
  • Hard cap — 10,000 per agent. Emergency compression retires lowest-confidence memories.
  • Consolidation — Batch maintenance: Hebbian learning, temporal promotion, compression. Schedule with cron.

Health & Diagnostics

brain.doctor()    # table checks, integrity, vec availability, DB size
brainctl stats    # database overview
brainctl lint     # quality issues (low confidence, duplicates, orphans)
brainctl lint --fix  # auto-fix safe issues
brainctl cost     # token usage dashboard

Token Cost Optimization

brainctl search "deploy" --output oneline   # ~60 tokens (~97% savings vs JSON)
brainctl search "deploy" --budget 500       # hard token cap
brainctl search "deploy" --limit 3          # fewer results

Vector Search (Optional)

Works without embeddings. For semantic similarity:

pip install brainctl[vec]
ollama pull nomic-embed-text       # install Ollama first: https://ollama.ai
brainctl embed populate            # backfill embeddings
brainctl vsearch "semantic query"

Docker

docker build -t brainctl .
docker run -v ./data:/data brainctl                    # MCP server
docker run -v ./data:/data brainctl brainctl stats     # CLI

Documentation

Doc What it covers
Agent Onboarding Guide Step-by-step integration for agents
Agent Instructions Copy-paste blocks for MCP, CLI, Python agents
MCP Server Reference 196 tools with decision tree
Architecture Technical deep-dive
Cognitive Protocol The Orient-Work-Record pattern
Examples Runnable scripts (quickstart, lifecycle, multi-agent)
Contributing Development setup and PR workflow

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

brainctl-1.5.2.tar.gz (571.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

brainctl-1.5.2-py3-none-any.whl (486.0 kB view details)

Uploaded Python 3

File details

Details for the file brainctl-1.5.2.tar.gz.

File metadata

  • Download URL: brainctl-1.5.2.tar.gz
  • Upload date:
  • Size: 571.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for brainctl-1.5.2.tar.gz
Algorithm Hash digest
SHA256 133e9ecb01d8f520f11601a04bbfd89cdf02c187dc79142bf73ac2540bae1b9b
MD5 bb1a8eee90fc8df0b051ee01aa36357c
BLAKE2b-256 586ba362d7cdb7d73690d295efce8519cc2a738007a723160f7ec7fa98e2d337

See more details on using hashes here.

Provenance

The following attestation bundles were made for brainctl-1.5.2.tar.gz:

Publisher: publish.yml on TSchonleber/brainctl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file brainctl-1.5.2-py3-none-any.whl.

File metadata

  • Download URL: brainctl-1.5.2-py3-none-any.whl
  • Upload date:
  • Size: 486.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for brainctl-1.5.2-py3-none-any.whl
Algorithm Hash digest
SHA256 caf1b209058a2a1353a3c3e731fad947f5db9853f3debe71f74a6cbf45b7f8af
MD5 f7034a3a5a8f4725552399dd4670ad03
BLAKE2b-256 d9339259cd39f093d0957e54fcfc256382be7468b4fa07172e761f7785b64656

See more details on using hashes here.

Provenance

The following attestation bundles were made for brainctl-1.5.2-py3-none-any.whl:

Publisher: publish.yml on TSchonleber/brainctl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page