apiary-memory 0.2.0__tar.gz

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,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Apiary
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,333 @@
1
+ Metadata-Version: 2.4
2
+ Name: apiary-memory
3
+ Version: 0.2.0
4
+ Summary: Local-first memory your AI agents share over MCP. Ships a working SQLite memory store; agents propose, only you confirm.
5
+ Author: Apiary
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://hello-fengchao.com
8
+ Project-URL: Repository, https://github.com/330899935/apiary-memory
9
+ Project-URL: App (macOS), https://apps.apple.com/app/id6806992983
10
+ Project-URL: Source, https://github.com/330899935/apiary-memory
11
+ Project-URL: Changelog, https://github.com/330899935/apiary-memory/blob/main/CHANGELOG.md
12
+ Keywords: mcp,mcp-server,model-context-protocol,memory,ai-memory,local-first,privacy,ai-agents,claude,cursor
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: MacOS
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Topic :: Database
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Requires-Python: >=3.8
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Dynamic: license-file
24
+
25
+ # Apiary Memory MCP
26
+
27
+ <!-- mcp-name: io.github.330899935/apiary-memory -->
28
+
29
+ > **Also known as:** Apiary Memory · 记忆蜂巢 · Memory Hive · 蜂巢 ·
30
+ > `io.github.330899935/apiary-memory` (MCP Registry name, from v0.2.0) ·
31
+ > `hive-memory` (Registry name up to v0.1.9) · `memory-hive-mcp` (PyPI package until the rename ships).
32
+ > Not affiliated with [hive.com](https://hive.com) (team collaboration) or the `hive-mcp` Claude Code plugin.
33
+
34
+ **Local-first personal memory for AI agents, over MCP.** Your agents can search what you have
35
+ confirmed and propose what they think you should keep; **only you can confirm it.** Everything
36
+ lives in one file on your own disk, and nothing is sent anywhere.
37
+
38
+ It runs on its own. A working SQLite memory store ships inside this package — no account, no
39
+ cloud, no daemon, no dependencies.
40
+
41
+ ```bash
42
+ pip install memory-hive-mcp
43
+ ```
44
+
45
+ **Desktop app, no terminal:** download [`memory-hive-mcp-0.1.9.mcpb`](https://github.com/330899935/apiary-memory/releases/download/v0.1.9/memory-hive-mcp-0.1.9.mcpb) and double-click it.
46
+
47
+ Measured on 2026-10-27, on one MacBook with the Hive running locally — script and raw output in [`bench/`](bench/):
48
+
49
+ | Measure | Result |
50
+ | --- | --- |
51
+ | Search latency | **p95 111 ms**, p50 76 ms (warm, includes HTTP) |
52
+ | Retrieval | correct entry in **top-5 for 97.5%** of 40 trials |
53
+ | Corpus | **1,303 entries · 2.39 M chars · 45 days**, plaintext only |
54
+
55
+ *Retrieval used each entry's own title as the query — an easy set. It shows the index is complete and ranks correctly on exact terms, not how well it answers a question asked in your own words. Run [`bench/bench_search.py`](bench/bench_search.py) on your own Hive.*
56
+
57
+ ---
58
+
59
+ ## What you get without the app
60
+
61
+ A complete, if modest, memory server. On a machine with nothing else installed:
62
+
63
+ | Call | What happens |
64
+ | --- | --- |
65
+ | `initialize` | answered locally, protocol `2024-11-05` |
66
+ | `tools/list` | answered locally, six tools |
67
+ | `propose` | **writes to a real database** on your disk |
68
+ | `recall` | **searches that database** and returns ranked entries |
69
+ | `get_context` | a digest of what you confirmed most recently |
70
+ | `manage` | read one entry, list what is pending, forget, restore |
71
+ | `say` / `board` | a shared message board for coordinating several agents |
72
+
73
+ Storage is SQLite at `~/.memory-hive/hive.db` by default. Search is lexical — character bigrams
74
+ for Chinese, words for Latin script — so it ranks well when the words overlap and finds nothing
75
+ when they do not. There are no embeddings and no vector index. Every response says
76
+ `"mode": "local"` so you can always tell which engine answered.
77
+
78
+ **Without the app, the database is plain SQLite: it is not encrypted.** That is stated here
79
+ rather than discovered later — see [Honest limits](#honest-limits).
80
+
81
+ ## What the app adds
82
+
83
+ [Apiary Memory for macOS](https://apps.apple.com/app/id6806992983) is the same design with the
84
+ expensive parts built: eight vaults with four of them locked behind a PIN (Argon2id-wrapped key,
85
+ AES-256 at rest), a daily evolution log, multi-agent identity management, and a UI for reading
86
+ and confirming. It also answers MCP itself, with richer ranking.
87
+
88
+ If the app is running, this package uses it and leaves the local file alone. If it is not, the
89
+ local store answers. You do not have to choose up front:
90
+
91
+ | `HIVE_MODE` | Behaviour |
92
+ | --- | --- |
93
+ | `auto` (default) | Ask the app. Use the local store **only if the app is unreachable.** |
94
+ | `local` | Never touch the network. Always use the local store. |
95
+ | `remote` | Only the app. A connection failure is an error, not a reroute. |
96
+
97
+ One rule holds in every mode: **if the app is running and answers with an error, that error is
98
+ returned unchanged.** Falling back on a refusal would write your memory into a second database
99
+ while your client believed it had reached the app. Silent data forking is worse than an error
100
+ message, so a reply from the app is final. The fallback fires on a connection failure, and on
101
+ nothing else.
102
+
103
+ ## Install
104
+
105
+ ```bash
106
+ pip install memory-hive-mcp # the server: memory-hive-mcp
107
+ # the human's CLI: memory-hive-mcp-cli
108
+ ```
109
+
110
+ Python 3.8 or newer. There is nothing else to install — the package uses only the standard
111
+ library, and `sqlite3` is part of it.
112
+
113
+ From a checkout:
114
+
115
+ ```bash
116
+ git clone https://github.com/330899935/apiary-memory
117
+ cd apiary-memory
118
+ PYTHONPATH=src python -m hive_mcp.stdio
119
+ ```
120
+
121
+ ## Connect a client
122
+
123
+ Any MCP host that can run a stdio command will work. The minimum is the command; everything else
124
+ is optional.
125
+
126
+ **Claude Desktop** — `~/Library/Application Support/Claude/claude_desktop_config.json`:
127
+
128
+ ```json
129
+ {
130
+ "mcpServers": {
131
+ "memory-hive": {
132
+ "command": "memory-hive-mcp",
133
+ "env": { "HIVE_MODE": "local" }
134
+ }
135
+ }
136
+ }
137
+ ```
138
+
139
+ **Cursor** — `~/.cursor/mcp.json`, same `mcpServers` shape.
140
+
141
+ **Any host that only speaks HTTP** — start the app and point it at `http://127.0.0.1:8768/mcp`
142
+ with the headers `X-Hive-Agent` and `X-Hive-Token`. This package is the stdio path; the HTTP
143
+ endpoint belongs to the app.
144
+
145
+ ## Prerequisite
146
+
147
+ **None, for the local store** — install the package and it works. A running app is a prerequisite
148
+ only for the app's own features: encrypted vaults, the evolution log, and multi-agent identity.
149
+ If you want those, install [the Hive app](https://apps.apple.com/app/id6806992983) (macOS,
150
+ version **1.4.5 or newer**) and leave `HIVE_MODE` at `auto`.
151
+
152
+ ## The six tools
153
+
154
+ The six tools are the whole surface. They are the same six whether the app or the local store
155
+ answers; only the ranking behind them differs — and, for two inputs, whether they exist at all.
156
+ The app accepts precomputed embeddings (`recall.query_vector`, `propose.vector`); the local
157
+ store has no embedder, so `tools/list` omits those two wherever the local store can answer,
158
+ including under `auto` where the app might stop answering mid-session. A field that would be
159
+ accepted and silently ignored is not advertised at all.
160
+
161
+ The same rule covers wording. `recall.query` is described as the lexical ranker it is wherever
162
+ the local store can answer — words and character bigrams, no embeddings — and as the app's
163
+ index-based ranking with `query_vector` for meaning wherever only the app can answer. A
164
+ description is a claim about what will happen to the input, so it is narrowed with the inputs.
165
+
166
+ Defaults are not narrowed, they are shared. Omit `limit` and you get 10 from `recall` and 8 from
167
+ `get_context`; omit `compact` and bodies come back trimmed; omit `ttl` on `say` and the card
168
+ lives 24 hours. Both engines answer those numbers identically, because a default is a number in
169
+ the schema rather than a capability one engine lacks. `store.py` holds each one as a named
170
+ constant, and the tests compare the answer against the advertised number instead of a second
171
+ hand-written copy of it.
172
+
173
+ | Tool | Kind | What it is for |
174
+ | --- | --- | --- |
175
+ | `recall` | read | Search confirmed memory by topic. `{"query": "..."}` plus optional `limit`, `vaults`, `compact`. |
176
+ | `propose` | write | Submit a memory for the human to approve. Lands in a queue; changes no confirmed memory. |
177
+ | `manage` | read/write | Address one entry: `list_pending`, `get_by_id`, `forget`, `restore`, `discard_pending`. |
178
+ | `get_context` | read | A short digest of recent confirmed memory, to seed a conversation. |
179
+ | `say` | write | Post to the shared board so other agents see what was done or handed over. |
180
+ | `board` | read | Read the board, optionally only what arrived since your last cursor. |
181
+
182
+ Two properties are worth stating plainly, because they are the product:
183
+
184
+ - **`propose` succeeding means "queued", not "stored".** `recall` will not return it until a
185
+ human confirms it.
186
+ - **`manage` has no `approve` action.** There is no path from an agent to a confirmed memory.
187
+ That is not an omission; it is the design.
188
+
189
+ ## Response shapes
190
+
191
+ `tools/list` is one surface for both engines, and an answer should be too: a model that has
192
+ to branch on which engine replied will eventually branch wrong. `board` therefore answers
193
+ the app's shape, field for field — `items`, `unread`, `count`, `cursor`, `reader` — and
194
+ `cursor` is the id of the newest card, the same kind of value the app returns.
195
+
196
+ The cursor is what a poll carries *across* an engine switch, which is why it gets the space.
197
+ Under `auto` one call can be answered by the app and the next by the local store. Before 0.1.9
198
+ the local engine answered a float epoch timestamp and read the app's card id with `float()`,
199
+ so a cursor fetched from the app came back as a full re-read of the board and nothing said
200
+ so; a float sent the other way matched no card id, and the app answered with its newest
201
+ `limit`, equally quietly.
202
+
203
+ A cursor can still fail to resolve: its card expired (cards live 24 hours by default), or it
204
+ was issued by the other engine, whose ids are `CB…` in the app and `msg_…` here. Neither
205
+ engine can resume from that, so both return the newest window — but this one also sets
206
+ `since_unknown` and a `note` saying which of those happened. `unread` counts every live card
207
+ after the cursor and `count` counts what the answer carries, so `unread > count` means the
208
+ page did not cover everything waiting, and the `note` says so in words.
209
+
210
+ Three shapes are **not** unified, because the engines really do hold different data:
211
+
212
+ - a `recall` entry names its vault `vault` from the local store and `wh` from the app;
213
+ - `get_context` returns one flat `digest` locally and one bucket per warehouse (`context`,
214
+ keyed by warehouse name) from the app;
215
+ - `roster` entries share `agent_id`; locally they also carry `messages` and `last_seen`,
216
+ while the app adds its registry card — display name, seat, leases, current task — which a
217
+ SQLite file has no way to know.
218
+
219
+ ## Confirming what agents propose
220
+
221
+ Agents propose. You confirm. The confirmation lives in a terminal, in a command you have to
222
+ type — deliberately not a tool an agent can call.
223
+
224
+ ```bash
225
+ memory-hive-mcp-cli list # what is waiting
226
+ memory-hive-mcp-cli show <id> # read one in full
227
+ memory-hive-mcp-cli approve <id> # confirm it, or --all
228
+ memory-hive-mcp-cli reject <id> # drop it for good
229
+ memory-hive-mcp-cli search "deploy key" # search confirmed memory
230
+ memory-hive-mcp-cli forget <id> # soft delete, reversible
231
+ memory-hive-mcp-cli restore <id> # undo forget
232
+ memory-hive-mcp-cli stats # counts and the database path
233
+ memory-hive-mcp-cli export --out dump.json
234
+ memory-hive-mcp-cli path
235
+ ```
236
+
237
+ `--db <path>` on any command points at a different database. `HIVE_DB` does the same from the
238
+ environment.
239
+
240
+ ## Where your memory lives
241
+
242
+ `~/.memory-hive/hive.db`, unless `HIVE_DB` says otherwise. One SQLite file; copy it to back it
243
+ up, delete it to start over.
244
+
245
+ The board keeps its messages in the same file, so there is only ever one thing to back up. Cards
246
+ expire: 24 hours unless `ttl` says otherwise, clamped to between 60 seconds and 30 days, which
247
+ is what the app does too — a board that grows forever stops being a board.
248
+
249
+ ## How search works, and what it does not do
250
+
251
+ Chinese text is indexed as single characters plus overlapping character bigrams; Latin text as
252
+ words. A query is scored by how much of it the entry covers, then nudged by recency — a 10%
253
+ multiplier, enough to break ties and not enough to overturn relevance.
254
+
255
+ This is a ranker, not an understander.
256
+
257
+ - **Scores are relative.** `0.8` means "closer than `0.4` for this query", not "80% confident".
258
+ They are not comparable across queries.
259
+ - **No semantic recall.** Ask about "money" and an entry that only says "invoice" will not be
260
+ found. Related-word coverage needs an embedder; this package has no dependencies and does not
261
+ pretend otherwise.
262
+ - **The ranking is the one the description states.** `tools/list` says "words and character
263
+ bigrams ... no embeddings" here, and that sentence is true of this engine. It is narrowed per
264
+ engine like the embedding inputs are, because the app's answer to the same question differs.
265
+ - **A miss is reported as a miss.** When nothing matches, `recall` says so and mentions how many
266
+ entries are awaiting confirmation, rather than returning a plausible neighbour.
267
+
268
+ ## Configuration
269
+
270
+ | Variable | Default | Purpose |
271
+ | --- | --- | --- |
272
+ | `HIVE_MODE` | `auto` | `auto`, `local`, or `remote` — see the table above |
273
+ | `HIVE_DB` | `~/.memory-hive/hive.db` | Where the local database lives |
274
+ | `HIVE_MCP_URL` | `http://127.0.0.1:8768/mcp` | The app's endpoint |
275
+ | `HIVE_AGENT_ID` | — | Agent id from the app; only for calls the app serves |
276
+ | `HIVE_AGENT_TOKEN` | — | Access token from the app; only for calls the app serves |
277
+
278
+ `HIVE_AGENT_ID` and `HIVE_AGENT_TOKEN` are **not** required to use the local store. They are
279
+ read straight from the environment and never written to disk by this package.
280
+
281
+ ## Honest limits
282
+
283
+ Written down because a memory tool that oversells itself is worse than one that does less.
284
+
285
+ 1. **The local store is not encrypted.** Plain SQLite. Anyone who can read your home directory
286
+ can read it. The app's vaults are the encrypted option, and `stats` reports
287
+ `"encrypted": false` instead of leaving you to find out.
288
+ 2. **No semantic search**, as above.
289
+ 3. **One writer at a time.** WAL mode lets the CLI confirm while a server is connected, but this
290
+ is a personal memory file, not a multi-host service. Do not point two machines at one
291
+ database over a network share.
292
+ 4. **The board is coordination, not memory.** Messages are for hand-offs between agents; they
293
+ are not searchable with `recall`.
294
+ 5. **The app is macOS only.** The local store is not — it is pure Python.
295
+
296
+ ## Troubleshooting
297
+
298
+ **"no confirmed memory matched this query" with entries pending.** Correct behaviour. Confirm
299
+ them: `memory-hive-mcp-cli list`, then `approve`.
300
+
301
+ **A call fails with a message about `HIVE_AGENT_ID`.** The app answered and refused the
302
+ credential. The call did **not** fall back to the local store, on purpose. Register an agent in
303
+ the app and set both variables, or set `HIVE_MODE=local` if you meant to use the local file.
304
+
305
+ **"Hive app not reachable ... and HIVE_MODE=remote forbids the local fallback".** You asked for
306
+ the app only and it is not running. Start it, or drop `HIVE_MODE=remote`.
307
+
308
+ **Where did my memory go?** `memory-hive-mcp-cli stats` prints the database path. If `HIVE_MODE`
309
+ is `auto` and the app is running, the app has been answering — the local file is untouched by
310
+ design.
311
+
312
+ ## Development
313
+
314
+ ```bash
315
+ PYTHONPATH=src python -m unittest discover -s tests -v
316
+ ```
317
+
318
+ The suite needs no running app and no network: it stands up its own fake backend where a real
319
+ response is required, and points `HIVE_DB` at a temporary file so a test never touches a real
320
+ memory database.
321
+
322
+ Layout:
323
+
324
+ ```
325
+ src/hive_mcp/store.py the memory engine (SQLite, stdlib only)
326
+ src/hive_mcp/stdio.py the MCP server: routing, envelopes, the app bridge
327
+ src/hive_mcp/cli.py the human's half: review and confirm
328
+ src/hive_mcp/tools.json the tool surface snapshot for the offline path
329
+ ```
330
+
331
+ ## License
332
+
333
+ MIT. Your memory file is yours; nothing here phones home.
@@ -0,0 +1,309 @@
1
+ # Apiary Memory MCP
2
+
3
+ <!-- mcp-name: io.github.330899935/apiary-memory -->
4
+
5
+ > **Also known as:** Apiary Memory · 记忆蜂巢 · Memory Hive · 蜂巢 ·
6
+ > `io.github.330899935/apiary-memory` (MCP Registry name, from v0.2.0) ·
7
+ > `hive-memory` (Registry name up to v0.1.9) · `memory-hive-mcp` (PyPI package until the rename ships).
8
+ > Not affiliated with [hive.com](https://hive.com) (team collaboration) or the `hive-mcp` Claude Code plugin.
9
+
10
+ **Local-first personal memory for AI agents, over MCP.** Your agents can search what you have
11
+ confirmed and propose what they think you should keep; **only you can confirm it.** Everything
12
+ lives in one file on your own disk, and nothing is sent anywhere.
13
+
14
+ It runs on its own. A working SQLite memory store ships inside this package — no account, no
15
+ cloud, no daemon, no dependencies.
16
+
17
+ ```bash
18
+ pip install memory-hive-mcp
19
+ ```
20
+
21
+ **Desktop app, no terminal:** download [`memory-hive-mcp-0.1.9.mcpb`](https://github.com/330899935/apiary-memory/releases/download/v0.1.9/memory-hive-mcp-0.1.9.mcpb) and double-click it.
22
+
23
+ Measured on 2026-10-27, on one MacBook with the Hive running locally — script and raw output in [`bench/`](bench/):
24
+
25
+ | Measure | Result |
26
+ | --- | --- |
27
+ | Search latency | **p95 111 ms**, p50 76 ms (warm, includes HTTP) |
28
+ | Retrieval | correct entry in **top-5 for 97.5%** of 40 trials |
29
+ | Corpus | **1,303 entries · 2.39 M chars · 45 days**, plaintext only |
30
+
31
+ *Retrieval used each entry's own title as the query — an easy set. It shows the index is complete and ranks correctly on exact terms, not how well it answers a question asked in your own words. Run [`bench/bench_search.py`](bench/bench_search.py) on your own Hive.*
32
+
33
+ ---
34
+
35
+ ## What you get without the app
36
+
37
+ A complete, if modest, memory server. On a machine with nothing else installed:
38
+
39
+ | Call | What happens |
40
+ | --- | --- |
41
+ | `initialize` | answered locally, protocol `2024-11-05` |
42
+ | `tools/list` | answered locally, six tools |
43
+ | `propose` | **writes to a real database** on your disk |
44
+ | `recall` | **searches that database** and returns ranked entries |
45
+ | `get_context` | a digest of what you confirmed most recently |
46
+ | `manage` | read one entry, list what is pending, forget, restore |
47
+ | `say` / `board` | a shared message board for coordinating several agents |
48
+
49
+ Storage is SQLite at `~/.memory-hive/hive.db` by default. Search is lexical — character bigrams
50
+ for Chinese, words for Latin script — so it ranks well when the words overlap and finds nothing
51
+ when they do not. There are no embeddings and no vector index. Every response says
52
+ `"mode": "local"` so you can always tell which engine answered.
53
+
54
+ **Without the app, the database is plain SQLite: it is not encrypted.** That is stated here
55
+ rather than discovered later — see [Honest limits](#honest-limits).
56
+
57
+ ## What the app adds
58
+
59
+ [Apiary Memory for macOS](https://apps.apple.com/app/id6806992983) is the same design with the
60
+ expensive parts built: eight vaults with four of them locked behind a PIN (Argon2id-wrapped key,
61
+ AES-256 at rest), a daily evolution log, multi-agent identity management, and a UI for reading
62
+ and confirming. It also answers MCP itself, with richer ranking.
63
+
64
+ If the app is running, this package uses it and leaves the local file alone. If it is not, the
65
+ local store answers. You do not have to choose up front:
66
+
67
+ | `HIVE_MODE` | Behaviour |
68
+ | --- | --- |
69
+ | `auto` (default) | Ask the app. Use the local store **only if the app is unreachable.** |
70
+ | `local` | Never touch the network. Always use the local store. |
71
+ | `remote` | Only the app. A connection failure is an error, not a reroute. |
72
+
73
+ One rule holds in every mode: **if the app is running and answers with an error, that error is
74
+ returned unchanged.** Falling back on a refusal would write your memory into a second database
75
+ while your client believed it had reached the app. Silent data forking is worse than an error
76
+ message, so a reply from the app is final. The fallback fires on a connection failure, and on
77
+ nothing else.
78
+
79
+ ## Install
80
+
81
+ ```bash
82
+ pip install memory-hive-mcp # the server: memory-hive-mcp
83
+ # the human's CLI: memory-hive-mcp-cli
84
+ ```
85
+
86
+ Python 3.8 or newer. There is nothing else to install — the package uses only the standard
87
+ library, and `sqlite3` is part of it.
88
+
89
+ From a checkout:
90
+
91
+ ```bash
92
+ git clone https://github.com/330899935/apiary-memory
93
+ cd apiary-memory
94
+ PYTHONPATH=src python -m hive_mcp.stdio
95
+ ```
96
+
97
+ ## Connect a client
98
+
99
+ Any MCP host that can run a stdio command will work. The minimum is the command; everything else
100
+ is optional.
101
+
102
+ **Claude Desktop** — `~/Library/Application Support/Claude/claude_desktop_config.json`:
103
+
104
+ ```json
105
+ {
106
+ "mcpServers": {
107
+ "memory-hive": {
108
+ "command": "memory-hive-mcp",
109
+ "env": { "HIVE_MODE": "local" }
110
+ }
111
+ }
112
+ }
113
+ ```
114
+
115
+ **Cursor** — `~/.cursor/mcp.json`, same `mcpServers` shape.
116
+
117
+ **Any host that only speaks HTTP** — start the app and point it at `http://127.0.0.1:8768/mcp`
118
+ with the headers `X-Hive-Agent` and `X-Hive-Token`. This package is the stdio path; the HTTP
119
+ endpoint belongs to the app.
120
+
121
+ ## Prerequisite
122
+
123
+ **None, for the local store** — install the package and it works. A running app is a prerequisite
124
+ only for the app's own features: encrypted vaults, the evolution log, and multi-agent identity.
125
+ If you want those, install [the Hive app](https://apps.apple.com/app/id6806992983) (macOS,
126
+ version **1.4.5 or newer**) and leave `HIVE_MODE` at `auto`.
127
+
128
+ ## The six tools
129
+
130
+ The six tools are the whole surface. They are the same six whether the app or the local store
131
+ answers; only the ranking behind them differs — and, for two inputs, whether they exist at all.
132
+ The app accepts precomputed embeddings (`recall.query_vector`, `propose.vector`); the local
133
+ store has no embedder, so `tools/list` omits those two wherever the local store can answer,
134
+ including under `auto` where the app might stop answering mid-session. A field that would be
135
+ accepted and silently ignored is not advertised at all.
136
+
137
+ The same rule covers wording. `recall.query` is described as the lexical ranker it is wherever
138
+ the local store can answer — words and character bigrams, no embeddings — and as the app's
139
+ index-based ranking with `query_vector` for meaning wherever only the app can answer. A
140
+ description is a claim about what will happen to the input, so it is narrowed with the inputs.
141
+
142
+ Defaults are not narrowed, they are shared. Omit `limit` and you get 10 from `recall` and 8 from
143
+ `get_context`; omit `compact` and bodies come back trimmed; omit `ttl` on `say` and the card
144
+ lives 24 hours. Both engines answer those numbers identically, because a default is a number in
145
+ the schema rather than a capability one engine lacks. `store.py` holds each one as a named
146
+ constant, and the tests compare the answer against the advertised number instead of a second
147
+ hand-written copy of it.
148
+
149
+ | Tool | Kind | What it is for |
150
+ | --- | --- | --- |
151
+ | `recall` | read | Search confirmed memory by topic. `{"query": "..."}` plus optional `limit`, `vaults`, `compact`. |
152
+ | `propose` | write | Submit a memory for the human to approve. Lands in a queue; changes no confirmed memory. |
153
+ | `manage` | read/write | Address one entry: `list_pending`, `get_by_id`, `forget`, `restore`, `discard_pending`. |
154
+ | `get_context` | read | A short digest of recent confirmed memory, to seed a conversation. |
155
+ | `say` | write | Post to the shared board so other agents see what was done or handed over. |
156
+ | `board` | read | Read the board, optionally only what arrived since your last cursor. |
157
+
158
+ Two properties are worth stating plainly, because they are the product:
159
+
160
+ - **`propose` succeeding means "queued", not "stored".** `recall` will not return it until a
161
+ human confirms it.
162
+ - **`manage` has no `approve` action.** There is no path from an agent to a confirmed memory.
163
+ That is not an omission; it is the design.
164
+
165
+ ## Response shapes
166
+
167
+ `tools/list` is one surface for both engines, and an answer should be too: a model that has
168
+ to branch on which engine replied will eventually branch wrong. `board` therefore answers
169
+ the app's shape, field for field — `items`, `unread`, `count`, `cursor`, `reader` — and
170
+ `cursor` is the id of the newest card, the same kind of value the app returns.
171
+
172
+ The cursor is what a poll carries *across* an engine switch, which is why it gets the space.
173
+ Under `auto` one call can be answered by the app and the next by the local store. Before 0.1.9
174
+ the local engine answered a float epoch timestamp and read the app's card id with `float()`,
175
+ so a cursor fetched from the app came back as a full re-read of the board and nothing said
176
+ so; a float sent the other way matched no card id, and the app answered with its newest
177
+ `limit`, equally quietly.
178
+
179
+ A cursor can still fail to resolve: its card expired (cards live 24 hours by default), or it
180
+ was issued by the other engine, whose ids are `CB…` in the app and `msg_…` here. Neither
181
+ engine can resume from that, so both return the newest window — but this one also sets
182
+ `since_unknown` and a `note` saying which of those happened. `unread` counts every live card
183
+ after the cursor and `count` counts what the answer carries, so `unread > count` means the
184
+ page did not cover everything waiting, and the `note` says so in words.
185
+
186
+ Three shapes are **not** unified, because the engines really do hold different data:
187
+
188
+ - a `recall` entry names its vault `vault` from the local store and `wh` from the app;
189
+ - `get_context` returns one flat `digest` locally and one bucket per warehouse (`context`,
190
+ keyed by warehouse name) from the app;
191
+ - `roster` entries share `agent_id`; locally they also carry `messages` and `last_seen`,
192
+ while the app adds its registry card — display name, seat, leases, current task — which a
193
+ SQLite file has no way to know.
194
+
195
+ ## Confirming what agents propose
196
+
197
+ Agents propose. You confirm. The confirmation lives in a terminal, in a command you have to
198
+ type — deliberately not a tool an agent can call.
199
+
200
+ ```bash
201
+ memory-hive-mcp-cli list # what is waiting
202
+ memory-hive-mcp-cli show <id> # read one in full
203
+ memory-hive-mcp-cli approve <id> # confirm it, or --all
204
+ memory-hive-mcp-cli reject <id> # drop it for good
205
+ memory-hive-mcp-cli search "deploy key" # search confirmed memory
206
+ memory-hive-mcp-cli forget <id> # soft delete, reversible
207
+ memory-hive-mcp-cli restore <id> # undo forget
208
+ memory-hive-mcp-cli stats # counts and the database path
209
+ memory-hive-mcp-cli export --out dump.json
210
+ memory-hive-mcp-cli path
211
+ ```
212
+
213
+ `--db <path>` on any command points at a different database. `HIVE_DB` does the same from the
214
+ environment.
215
+
216
+ ## Where your memory lives
217
+
218
+ `~/.memory-hive/hive.db`, unless `HIVE_DB` says otherwise. One SQLite file; copy it to back it
219
+ up, delete it to start over.
220
+
221
+ The board keeps its messages in the same file, so there is only ever one thing to back up. Cards
222
+ expire: 24 hours unless `ttl` says otherwise, clamped to between 60 seconds and 30 days, which
223
+ is what the app does too — a board that grows forever stops being a board.
224
+
225
+ ## How search works, and what it does not do
226
+
227
+ Chinese text is indexed as single characters plus overlapping character bigrams; Latin text as
228
+ words. A query is scored by how much of it the entry covers, then nudged by recency — a 10%
229
+ multiplier, enough to break ties and not enough to overturn relevance.
230
+
231
+ This is a ranker, not an understander.
232
+
233
+ - **Scores are relative.** `0.8` means "closer than `0.4` for this query", not "80% confident".
234
+ They are not comparable across queries.
235
+ - **No semantic recall.** Ask about "money" and an entry that only says "invoice" will not be
236
+ found. Related-word coverage needs an embedder; this package has no dependencies and does not
237
+ pretend otherwise.
238
+ - **The ranking is the one the description states.** `tools/list` says "words and character
239
+ bigrams ... no embeddings" here, and that sentence is true of this engine. It is narrowed per
240
+ engine like the embedding inputs are, because the app's answer to the same question differs.
241
+ - **A miss is reported as a miss.** When nothing matches, `recall` says so and mentions how many
242
+ entries are awaiting confirmation, rather than returning a plausible neighbour.
243
+
244
+ ## Configuration
245
+
246
+ | Variable | Default | Purpose |
247
+ | --- | --- | --- |
248
+ | `HIVE_MODE` | `auto` | `auto`, `local`, or `remote` — see the table above |
249
+ | `HIVE_DB` | `~/.memory-hive/hive.db` | Where the local database lives |
250
+ | `HIVE_MCP_URL` | `http://127.0.0.1:8768/mcp` | The app's endpoint |
251
+ | `HIVE_AGENT_ID` | — | Agent id from the app; only for calls the app serves |
252
+ | `HIVE_AGENT_TOKEN` | — | Access token from the app; only for calls the app serves |
253
+
254
+ `HIVE_AGENT_ID` and `HIVE_AGENT_TOKEN` are **not** required to use the local store. They are
255
+ read straight from the environment and never written to disk by this package.
256
+
257
+ ## Honest limits
258
+
259
+ Written down because a memory tool that oversells itself is worse than one that does less.
260
+
261
+ 1. **The local store is not encrypted.** Plain SQLite. Anyone who can read your home directory
262
+ can read it. The app's vaults are the encrypted option, and `stats` reports
263
+ `"encrypted": false` instead of leaving you to find out.
264
+ 2. **No semantic search**, as above.
265
+ 3. **One writer at a time.** WAL mode lets the CLI confirm while a server is connected, but this
266
+ is a personal memory file, not a multi-host service. Do not point two machines at one
267
+ database over a network share.
268
+ 4. **The board is coordination, not memory.** Messages are for hand-offs between agents; they
269
+ are not searchable with `recall`.
270
+ 5. **The app is macOS only.** The local store is not — it is pure Python.
271
+
272
+ ## Troubleshooting
273
+
274
+ **"no confirmed memory matched this query" with entries pending.** Correct behaviour. Confirm
275
+ them: `memory-hive-mcp-cli list`, then `approve`.
276
+
277
+ **A call fails with a message about `HIVE_AGENT_ID`.** The app answered and refused the
278
+ credential. The call did **not** fall back to the local store, on purpose. Register an agent in
279
+ the app and set both variables, or set `HIVE_MODE=local` if you meant to use the local file.
280
+
281
+ **"Hive app not reachable ... and HIVE_MODE=remote forbids the local fallback".** You asked for
282
+ the app only and it is not running. Start it, or drop `HIVE_MODE=remote`.
283
+
284
+ **Where did my memory go?** `memory-hive-mcp-cli stats` prints the database path. If `HIVE_MODE`
285
+ is `auto` and the app is running, the app has been answering — the local file is untouched by
286
+ design.
287
+
288
+ ## Development
289
+
290
+ ```bash
291
+ PYTHONPATH=src python -m unittest discover -s tests -v
292
+ ```
293
+
294
+ The suite needs no running app and no network: it stands up its own fake backend where a real
295
+ response is required, and points `HIVE_DB` at a temporary file so a test never touches a real
296
+ memory database.
297
+
298
+ Layout:
299
+
300
+ ```
301
+ src/hive_mcp/store.py the memory engine (SQLite, stdlib only)
302
+ src/hive_mcp/stdio.py the MCP server: routing, envelopes, the app bridge
303
+ src/hive_mcp/cli.py the human's half: review and confirm
304
+ src/hive_mcp/tools.json the tool surface snapshot for the offline path
305
+ ```
306
+
307
+ ## License
308
+
309
+ MIT. Your memory file is yours; nothing here phones home.