hermes-brain-memory 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,18 @@
1
+ """hermes-brain-memory — Brain Memory provider for Hermes Agent.
2
+
3
+ This package is an *installer + payload*: it vendors the Brain Memory
4
+ provider (a Hermes ``exclusive``/memory plugin, stdlib only) and ships the
5
+ ``hermes-brain-memory`` console script that copies it into
6
+ ``$HERMES_HOME/plugins/brain/``, where Hermes' user-plugin memory discovery
7
+ picks it up.
8
+
9
+ The provider itself lives in ``_vendor/brain/`` and is deliberately
10
+ self-contained — Hermes loads it from the plugins directory, never through
11
+ this package's import path.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ __version__ = "0.1.0"
17
+
18
+ __all__ = ["__version__"]
@@ -0,0 +1,51 @@
1
+ # Brain Memory provider for Hermes Agent
2
+
3
+ Backs Hermes Agent's memory slot with [Brain Memory](https://brainmemory.ai) — a local-first, human-readable Markdown memory store in `~/.brain/`, shared across Hermes, Claude Code, Codex, OpenCode, and OpenClaw. Memories decay, strengthen with use, and connect through an associative network — the model decides *what* to remember; the `brain` CLI handles the plumbing deterministically.
4
+
5
+ ## Requirements
6
+
7
+ - The `brain` CLI: `npm install -g brain-memory` (then run its installer once so `~/.brain/` exists)
8
+ - Python 3.10+ (no pip dependencies)
9
+
10
+ ## Setup
11
+
12
+ 1. Copy this directory to `$HERMES_HOME/plugins/brain/` (usually `~/.hermes/plugins/brain/`), or use it in-tree at `plugins/memory/brain/`.
13
+ 2. Activate it:
14
+
15
+ ```bash
16
+ hermes memory setup # guided
17
+ ```
18
+
19
+ or in `~/.hermes/config.yaml`:
20
+
21
+ ```yaml
22
+ memory:
23
+ provider: brain
24
+ ```
25
+
26
+ 3. Verify: `hermes memory status`
27
+
28
+ ## What it does
29
+
30
+ | Lifecycle | Behavior |
31
+ |---|---|
32
+ | Session start | Injects a budget-bounded context block from `brain session-start`: status line, pinned facts, skills index, relevant memory titles, memorize guidance |
33
+ | Pre-turn | Prefetches relevant memories for the user's message (background thread) |
34
+ | Tools | `brain_recall` (recall + auto-reinforce + full bodies), `brain_memorize` (validated store), `brain_reinforce` |
35
+ | Pre-compression | Reminds the model to store un-memorized notable content before context is discarded |
36
+ | Session end | Appends a session entry to `~/.brain/contexts.json` (last 20 kept) |
37
+ | Built-in memory writes | Mirrors MEMORY.md entries into `~/.brain` as deduplicated observations |
38
+
39
+ ## Configuration
40
+
41
+ Stored in `$HERMES_HOME/brain.json`; environment variables override defaults.
42
+
43
+ | Key | Default | Env var | Description |
44
+ |---|---|---|---|
45
+ | `project` | `hermes` | `BRAIN_PROJECT` | Project label for context-dependent recall |
46
+ | `top_recall` | `6` | `BRAIN_TOP_RECALL` | Max memories per recall (1–25) |
47
+ | `auto_reinforce` | `true` | `BRAIN_AUTO_REINFORCE` | Reinforce memories surfaced by `brain_recall` |
48
+ | `brain_bin` | `brain` | `BRAIN_BIN` | Path to the brain CLI |
49
+ | `sync_on_memorize` | `false` | `BRAIN_SYNC_ON_MEMORIZE` | Push each store to Brain Cloud / Git remote |
50
+
51
+ The built-in MEMORY.md/USER.md memory keeps running alongside — this provider supplements it with a long-lived, cross-agent store. See `integrations/hermes/README.md` in the brain-memory repository for hooks-based and MCP-based alternatives.
@@ -0,0 +1,31 @@
1
+ """Brain Memory provider plugin for Hermes Agent.
2
+
3
+ Local-first, human-readable Markdown memory (~/.brain) shared across Hermes,
4
+ Claude Code, Gemini CLI, Codex, OpenCode, and OpenClaw. See README.md.
5
+ """
6
+
7
+ try:
8
+ # Normal case: loaded as a package (in-tree plugins/memory/brain or
9
+ # $HERMES_HOME/plugins/brain when the loader imports the package).
10
+ from .provider import BrainMemoryProvider
11
+ except ImportError: # pragma: no cover
12
+ # Fallback: some loaders exec __init__.py as a standalone module, which
13
+ # breaks relative imports. Load provider.py from the same directory.
14
+ import importlib.util as _ilu
15
+ import os as _os
16
+
17
+ _spec = _ilu.spec_from_file_location(
18
+ "hermes_brain_memory_provider",
19
+ _os.path.join(_os.path.dirname(_os.path.abspath(__file__)), "provider.py"),
20
+ )
21
+ _mod = _ilu.module_from_spec(_spec)
22
+ assert _spec.loader is not None
23
+ _spec.loader.exec_module(_mod)
24
+ BrainMemoryProvider = _mod.BrainMemoryProvider
25
+
26
+ __all__ = ["BrainMemoryProvider", "register"]
27
+
28
+
29
+ def register(ctx) -> None:
30
+ """Register Brain Memory as a memory provider plugin."""
31
+ ctx.register_memory_provider(BrainMemoryProvider())
@@ -0,0 +1,119 @@
1
+ """Standalone diagnostics CLI for the Brain Memory provider.
2
+
3
+ Hermes loads user-installed memory providers through its memory-discovery
4
+ path, whose plugin context only accepts ``register_memory_provider`` — it has
5
+ no CLI registration (that API belongs to regular, non-exclusive plugins). So
6
+ these commands run as a plain module instead:
7
+
8
+ python3 ~/.hermes/plugins/brain/cli.py status
9
+ python3 ~/.hermes/plugins/brain/cli.py recall "what did we decide about X"
10
+
11
+ ``register_cli(subparser)`` is kept for a possible future in-tree bundling
12
+ where a real CLI hook exists. Stdlib only; shells out to the ``brain`` CLI
13
+ (brain-memory npm package). In-session, use the provider's ``brain_recall`` /
14
+ ``brain_memorize`` tools — the agent calls those itself.
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import json
20
+ import os
21
+ import shutil
22
+ import subprocess
23
+ from pathlib import Path
24
+
25
+ try:
26
+ from .provider import BrainMemoryProvider, brain_dir
27
+ except ImportError: # pragma: no cover — standalone loading
28
+ import importlib.util as _ilu
29
+
30
+ _spec = _ilu.spec_from_file_location(
31
+ "hermes_brain_memory_provider_cli",
32
+ os.path.join(os.path.dirname(os.path.abspath(__file__)), "provider.py"),
33
+ )
34
+ _mod = _ilu.module_from_spec(_spec)
35
+ assert _spec.loader is not None
36
+ _spec.loader.exec_module(_mod)
37
+ BrainMemoryProvider = _mod.BrainMemoryProvider
38
+ brain_dir = _mod.brain_dir
39
+
40
+
41
+ def _brain_bin() -> str:
42
+ return os.environ.get("BRAIN_BIN", "brain")
43
+
44
+
45
+ def _cmd_status(args) -> int:
46
+ bin_name = _brain_bin()
47
+ found = shutil.which(bin_name) or (os.path.isfile(os.path.expanduser(bin_name)) and bin_name)
48
+ store = brain_dir()
49
+ index = store / "index.json"
50
+ print(f"brain CLI : {found or 'NOT FOUND (npm install -g brain-memory)'}")
51
+ print(f"store : {store} ({'present' if store.exists() else 'missing'})")
52
+ print(f"index.json : {'present' if index.exists() else 'missing'}")
53
+ if found and index.exists():
54
+ try:
55
+ env = dict(os.environ)
56
+ env["BRAIN_AGENT"] = "hermes"
57
+ proc = subprocess.run(
58
+ [bin_name, "session-start", "--project", os.environ.get("BRAIN_PROJECT", "hermes")],
59
+ capture_output=True,
60
+ text=True,
61
+ timeout=15,
62
+ env=env,
63
+ )
64
+ if proc.returncode == 0:
65
+ payload = json.loads(proc.stdout)
66
+ print(f"memories : {payload.get('memory_count', '?')}")
67
+ print(f"pinned : {len(payload.get('pinned') or [])}")
68
+ print(f"skills : {len(payload.get('skills_index') or [])}")
69
+ except (OSError, subprocess.TimeoutExpired, ValueError):
70
+ print("memories : (could not query)")
71
+ return 0
72
+
73
+
74
+ def _cmd_recall(args) -> int:
75
+ provider = BrainMemoryProvider()
76
+ provider.initialize("cli", hermes_home=os.environ.get("HERMES_HOME", ""))
77
+ print(
78
+ provider.handle_tool_call(
79
+ "brain_recall",
80
+ {"query": " ".join(args.query), "reinforce": False},
81
+ )
82
+ )
83
+ return 0
84
+
85
+
86
+ def _dispatch(args) -> int:
87
+ command = getattr(args, "brain_command", None)
88
+ if command == "status":
89
+ return _cmd_status(args)
90
+ if command == "recall":
91
+ return _cmd_recall(args)
92
+ print("usage: hermes memory {status|recall <query>}")
93
+ return 1
94
+
95
+
96
+ def register_cli(subparser) -> None:
97
+ """Attach brain subcommands to an argparse subparser (in-tree use only —
98
+ Hermes exposes no CLI hook to user-installed memory providers)."""
99
+ subs = subparser.add_subparsers(dest="brain_command")
100
+ subs.add_parser("status", help="Show Brain Memory store status")
101
+ recall = subs.add_parser("recall", help="Recall memories from ~/.brain")
102
+ recall.add_argument("query", nargs="+", help="What to recall")
103
+ subparser.set_defaults(func=_dispatch)
104
+
105
+
106
+ def main(argv=None) -> int:
107
+ import argparse
108
+
109
+ parser = argparse.ArgumentParser(
110
+ prog="brain-provider",
111
+ description="Brain Memory provider diagnostics (standalone)",
112
+ )
113
+ register_cli(parser)
114
+ args = parser.parse_args(argv)
115
+ return _dispatch(args)
116
+
117
+
118
+ if __name__ == "__main__":
119
+ raise SystemExit(main())
@@ -0,0 +1,7 @@
1
+ name: brain
2
+ version: 1.0.0
3
+ description: "Brain Memory — local-first, human-readable Markdown memory (~/.brain) with decay, spreading activation, and spaced reinforcement, shared across Hermes, Claude Code, Codex, OpenCode, and OpenClaw."
4
+ hooks:
5
+ - on_session_end
6
+ - on_pre_compress
7
+ - on_memory_write