peon-mem 1.0.1 โ†’ 1.0.2

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.
package/README.md CHANGED
@@ -1,12 +1,12 @@
1
1
  # ๐Ÿง  Peon โ€” a memory brain for your AI coding agents
2
2
 
3
- [![npm](https://img.shields.io/npm/v/peon-mem)](https://www.npmjs.com/package/peon-mem) [![license](https://img.shields.io/badge/license-MIT-blue)](LICENSE) [![tests](https://img.shields.io/badge/tests-255%20passing-brightgreen)](test/)
3
+ [![npm](https://img.shields.io/npm/v/peon-mem)](https://www.npmjs.com/package/peon-mem) [![license](https://img.shields.io/badge/license-MIT-blue)](LICENSE) [![tests](https://img.shields.io/badge/tests-passing-brightgreen)](test/)
4
4
 
5
5
  **Local-first, hierarchical, self-improving memory for Claude Code, Codex, and any MCP client.**
6
6
 
7
- Your AI forgets everything between sessions. Peon doesn't. It records your sessions, consolidates
8
- them into typed *beliefs* with an LLM, and injects the relevant ones back into every prompt โ€”
9
- automatically, from a daemon that never leaves your machine.
7
+ Your AI forgets everything between sessions. Peon doesn't. It records your sessions, uses an
8
+ LLM to consolidate them into typed *beliefs*, and injects the relevant ones back into every
9
+ prompt. It runs as a daemon on your machine, and nothing leaves it.
10
10
 
11
11
  ```
12
12
  PEON GLOBAL BRAIN โ† user-level facts & preferences, inherited everywhere
@@ -16,25 +16,30 @@ automatically, from a daemon that never leaves your machine.
16
16
 
17
17
  ## Why Peon
18
18
 
19
- - **Hierarchical brains** โ€” one global parent brain (who you are, your rules, your tools) plus an
20
- isolated child brain per project. Every injection = project memory + inherited global memory.
21
- - **Two memory layers, honestly measured** โ€” consolidated *beliefs* (decisions, preferences, facts,
22
- artifactsโ€ฆ) for gist, plus an *episodic* verbatim layer that recovers exact details lossy
23
- summaries drop (measured on LongMemEval: raw-episodic recall 61% vs belief-only 17%).
24
- - **Auto capture + auto injection** โ€” Claude Code hooks record messages/events and inject a
25
- query-ranked memory block (with an `โš  MOST RELEVANT` headline) into every prompt. Zero effort.
26
- - **Cost-gated consolidation** โ€” an LLM distills sessions into beliefs only when enough new
27
- memory accumulates. Supersede / merge / conflict-detect; nothing is destructively deleted.
28
- - **Hybrid retrieval** โ€” lexical + semantic RRF fusion, MMR diversity, reinforcement, recency;
29
- query-embedding cache (persisted) so repeat prompts cost nothing.
30
- - **The Neural Universe** โ€” a live monitor at `localhost:3737/monitor` that renders every belief
31
- as a star: projects are galaxies, search makes matches flare, autonomous curation pulses.
32
- - **A daily self-improvement loop (STL)** โ€” Peon audits itself every day: what it recorded,
33
- injected, what failed, what consolidation did โ€” and files a report with a verdict.
34
- - **Eval-gated development** โ€” a committed results ledger (git SHA + qrels + brain fingerprint per
35
- row) so retrieval changes are *proven*, not asserted. Negative results stay documented.
36
- - **Local-first & locked down** โ€” plain JSONL you can read, loopback-only daemon with
37
- DNS-rebinding protection, secret redaction at the injection boundary, path-traversal guards.
19
+ - **Hierarchical brains.** One global parent brain holds who you are, your rules, and your
20
+ tools. Each project gets an isolated child brain. Every injection carries both.
21
+ - **Two memory layers, honestly measured.** Consolidated *beliefs* (decisions, preferences,
22
+ facts, artifacts) give you the gist. An *episodic* verbatim layer recovers the exact details
23
+ that lossy summaries drop. On LongMemEval, raw-episodic recall scored 61% where belief-only
24
+ scored 17%.
25
+ - **Automatic capture and injection.** Claude Code hooks record messages and events, then
26
+ inject a query-ranked memory block (with an `โš  MOST RELEVANT` headline) into every prompt.
27
+ You never have to remember to save anything.
28
+ - **Cost-gated consolidation.** An LLM distills sessions into beliefs only once enough new
29
+ memory accumulates. It can supersede, merge, and flag conflicts. Nothing is destructively
30
+ deleted.
31
+ - **Hybrid retrieval.** Lexical and semantic RRF fusion, MMR diversity, reinforcement, and
32
+ recency. Query embeddings are cached to disk, so repeat prompts cost nothing.
33
+ - **The Neural Universe.** A live monitor at `localhost:3737/monitor` renders every belief as
34
+ a star. Projects are galaxies, search makes matches flare, and autonomous curation pulses.
35
+ - **A daily self-audit (STL).** Peon checks itself every day: what it recorded, what it
36
+ injected, what failed, what consolidation did. Then it files a report with a verdict.
37
+ - **Eval-gated development.** A committed results ledger (git SHA, qrels, and brain
38
+ fingerprint per row) means retrieval changes are proven, not asserted. Negative results stay
39
+ documented.
40
+ - **Local-first and locked down.** Plain JSONL you can read, a loopback-only daemon with
41
+ DNS-rebinding protection, secret redaction at the injection boundary, and path-traversal
42
+ guards.
38
43
 
39
44
 
40
45
 
@@ -47,15 +52,15 @@ automatically, from a daemon that never leaves your machine.
47
52
 
48
53
  ## Why "Peon"?
49
54
 
50
- The name comes from Indian offices. Every office had a **peon** โ€” the person who walked desk to
55
+ The name comes from Indian offices. Every office had a **peon**, the person who walked desk to
51
56
  desk all day: collect a file from this table, note who needs what, carry it to the next table,
52
- remember where everything is. Not the boss, not the star โ€” but the one person the whole office
53
- quietly ran on. Nothing moved without him, and he never forgot where anything was.
57
+ remember where everything is. He wasn't the boss or the star, but the whole office quietly ran
58
+ on him. Nothing moved without him, and he never forgot where anything was.
54
59
 
55
- That's exactly this framework, with AI. Peon walks between your sessions and your projects โ€”
56
- collects what happened at one desk (a session), files it in the right cabinet (a project brain),
57
- carries the relevant papers to the next desk before you ask (injection), and keeps the master
58
- ledger upstairs (the global brain). Quiet clerk. Perfect memory. The office runs on him.
60
+ That's this framework, with AI. Peon walks between your sessions and your projects. It collects
61
+ what happened at one desk (a session), files it in the right cabinet (a project brain), carries
62
+ the relevant papers to the next desk before you ask (injection), and keeps the master ledger
63
+ upstairs (the global brain). Quiet clerk. Perfect memory. The office runs on him.
59
64
 
60
65
  ## How Peon differs from existing memory tools
61
66
 
@@ -71,9 +76,9 @@ ledger upstairs (the global brain). Quiet clerk. Perfect memory. The office runs
71
76
  | Observability | **live Neural Universe monitor + daily self-audit (STL) + serve telemetry** | dashboard | โ€” | โ€” | โ€” |
72
77
  | Verification | **committed eval ledger; negative results kept** | vendor benchmarks | โ€” | vendor benchmarks | โ€” |
73
78
 
74
- Positioning in one line: mem0/Zep are memory **platforms for products you build**; Peon is a
75
- memory **brain for the coding agents you already use** โ€” plug into Claude Code/Codex in five
76
- minutes, watch it think, audit every number.
79
+ The short version: mem0 and Zep are memory platforms for products you build. Peon is memory
80
+ for the coding agents you already use. It plugs into Claude Code or Codex in about five
81
+ minutes, and you can watch it think and audit every number it claims.
77
82
 
78
83
  ## Quickstart
79
84
 
@@ -91,12 +96,13 @@ npm install -g peon-mem && peon-mem install
91
96
  The guided setup asks four things:
92
97
 
93
98
  1. **Where your global brain lives** (default: `~/Library/Application Support/Peon`)
94
- 2. **Which LLM** โ€” OpenRouter (one key, any model) ยท OpenAI ยท Anthropic ยท **Ollama (100% local & free)** ยท or skip
95
- 3. Installs the **daemon** as an auto-start service
96
- 4. **Detects your AI apps** and wires the MCP server (+ hooks for Claude Code) into the ones you
97
- pick โ€” auto-configured: Claude Code, Claude Desktop, Codex, Gemini CLI, Cursor, Windsurf,
98
- VS Code (Copilot MCP), Zed, LM Studio; detected with in-app instructions: ChatGPT Desktop,
99
- Perplexity Desktop. Every touched config gets a `.peon-backup`.
99
+ 2. **Which LLM**: OpenRouter (one key, any model) ยท OpenAI ยท Anthropic ยท **Ollama (100% local
100
+ & free)** ยท or skip
101
+ 3. Installs the **daemon** as an auto-start service (launchd on macOS, systemd user unit on Linux)
102
+ 4. **Detects your AI apps** and wires the MCP server (plus hooks for Claude Code) into the
103
+ ones you pick. Auto-configured: Claude Code, Claude Desktop, Codex, Gemini CLI, Cursor,
104
+ Windsurf, VS Code (Copilot MCP), Zed, LM Studio. Detected with in-app instructions: ChatGPT
105
+ Desktop, Perplexity Desktop. Every touched config gets a `.peon-backup`.
100
106
 
101
107
  That builds the package, starts the daemon as a service, wires your Claude Code hooks + MCP
102
108
  server (with a backup of your settings), and writes a config template. Then add your key to
@@ -127,25 +133,28 @@ node dist/daemon-cli.js # serves 127.0.0.1:3737
127
133
 
128
134
  Then wire your agent (the installer prints these filled in for your paths):
129
135
 
130
- - **Claude Code** โ€” add the hook to `~/.claude/settings.json` (SessionStart / UserPromptSubmit /
136
+ - **Claude Code**: add the hook to `~/.claude/settings.json` (SessionStart / UserPromptSubmit /
131
137
  SessionEnd โ†’ `scripts/claude-peon-hook.mjs`) and the MCP server (`dist/index.js`).
132
- - **Codex / any MCP client** โ€” register `dist/index.js` as a stdio MCP server; 16 tools
138
+ - **Codex / any MCP client**: register `dist/index.js` as a stdio MCP server; 16 tools
133
139
  (`start_session`, `get_context`, `search_memory`, `record_message`, `process_memory`, โ€ฆ).
134
140
 
135
141
  Open `http://127.0.0.1:3737/monitor` and watch your brain grow.
136
142
 
137
143
  ## How it works
138
144
 
139
- 1. **Record** โ€” hooks stream messages/events/tool-calls into `<project>/.peon/raw/` (append-only).
140
- 2. **Consolidate** โ€” past a size gate, an LLM turns the session delta into typed belief records in
141
- `.peon/brain/memories.jsonl` (importance/confidence scores, entities, provenance pointers),
142
- reconciling against existing beliefs: supersede, merge, conflict-flag. Recoverable, never deleted.
143
- 3. **Retrieve + inject** โ€” on every prompt, beliefs are ranked (RRF lexical+semantic, MMR,
144
- reinforcement) and injected alongside episodic verbatim matches and inherited global beliefs.
145
- 4. **Self-curate** โ€” a background brain pass reinforces recalled beliefs, compresses stale
146
- clusters, resolves duplicates โ€” every action logged and undoable.
147
- 5. **Self-audit (STL)** โ€” a daily job reports: recorded / injected / went-wrong / consolidation
148
- correctness, with serve-latency telemetry and a health verdict.
145
+ 1. **Record.** Hooks stream messages, events, and tool calls into `<project>/.peon/raw/`
146
+ (append-only).
147
+ 2. **Consolidate.** Past a size gate, an LLM turns the session delta into typed belief records
148
+ in `.peon/brain/memories.jsonl` (importance/confidence scores, entities, provenance
149
+ pointers), reconciling against existing beliefs: supersede, merge, conflict-flag.
150
+ Recoverable, never deleted.
151
+ 3. **Retrieve + inject.** On every prompt, beliefs are ranked (RRF lexical+semantic, MMR,
152
+ reinforcement) and injected alongside episodic verbatim matches and inherited global
153
+ beliefs.
154
+ 4. **Self-curate.** A background brain pass reinforces recalled beliefs, compresses stale
155
+ clusters, and resolves duplicates. Every action is logged and undoable.
156
+ 5. **Self-audit (STL).** A daily job reports what was recorded, what was injected, what went
157
+ wrong, and whether consolidation behaved, with serve-latency telemetry and a health verdict.
149
158
 
150
159
 
151
160
  ## Full install (copy-paste)
@@ -177,7 +186,9 @@ launchctl load ~/Library/LaunchAgents/com.peon.daemon.plist
177
186
  curl http://127.0.0.1:3737/health # โ†’ {"ok":true}
178
187
  ```
179
188
 
180
- Linux: run `node dist/daemon-cli.js` under systemd (`Restart=always`).
189
+ Linux: the installer writes `~/.config/systemd/user/peon-mem.service` and enables it. Manual
190
+ equivalent: `systemctl --user enable --now peon-mem.service`, plus `loginctl enable-linger $USER`
191
+ so it survives logout. (Linux support is young โ€” [issue #1](https://github.com/VineetV2/peon-mem/issues/1) tracks real-machine reports.)
181
192
 
182
193
  ### 2. Claude Code โ€” hooks (auto capture + injection)
183
194
 
@@ -214,7 +225,7 @@ args = ["/ABSOLUTE/PATH/TO/peon/dist/index.js"]
214
225
  PEON_DAEMON_URL = "http://127.0.0.1:3737"
215
226
  ```
216
227
 
217
- Codex has no hooks โ€” add usage rules to `~/.codex/AGENTS.md` telling it to call
228
+ Codex has no hooks, so add usage rules to `~/.codex/AGENTS.md` telling it to call
218
229
  `start_session` + `get_context` at session start and `record_message` for durable facts
219
230
  (example block in [docs/](docs/)).
220
231
 
@@ -225,8 +236,8 @@ curl "http://127.0.0.1:3737/context?projectPath=$PWD&query=test" # JSON contex
225
236
  open http://127.0.0.1:3737/monitor # the Neural Universe
226
237
  ```
227
238
 
228
- Start a Claude Code session in any project, say something decision-shaped, end the session โ€”
229
- within a minute the monitor shows the belief. Next session injects it.
239
+ Start a Claude Code session in any project, say something decision-shaped, and end the session.
240
+ Within a minute the monitor shows the belief. The next session injects it.
230
241
 
231
242
  ### MCP tools exposed
232
243
 
@@ -245,17 +256,17 @@ launchctl unload ~/Library/LaunchAgents/com.peon.daemon.plist
245
256
 
246
257
  ## Troubleshooting / FAQ
247
258
 
248
- - **No injection appearing?** `curl http://127.0.0.1:3737/health`; check hook is registered
249
- (`claude` โ†’ run any prompt โ†’ monitor Systems page shows the request).
250
- - **431 errors on huge prompts?** Handled โ€” the hook caps the retrieval query at 2k chars.
259
+ - **No injection appearing?** `curl http://127.0.0.1:3737/health`; check the hook is registered
260
+ (run any prompt in `claude`, then look at the monitor's Systems page for the request).
261
+ - **431 errors on huge prompts?** Handled. The hook caps the retrieval query at 2k chars.
251
262
  - **No OpenRouter key?** Everything still runs; retrieval is lexical + episodic only
252
263
  (semantic ranking and consolidation need a model). `PEON_EMBEDDING_MODE=ollama` works too.
253
- - **Cost?** Consolidation is gated (default: fires per ~6k new chars, ~cents/day with
254
- flash-lite). Query embeddings are cached to disk โ€” repeats are free.
255
- - **Multiple machines?** Brains are plain files in your repos โ€” commit `.peon/` if you want
256
- memory to travel (redact first: raw layer contains session text).
264
+ - **Cost?** Consolidation is gated (default: fires per ~6k new chars, around cents/day with
265
+ flash-lite). Query embeddings are cached to disk, so repeats are free.
266
+ - **Multiple machines?** Brains are plain files in your repos. Commit `.peon/` if you want
267
+ memory to travel (redact first: the raw layer contains session text).
257
268
  - **Is my data sent anywhere?** Only consolidation/embedding calls to your configured model
258
- provider. No telemetry, no cloud store. Daemon rejects non-loopback callers.
269
+ provider. No telemetry, no cloud store. The daemon rejects non-loopback callers.
259
270
 
260
271
  ## Configuration (env)
261
272
 
@@ -275,55 +286,67 @@ launchctl unload ~/Library/LaunchAgents/com.peon.daemon.plist
275
286
 
276
287
  ## Project brains
277
288
 
278
- - A brain lives in `<project>/.peon/` โ€” human-readable JSONL + markdown. Commit it or ignore it;
279
- your choice (`.gitignore` ships ignoring it).
280
- - `.peon/root` marks a brain boundary. New brains are born rooted; a parent directory can never
281
- swallow a project's memory.
289
+ - A brain lives in `<project>/.peon/` as human-readable JSONL and markdown. Commit it or
290
+ ignore it; your choice (`.gitignore` ships ignoring it).
291
+ - `.peon/root` marks a brain boundary. New brains are born rooted, so a parent directory can
292
+ never swallow a project's memory.
282
293
  - The global brain lives in `~/Library/Application Support/Peon/global/` (macOS).
283
294
 
284
295
  ## Using Peon with NO AI at all
285
296
 
286
- Some people want a memory system that never calls a model โ€” no API keys, no local LLM, no
287
- embeddings, fully deterministic. Peon supports that as a first-class mode: pick **skip** in the
288
- install wizard, or set two env vars in `<memory-home>/.env`:
297
+ Some people want a memory system that never calls a model: no API keys, no local LLM, no
298
+ embeddings. Peon supports that. Pick **skip** in the install wizard, or set two env vars in
299
+ `<memory-home>/.env`:
289
300
 
290
301
  ```
291
302
  PEON_AI_MODE=off
292
303
  PEON_EMBEDDING_MODE=off
293
304
  ```
294
305
 
295
- **What still works (all of it deterministic code, no model anywhere):**
306
+ The pipeline looks like this without a model. Hooks still capture everything you do into
307
+ `<project>/.peon/raw/` as plain JSONL. As each event arrives, rule-based extraction files it
308
+ into readable brain files: a line that starts with "we decided" or "always use" lands in
309
+ `decisions.md`, preferences land in `preferences.md`, file paths land in `artifacts.md`. No
310
+ model reads it; it's pattern matching, and you can open the files to see exactly what it
311
+ caught. At your next session start, the hook asks the daemon for context, the daemon ranks
312
+ those records by keyword match, recency, and importance, and injects the best ones into your
313
+ prompt. The only step that disappears entirely is consolidation, the nightly LLM pass that
314
+ compresses raw history into deduplicated beliefs. Without it your memory is a well-indexed
315
+ journal instead of a distilled one. Search still finds things; nothing summarizes them.
296
316
 
297
- - **Capture** โ€” hooks record every prompt, tool call, and session event to plain JSONL in
317
+ What still works (all of it deterministic code, no model anywhere):
318
+
319
+ - **Capture.** Hooks record every prompt, tool call, and session event to plain JSONL in
298
320
  `<project>/.peon/raw/`.
299
- - **Real-time brain files** โ€” decisions, preferences, open questions, and artifacts are written
321
+ - **Real-time brain files.** Decisions, preferences, open questions, and artifacts are written
300
322
  live to readable `.md` files by rule-based extraction as events arrive.
301
- - **Injection** โ€” session-start context comes from those real-time files, query-focused and
323
+ - **Injection.** Session-start context comes from those real-time files, query-focused and
302
324
  budgeted, same as always.
303
- - **Search** โ€” lexical retrieval (RRF over keyword rank + recency + importance + type priors).
304
- No embeddings needed; this is the same degrade path the semantic stack falls back to.
305
- - **Episodic recall** โ€” verbatim what-was-said lookup is lexical by design, so it is unaffected.
306
- - **Monitor UI, token tracking, cross-project search, backups** โ€” all model-free.
325
+ - **Search.** Lexical retrieval (RRF over keyword rank, recency, importance, and type priors).
326
+ No embeddings needed. This is the same degrade path the semantic stack falls back to, so it
327
+ gets exercised constantly.
328
+ - **Episodic recall.** Verbatim what-was-said lookup is lexical by design, so it is unaffected.
329
+ - **Monitor UI, token tracking, cross-project search, backups.** All model-free.
307
330
 
308
- **What you give up:** consolidation (raw events are never distilled into deduplicated beliefs โ€”
331
+ What you give up: consolidation (raw events are never distilled into deduplicated beliefs, so
309
332
  memory grows as an append-only journal), semantic search (paraphrased queries need shared
310
333
  keywords), automatic entity extraction, and stale-shadow demotion (it compares embeddings).
311
334
 
312
- **Two escape hatches if you want curation without external AI:**
335
+ Two escape hatches if you want curation without external AI:
313
336
 
314
- 1. `process_memory` accepts a pre-built `aiResult` โ€” the coding agent you already run (Claude
337
+ 1. `process_memory` accepts a pre-built `aiResult`. The coding agent you already run (Claude
315
338
  Code, Codex) can do the distillation itself in-session and hand Peon the structured result.
316
339
  Memory stays curated, and Peon itself never spends a token.
317
- 2. Everything is plain JSONL/Markdown on disk โ€” you can edit beliefs by hand or through the
318
- monitor's memory endpoints. Peon backs up before every mutation.
340
+ 2. Everything is plain JSONL/Markdown on disk. You can edit beliefs by hand or through the
341
+ monitor's memory endpoints, and Peon backs up before every mutation.
319
342
 
320
343
  ## Measured: does memory actually save tokens?
321
344
 
322
- A/B test, real `claude -p` sessions, one question per session, same repo, same model. ON = Peon
323
- hooks active (memory injected at session start), OFF = `PEON_DISABLED=1` (agent falls back to
324
- reading files). 20 questions across procedures, past results, decisions, and current-state facts;
325
- 15 clean ON/OFF pairs survived tooling issues. Token counts read from Claude Code's own
326
- session transcripts.
345
+ A/B test with real `claude -p` sessions: one question per session, same repo, same model.
346
+ ON means Peon hooks active (memory injected at session start). OFF means `PEON_DISABLED=1`,
347
+ so the agent falls back to reading files. 20 questions across procedures, past results,
348
+ decisions, and current-state facts; 15 clean ON/OFF pairs survived tooling issues. Token
349
+ counts come from Claude Code's own session transcripts.
327
350
 
328
351
  | paired, n=15/arm | ON (Peon) | OFF | delta |
329
352
  |---|---|---|---|
@@ -332,38 +355,60 @@ session transcripts.
332
355
  | cache-read tokens | 81.6k | 110.5k | 1.35ร— less |
333
356
  | cheaper arm | **ON wins 12/15** | | |
334
357
 
335
- Answer quality (graded against repo ground truth): 8 ties, 1 clear Peon win, 5 baseline wins,
336
- 1 both-weak. The Peon win is the interesting one: a rule that was only ever stated in a
337
- conversation (a professor's citation policy from an email) โ€” the baseline answered *"no such
338
- rule found"*, Peon recited it exactly. Conversation-borne knowledge has no file to grep.
358
+ Answer quality, graded against repo ground truth: 8 ties, 1 clear Peon win, 5 baseline wins,
359
+ 1 where both were weak. The Peon win is the interesting one. A rule that was only ever stated
360
+ in a conversation (a professor's citation policy, from an email) got *"no such rule found"*
361
+ from the baseline; Peon recited it exactly. Conversation-borne knowledge has no file to grep.
339
362
 
340
363
  Honest caveats: the test repo has unusually good docs (a maintained research log), which makes
341
- the baseline strong โ€” most repos aren't like that; n=15 is small; questions were picked to have
342
- known answers, not sampled from real usage. Two weaknesses this test exposed โ€” a stale
343
- superseded belief outranking the newer truth, and token rows lost when consolidation outlived
344
- the hook timeout โ€” are both fixed (stale-shadow demotion at retrieval; usage logged before
345
- consolidation).
364
+ the baseline strong, and most repos aren't like that. n=15 is small. Questions were picked to
365
+ have known answers, not sampled from real usage. The test also exposed two real bugs in Peon
366
+ itself: a stale superseded belief outranking the newer truth, and token rows getting lost when
367
+ consolidation outlived the hook timeout. Both are fixed (stale-shadow demotion at retrieval;
368
+ usage logged before consolidation).
346
369
 
347
370
  ## Honesty section
348
371
 
349
- Peon's development is eval-gated and keeps its negative results: an associative entity graph was
350
- built, measured (โˆ’2.9% Recall@10), and turned OFF by default. Consolidation is lossy by design โ€”
351
- that's why the episodic layer exists and is regression-tested. The eval harness + committed
352
- ledger (`npm run eval`) let you verify retrieval changes on your own brain.
372
+ Peon's development is eval-gated and keeps its negative results. An associative entity graph
373
+ was built, measured (โˆ’2.9% Recall@10), and turned OFF by default. Consolidation is lossy by
374
+ design; that's why the episodic layer exists and is regression-tested. The eval harness and
375
+ committed ledger (`npm run eval`) let you verify retrieval changes on your own brain.
353
376
 
354
377
  ## Security
355
378
 
356
- - Daemon binds `127.0.0.1` only and rejects non-loopback `Host`/`Origin` (DNS-rebinding defense).
379
+ - The daemon binds `127.0.0.1` only and rejects non-loopback `Host`/`Origin` headers
380
+ (DNS-rebinding defense).
357
381
  - Secrets (API keys, tokens, JWTs) are redacted at the injection boundary.
358
- - Path-traversal guarded; per-project write locks; atomic tmp+rename writes; automatic backups
359
- before destructive-adjacent operations. Nothing is hard-deleted.
382
+ - Path traversal is guarded. Writes use per-project locks and atomic tmp+rename, with
383
+ automatic backups before anything destructive-adjacent. Nothing is hard-deleted.
360
384
 
361
385
  ## License
362
386
 
363
387
  MIT ยฉ Vineet Vora
364
388
 
365
- ## Contributing
389
+ ## Contributing โ€” I'd love your help
390
+
391
+ Peon is built and maintained by one person, and I'm open to help making it better. Issues,
392
+ PRs, ideas, criticism of the architecture, or just telling me where it broke on your machine:
393
+ all of it is useful.
394
+
395
+ Where help would matter most right now:
396
+
397
+ - **Windows & Linux support.** The daemon install is macOS launchd today. The systemd and Task
398
+ Scheduler equivalents need real users to test them.
399
+ - **More agent integrations.** The wizard covers 11 apps, but hooks-level capture (like the
400
+ Claude Code integration) for Codex, Cursor, and others would make memory richer everywhere.
401
+ - **Retrieval quality.** The eval harness (`npm run eval`) makes experiments cheap: better
402
+ consolidation prompts, smarter staleness handling, local embedding models worth defaulting
403
+ to.
404
+ - **Benchmarks.** Run the token A/B on your repo and share the numbers, especially where Peon
405
+ loses. Negative results are first-class here.
406
+ - **Docs and onboarding.** If the README or the wizard confused you, that confusion is a bug
407
+ report.
408
+
409
+ Open an issue at [github.com/VineetV2/peon-mem/issues](https://github.com/VineetV2/peon-mem/issues)
410
+ or send a PR directly.
366
411
 
367
- PRs welcome. Rules of the house: every retrieval/quality change ships with a test and an
368
- eval-ledger run (`npm run eval`); negative results get documented, not deleted; nothing may
369
- hard-delete user memory. `npm test` must stay green (255 tests).
412
+ Rules of the house: every retrieval/quality change ships with a test and an eval-ledger run
413
+ (`npm run eval`); negative results get documented, not deleted; nothing may hard-delete user
414
+ memory. `npm test` must stay green.
package/bin/peon-mem.mjs CHANGED
@@ -8,7 +8,7 @@
8
8
  * peon-mem doctor health + config check
9
9
  */
10
10
  import { execFileSync, spawnSync } from "node:child_process";
11
- import { existsSync, mkdirSync, readFileSync, writeFileSync, copyFileSync } from "node:fs";
11
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, copyFileSync, rmSync } from "node:fs";
12
12
  import { homedir, platform } from "node:os";
13
13
  import { dirname, join } from "node:path";
14
14
  import { fileURLToPath } from "node:url";
@@ -16,7 +16,8 @@ import { createInterface } from "node:readline/promises";
16
16
 
17
17
  const PKG = dirname(dirname(fileURLToPath(import.meta.url)));
18
18
  const HOME = homedir();
19
- const MAC = platform() === "darwin";
19
+ // PEON_FORCE_PLATFORM lets CI and maintainers exercise the other OS's install path.
20
+ const MAC = (process.env.PEON_FORCE_PLATFORM || platform()) === "darwin";
20
21
  const DEFAULT_HOME = MAC ? join(HOME, "Library", "Application Support", "Peon") : join(HOME, ".local", "share", "peon");
21
22
  const PLIST = join(HOME, "Library", "LaunchAgents", "com.peon.daemon.plist");
22
23
  const HOOK = join(PKG, "scripts", "claude-peon-hook.mjs");
@@ -156,8 +157,34 @@ function installService(memoryHome) {
156
157
  execFileSync("launchctl", ["load", PLIST]);
157
158
  });
158
159
  } else {
159
- log(" โ†’ Linux: systemd user unit:");
160
- log(` ExecStart=${NODE} ${DAEMON}\n WorkingDirectory=${memoryHome}\n Restart=always`);
160
+ // Linux: write a real systemd user unit instead of printing a recipe.
161
+ const unitDir = join(HOME, ".config", "systemd", "user");
162
+ const unitFile = join(unitDir, "peon-mem.service");
163
+ const unit = `[Unit]
164
+ Description=Peon memory daemon (local-first memory for AI coding agents)
165
+ After=network.target
166
+
167
+ [Service]
168
+ ExecStart=${NODE} ${DAEMON}
169
+ WorkingDirectory=${memoryHome}
170
+ Restart=always
171
+ RestartSec=2
172
+
173
+ [Install]
174
+ WantedBy=default.target
175
+ `;
176
+ act("daemon service (systemd user unit) โ†’ " + unitFile, () => {
177
+ mkdirSync(unitDir, { recursive: true });
178
+ writeFileSync(unitFile, unit);
179
+ // Enable + start when systemd is actually available; on failure fall back to instructions.
180
+ const r = spawnSync("systemctl", ["--user", "daemon-reload"], { stdio: "ignore" });
181
+ if (r.status === 0) {
182
+ spawnSync("systemctl", ["--user", "enable", "--now", "peon-mem.service"], { stdio: "ignore" });
183
+ }
184
+ });
185
+ log(" โ†’ if the daemon isn't running yet:");
186
+ log(" systemctl --user daemon-reload && systemctl --user enable --now peon-mem.service");
187
+ log(" loginctl enable-linger $USER # keeps it running after logout");
161
188
  }
162
189
  }
163
190
 
@@ -249,6 +276,11 @@ if (cmd === "install") {
249
276
  rl?.close();
250
277
  } else if (cmd === "uninstall") {
251
278
  if (MAC && existsSync(PLIST)) act("stop + remove daemon service", () => spawnSync("launchctl", ["unload", PLIST], { stdio: "ignore" }));
279
+ const UNIT = join(HOME, ".config", "systemd", "user", "peon-mem.service");
280
+ if (!MAC && existsSync(UNIT)) act("stop + remove daemon service", () => {
281
+ spawnSync("systemctl", ["--user", "disable", "--now", "peon-mem.service"], { stdio: "ignore" });
282
+ rmSync(UNIT, { force: true });
283
+ });
252
284
  const settings = join(HOME, ".claude", "settings.json");
253
285
  try {
254
286
  const s = JSON.parse(readFileSync(settings, "utf8"));
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "peon-mem",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -21,7 +21,7 @@
21
21
  "dependencies": {
22
22
  "@modelcontextprotocol/sdk": "^1.23.0"
23
23
  },
24
- "description": "Local-first hierarchical memory brain for AI coding agents โ€” auto-capture, LLM consolidation into beliefs, hybrid retrieval, per-prompt injection, a living Neural Universe monitor, and a daily self-improvement loop. Works with Claude Code, Codex, and any MCP client.",
24
+ "description": "Local-first hierarchical memory brain for AI coding agents \u2014 auto-capture, LLM consolidation into beliefs, hybrid retrieval, per-prompt injection, a living Neural Universe monitor, and a daily self-improvement loop. Works with Claude Code, Codex, and any MCP client.",
25
25
  "license": "MIT",
26
26
  "keywords": [
27
27
  "memory",
@@ -36,7 +36,7 @@
36
36
  ],
37
37
  "repository": {
38
38
  "type": "git",
39
- "url": "https://github.com/VineetV2/peon-mem"
39
+ "url": "git+https://github.com/VineetV2/peon-mem.git"
40
40
  },
41
41
  "engines": {
42
42
  "node": ">=20"
@@ -53,5 +53,6 @@
53
53
  "docs/assets",
54
54
  "README.md",
55
55
  "LICENSE"
56
- ]
57
- }
56
+ ],
57
+ "mcpName": "io.github.VineetV2/peon-mem"
58
+ }