@bcmyguest/openmem 0.6.3 → 0.9.0
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/{skills → .agents/skills}/openmem/SKILL.md +5 -0
- package/README.md +81 -76
- package/cli/coding-agent/capabilities.mjs +14 -3
- package/cli/coding-agent/context-store.mjs +81 -0
- package/cli/coding-agent/context-trim.mjs +899 -0
- package/cli/coding-agent/file-io.mjs +72 -0
- package/cli/coding-agent/hook-harnesses.mjs +2 -1
- package/cli/coding-agent/hook-runner.mjs +28 -4
- package/cli/coding-agent/install-access.mjs +43 -17
- package/cli/coding-agent/install-context-proxy.mjs +333 -0
- package/cli/coding-agent/install-rtk.mjs +60 -0
- package/cli/coding-agent/install-shim.mjs +119 -15
- package/cli/coding-agent/opencode-config.mjs +21 -5
- package/cli/coding-agent/opencode-plugin.mjs +39 -3
- package/cli/coding-agent/opencode2-plugin/index.js +299 -0
- package/cli/coding-agent/recall-frame.mjs +29 -0
- package/cli/coding-agent/remove-upstream-access.mjs +122 -0
- package/cli/coding-agent/runtime.mjs +2 -1
- package/cli/coding-agent/session-db.mjs +626 -0
- package/cli/coding-agent/session-facade.mjs +30 -6
- package/cli/coding-agent/toml-edit.mjs +161 -0
- package/cli/context-management.mjs +254 -0
- package/cli/feed-sync.mjs +18 -2
- package/cli/install-coding-agent.mjs +173 -40
- package/cli/mcp/context-sql-runner.mjs +58 -0
- package/cli/mcp/context-store.mjs +670 -0
- package/cli/mcp/knowledge.mjs +333 -0
- package/cli/mcp/memory-facade.mjs +99 -33
- package/cli/openmem-mcp.mjs +3 -0
- package/cli/openmem.mjs +18 -1
- package/cli/schedule.mjs +176 -0
- package/cli/stack.mjs +2 -0
- package/cli/switch-memory-provider.mjs +1 -1
- package/compose.yaml +67 -4
- package/config/hindsight.env.example +2 -0
- package/config/openmem.toml.example +64 -2
- package/docs/architecture.md +35 -9
- package/docs/coding-agent-hooks.md +26 -2
- package/docs/coding-agents.md +27 -7
- package/docs/compatibility.md +80 -0
- package/docs/concepts.md +30 -7
- package/docs/context-management.md +230 -0
- package/docs/context-proxy.md +115 -0
- package/docs/context-research.md +226 -0
- package/docs/context-store.md +277 -0
- package/docs/evidence-plan.md +216 -0
- package/docs/hindsight.md +5 -2
- package/docs/mcp-setup.md +5 -2
- package/docs/mem0.md +39 -1
- package/docs/memory-providers.md +2 -2
- package/docs/meridian-litellm.md +198 -0
- package/docs/model-configuration.md +22 -0
- package/docs/npx-install.md +6 -4
- package/docs/openmem-config.md +2 -2
- package/docs/quickstart.md +12 -6
- package/docs/setup-wizard.md +5 -4
- package/docs/sources-feeds.md +9 -22
- package/package.json +5 -4
- package/providers/cognee/OPERATOR.md +2 -2
- package/providers/hindsight/lib/clack.mjs +122 -20
- package/providers/hindsight/lib/coding-agent.mjs +1 -1
- package/providers/hindsight/lib/config.mjs +6 -0
- package/providers/hindsight/lib/env-setup.mjs +2 -1
- package/providers/hindsight/lib/litellm-routes.mjs +21 -12
- package/providers/hindsight/lib/meridian.mjs +307 -0
- package/providers/hindsight/lib/model-backend.mjs +38 -9
- package/providers/hindsight/lib/probe.mjs +21 -0
- package/providers/hindsight/lib/stack-env.mjs +5 -12
- package/providers/hindsight/lib/state.mjs +6 -1
- package/providers/hindsight/lib/summary.mjs +16 -2
- package/providers/hindsight/lib/validate.mjs +6 -0
- package/providers/hindsight/wizard.mjs +3 -2
- package/providers/mem0/OPERATOR.md +21 -2
- package/providers/mem0/compose.yaml +24 -2
- package/providers/mem0/lib/coding-agent.mjs +1 -1
- package/providers/mem0/lib/configure.mjs +66 -0
- package/providers/mem0/lib/litellm.mjs +457 -0
- package/providers/mem0/lib/stack-env.mjs +40 -1
- package/providers/mem0/lib/summary.mjs +30 -2
- package/providers/mem0/manifest.json +1 -1
- package/providers/mem0/wizard.mjs +15 -2
- package/proxy/config.yaml +33 -0
- package/proxy/openmem_context/__init__.py +6 -0
- package/proxy/openmem_context/adapters.py +504 -0
- package/proxy/openmem_context/compress.py +53 -0
- package/proxy/openmem_context/core.py +608 -0
- package/proxy/openmem_context/embed.py +212 -0
- package/proxy/openmem_context/recall.py +49 -0
- package/proxy/openmem_context/session.py +70 -0
- package/proxy/openmem_context/sessiondb.py +276 -0
- package/proxy/openmem_context/settings.py +134 -0
- package/proxy/openmem_context/store.py +129 -0
- package/proxy/openmem_context/tokens.py +123 -0
- package/proxy/openmem_context/ttl.py +78 -0
- package/proxy/openmem_context_hook.py +34 -0
- package/scripts/check-pack.mjs +2 -1
- package/scripts/run-setup.sh +14 -5
- package/scripts/setup.mjs +14 -1
- package/server.json +2 -2
- package/wizard/lib/context-step.mjs +140 -0
- package/wizard/lib/litellm-env.mjs +55 -0
- package/wizard/lib/pm-config.mjs +212 -4
- package/wizard/lib/prompts.mjs +28 -0
- package/wizard/lib/run-wizard.mjs +26 -31
|
@@ -15,12 +15,17 @@ For project work, pass the project bank explicitly so memories do not land in th
|
|
|
15
15
|
|
|
16
16
|
- For past decisions or project context, call `memory_recall` with a focused query and the project bank. `memory_search` is also available for direct search.
|
|
17
17
|
- Use `memory_reflect` when a question needs a synthesized answer across several memories. Check the returned evidence before treating it as current truth.
|
|
18
|
+
- Before fixing a bug or changing a convention, call `memory_pages_search` (then `memory_pages_read`; `memory_pages_list` shows what exists) for curated decision and convention pages. Hindsight only.
|
|
19
|
+
- When an `[openmem: continuing session <sid>; …]` pointer says earlier messages are not in your context, call `smart_compact_search` with that `session_id` and a query to recover the detail. Pass `pattern` (a JavaScript regex, `ignore_case` optional) instead of `query` for exact strings, and `context` (0–5) for neighbouring rows; `role` defaults to user and tool rows (`"all"` adds assistant text) and `in_context: false` keeps only trimmed rows; `line_matches` is an exact count of matching lines across the whole session (use it for "how many" questions). For counts, groupings or joins, call `smart_compact_sql` with the `session_id` and one read-only `SELECT` over the session database (`messages`, `lines`, `messages_fts`, `lines_fts`; the tool description lists the schema). For a compressed tool result, call `smart_compact_get` with its `id` (page with `offset`). All three read local files and work with every provider.
|
|
20
|
+
- To check whether context management is working, call `context_status` (or run `openmem context status`), not docker logs. It reports trims, estimated tokens saved and fail-opens. A fail-open means the request still succeeded but went to the model untrimmed; `proxy_stale: true` means the proxy runs older code than the checkout and needs a restart.
|
|
18
21
|
- If the tools are unavailable, say that memory was unavailable. Do not claim to have searched it.
|
|
19
22
|
|
|
20
23
|
## Store and correct
|
|
21
24
|
|
|
22
25
|
- Session hooks capture supported conversations. When the user explicitly asks to remember a durable fact, external note, or decision now, call `memory_add` with a concise, self-contained record and the project bank. On Hindsight, `memory_add` defaults to **async** ingest (omit `async` or pass `async: true`) so MCP clients do not time out; use `async: false` only when you must wait for extraction.
|
|
23
26
|
- When verified code or current documentation contradicts a memory, call `memory_add` with a correction that states the old claim, the current fact, and the evidence. Do not silently leave a known false record to resurface.
|
|
27
|
+
- After the user approves a plan for a new feature, call `memory_capture_initiative` before writing code; skip bug fixes and small tweaks.
|
|
28
|
+
- Call `memory_status` before relying on recall of just-stored content; it reports whether async ingest has drained.
|
|
24
29
|
- `memory_forget` can delete an entire Hindsight bank. Confirm the exact scope before using it for bulk deletion.
|
|
25
30
|
|
|
26
31
|
Use `memory_provider_status` to identify the active provider when that matters. The provider can change without changing this skill or the tool names.
|
package/README.md
CHANGED
|
@@ -2,18 +2,45 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@bcmyguest/openmem)
|
|
4
4
|
[](LICENSE)
|
|
5
|
-
[](https://glama.ai/mcp/servers/bcmyguest/openmem/score)
|
|
6
6
|
[](https://github.com/bcmyguest/openmem)
|
|
7
7
|
|
|
8
|
-
[](https://glama.ai/mcp/servers/bcmyguest/openmem)
|
|
9
9
|
|
|
10
|
-
**
|
|
10
|
+
**OpenMem.** Memory and context management for coding agents: smart compaction that keeps every turn searchable, pluggable [memory providers](https://bcmyguest.github.io/openmem/docs/provider-status/) (Hindsight, mem0, Cognee), one setup wizard.
|
|
11
11
|
|
|
12
|
-
**
|
|
12
|
+
**A. Memory**: your sources become memory any agent can query.
|
|
13
13
|
|
|
14
|
-
>
|
|
14
|
+
<p align="center">
|
|
15
|
+
<picture>
|
|
16
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://bcmyguest.github.io/openmem/media/overview-memory-wide-dark.png" />
|
|
17
|
+
<img src="https://bcmyguest.github.io/openmem/media/overview-memory-wide.png" alt="A, memory: sources (Git repos, Obsidian vaults, notes, papers, bookmarks, feeds), OpenMem indexer, one active provider (Hindsight default, mem0, Cognee), OpenMem MCP tools, coding agents with session hooks" />
|
|
18
|
+
</picture>
|
|
19
|
+
</p>
|
|
20
|
+
|
|
21
|
+
**B. Context management**: long sessions stay under the limit; nothing is summarized away.
|
|
22
|
+
|
|
23
|
+
<p align="center">
|
|
24
|
+
<picture>
|
|
25
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://bcmyguest.github.io/openmem/media/overview-context-wide-dark.png" />
|
|
26
|
+
<img src="https://bcmyguest.github.io/openmem/media/overview-context-wide.png" alt="B, context management: coding agent, context proxy trimming at 125k tokens (Haiku 95k) with no LLM call, model API, SQLite session store read back with smart_compact_search and smart_compact_sql; OpenCode 2 uses a native plugin" />
|
|
27
|
+
</picture>
|
|
28
|
+
</p>
|
|
29
|
+
|
|
30
|
+
**Benchmarks:** In seed-matched [ContextBench](https://github.com/RulinShao/ContextBench) log tasks on Haiku 5.5, smart compaction scored 0.469 higher than keep-everything (95% bootstrap interval 0.339–0.578; eight pairs). All arms scored 1.0 on kv R4000. Costs fell at R4000, L6400, and L12800; the L1600 saving remains uncertain. Claude Code's default native arm made no compaction in these tasks. [Methods and results](docs/context-management.md#benchmarks) · [paired intervals and pending work](docs/evidence-plan.md#completed-seed-paired-comparisons). Compact-Bench real-coding results are pending.
|
|
31
|
+
|
|
32
|
+
<p align="center">
|
|
33
|
+
<picture>
|
|
34
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://bcmyguest.github.io/openmem/media/contextbench-quality-compact-dark.png" />
|
|
35
|
+
<img src="https://bcmyguest.github.io/openmem/media/contextbench-quality-compact.png" alt="ContextBench scores: kv R4000 scores 1.00 in all arms; on log tasks, OpenMem scores 1.00 at L1600, 0.88 at L6400 and 1.00 at L12800, above both baselines" width="480" />
|
|
36
|
+
</picture>
|
|
37
|
+
</p>
|
|
15
38
|
|
|
16
|
-
**
|
|
39
|
+
**Docs:** [bcmyguest.github.io/openmem/](https://bcmyguest.github.io/openmem/)
|
|
40
|
+
|
|
41
|
+
**MCP:** `npx -y -p @bcmyguest/openmem openmem-mcp` (after the wizard — it needs a running provider)
|
|
42
|
+
|
|
43
|
+
**Start here:** [Concepts](https://bcmyguest.github.io/openmem/docs/concepts/) · [Quickstart](https://bcmyguest.github.io/openmem/docs/getting-started/) · [Compatibility](https://bcmyguest.github.io/openmem/docs/compatibility/)
|
|
17
44
|
|
|
18
45
|
## Quickstart
|
|
19
46
|
|
|
@@ -27,91 +54,61 @@
|
|
|
27
54
|
|
|
28
55
|
```sh
|
|
29
56
|
git clone https://github.com/bcmyguest/openmem.git && cd openmem
|
|
30
|
-
npm install &&
|
|
57
|
+
npm install && npm run setup
|
|
31
58
|
```
|
|
32
59
|
|
|
33
|
-
|
|
60
|
+
Other commands from a checkout: `node cli/openmem.mjs <command>`.
|
|
34
61
|
|
|
35
|
-
|
|
62
|
+
**Needs:** Docker Compose v2, Node ≥ 24 (built-in `node:sqlite` with FTS5), and an LLM route if you use Hindsight (lemond, Ollama, OpenAI-compatible, or a Claude subscription through Meridian — set in the wizard).
|
|
36
63
|
|
|
37
|
-
|
|
38
|
-
npx @bcmyguest/openmem up
|
|
39
|
-
npx @bcmyguest/openmem down
|
|
40
|
-
npx @bcmyguest/openmem switch mem0 --yes
|
|
41
|
-
npx @bcmyguest/openmem doctor
|
|
42
|
-
```
|
|
64
|
+
Later: `npx @bcmyguest/openmem up` / `down` / `switch <provider> --yes` / `doctor`.
|
|
43
65
|
|
|
44
66
|
Wizard dry-run (what first setup plans — no writes):
|
|
45
67
|
|
|
46
|
-
|
|
68
|
+
<p align="center">
|
|
69
|
+
<img src="https://bcmyguest.github.io/openmem/setup-demo.gif" alt="Terminal recording of the setup wizard dry run: preflight checks, memory provider, model backend, secrets, sources and stack steps, each planned write printed as a [dry-run] line" width="720" />
|
|
70
|
+
</p>
|
|
47
71
|
|
|
48
72
|
Full guide: [Quickstart](https://bcmyguest.github.io/openmem/docs/getting-started/) · [Concepts](https://bcmyguest.github.io/openmem/docs/concepts/) · [Architecture](https://bcmyguest.github.io/openmem/docs/architecture/)
|
|
49
73
|
|
|
50
74
|
## Architecture
|
|
51
75
|
|
|
76
|
+
The two diagrams at the top show memory (A) and context management (B).
|
|
77
|
+
|
|
78
|
+
<details>
|
|
79
|
+
<summary>Same diagrams as Mermaid</summary>
|
|
80
|
+
|
|
52
81
|
```mermaid
|
|
53
|
-
flowchart
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
subgraph compose["Docker Compose — one active provider"]
|
|
62
|
-
IDX[indexer]
|
|
63
|
-
PROV[(Provider API)]
|
|
64
|
-
IDX -->|retain / update| PROV
|
|
65
|
-
LIT[LiteLLM]
|
|
66
|
-
NLM[NotebookLM sync]
|
|
67
|
-
LIT -.->|Hindsight stack + optional reflect synth| PROV
|
|
68
|
-
NLM -.->|opt-in profile| PROV
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
LIT --> LLM[(lemond · Ollama · OpenAI-compatible)]
|
|
72
|
-
|
|
73
|
-
subgraph host["Host — coding agents"]
|
|
74
|
-
AG[Claude Code · Codex · Cursor Agent · OpenCode]
|
|
75
|
-
UMCP["OpenMem MCP\n(memory_*)"]
|
|
76
|
-
SHIM["Session hooks"]
|
|
77
|
-
PLG["Hindsight plugin\n(optional)"]
|
|
78
|
-
SKILL["openmem skill"]
|
|
79
|
-
PMCP[Provider MCP optional]
|
|
80
|
-
NLMCP[NotebookLM MCP optional]
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
GIT --> IDX
|
|
84
|
-
OBS --> IDX
|
|
85
|
-
MD --> IDX
|
|
86
|
-
FEED --> IDX
|
|
87
|
-
AG <-->|stdio| UMCP
|
|
88
|
-
AG <-->|hooks| SHIM
|
|
89
|
-
AG --> SKILL
|
|
90
|
-
AG <-->|optional| PLG
|
|
91
|
-
SHIM --> UMCP
|
|
92
|
-
AG <-->|stdio| PMCP
|
|
93
|
-
AG <-->|stdio| NLMCP
|
|
94
|
-
UMCP -->|loopback HTTP| PROV
|
|
95
|
-
PLG -->|loopback HTTP| PROV
|
|
96
|
-
PMCP -->|loopback HTTP| PROV
|
|
97
|
-
NLMCP -->|loopback HTTP| PROV
|
|
98
|
-
|
|
99
|
-
W["npx @bcmyguest/openmem\nsetup · install-mcp"] -.->|configure| compose
|
|
100
|
-
W -.->|mcp.json| UMCP
|
|
82
|
+
flowchart LR
|
|
83
|
+
S["<b>Sources</b><br/>Git repos: docs, code outlines<br/>Obsidian vaults · notes · papers · bookmarks<br/>RSS · OpenAlex feeds"] -->|index| I["<b>OpenMem indexer</b><br/>polls repos, watches folders"]
|
|
84
|
+
I -->|retain| P[("<b>Memory provider</b><br/>one active, swappable<br/>Hindsight (default) · mem0 · Cognee · …")]
|
|
85
|
+
P <--> M["<b>OpenMem MCP</b><br/>memory_recall · memory_add<br/>memory_search · memory_reflect<br/>memory_pages_* + export/import, status…"]
|
|
86
|
+
M <-->|tools| A["<b>Coding agents</b><br/>Claude Code · Codex · Cursor · OpenCode"]
|
|
87
|
+
A -.->|"session hooks: recall at start · retain at stop"| M
|
|
88
|
+
classDef om fill:#e8eaf9,stroke:#4651a6,color:#1b1d2a
|
|
89
|
+
class I,M om
|
|
101
90
|
```
|
|
102
91
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
|
92
|
+
```mermaid
|
|
93
|
+
flowchart LR
|
|
94
|
+
A["<b>Coding agent</b><br/>Claude Code · Codex · OpenCode 1"] -->|requests| X["<b>Context proxy</b><br/>LiteLLM pre-call hook<br/>trims at 125k tokens (Haiku 95k) · no LLM call"]
|
|
95
|
+
X -->|trimmed request| API["<b>Model API</b><br/>Anthropic · ChatGPT (Codex)"]
|
|
96
|
+
X -->|every turn| S[("<b>Session store</b><br/>SQLite · every turn, verbatim")]
|
|
97
|
+
S -->|"MCP: smart_compact_search · smart_compact_sql"| A
|
|
98
|
+
O["<b>OpenCode 2</b><br/>native plugin, no proxy"] -.->|same store| S
|
|
99
|
+
classDef om fill:#e8eaf9,stroke:#4651a6,color:#1b1d2a
|
|
100
|
+
class X,S om
|
|
101
|
+
```
|
|
108
102
|
|
|
109
|
-
|
|
103
|
+
</details>
|
|
104
|
+
|
|
105
|
+
Native compaction replaces history with an LLM summary, so exact values can be lost; OpenMem keeps every turn verbatim and searchable. The optional [context proxy](https://bcmyguest.github.io/openmem/docs/context-proxy/) trims long agent sessions without an LLM summary. See the [full architecture](https://bcmyguest.github.io/openmem/docs/architecture/) for setup, optional integrations, and provider-specific behavior.
|
|
110
106
|
|
|
111
107
|
## Providers and portability
|
|
112
108
|
|
|
113
|
-
- **Providers** —
|
|
109
|
+
- **Providers** — [Provider status](https://bcmyguest.github.io/openmem/docs/provider-status/) lists every provider and its support level from the manifests. Contributor details: [adding a provider](https://github.com/bcmyguest/openmem/blob/main/docs/memory-providers.md).
|
|
114
110
|
- **MCP** — unified `memory_*` plus optional native/NotebookLM servers: [MCP setup](https://bcmyguest.github.io/openmem/docs/mcp-setup/).
|
|
111
|
+
- **Context management** — smart compaction on/off, per-agent support, tools and config: [Context management](https://bcmyguest.github.io/openmem/docs/context-management/).
|
|
115
112
|
- **Portable memory** — `memory_export` / `memory_import` speak **PMM**: [Portable memory](https://bcmyguest.github.io/openmem/docs/memory-portability/).
|
|
116
113
|
- **Switch** — `npx @bcmyguest/openmem switch <provider>` does not migrate data by itself; export/import (or re-index) moves content.
|
|
117
114
|
|
|
@@ -125,12 +122,20 @@ OpenMem is not affiliated with these projects; they shape the problem or the pat
|
|
|
125
122
|
| --- | --- |
|
|
126
123
|
| **[OpenFeature](https://openfeature.dev/)** | Inspiration for a vendor-agnostic interface + pluggable providers (there: feature flags; here: coding-agent memory). |
|
|
127
124
|
| **[mise](https://mise.jdx.dev/) / [asdf](https://asdf-vm.com/)** | One CLI over many backends; declarative config and tasks without replacing each tool’s own settings. |
|
|
128
|
-
| **[
|
|
129
|
-
| **[
|
|
130
|
-
| **[
|
|
131
|
-
| **[
|
|
125
|
+
| **[LiteLLM](https://github.com/BerriAI/litellm)** | Model proxy used on Hindsight stacks; its pre-call hook hosts the context proxy. |
|
|
126
|
+
| **[Hindsight coding agents](https://www.npmjs.com/package/@vectorize-io/hindsight-coding-agents)** | Reference implementation for knowledge pages, initiative capture and ingest status; OpenMem's hooks replace it in `openmem` mode. |
|
|
127
|
+
| **[Mainplane](https://github.com/mainplane-ai/mainplane)** | Inspiration for smart compaction: continue in a fresh context with a pointer to the saved transcript and retrieve as you go, instead of an LLM summary. |
|
|
128
|
+
| **[Letta](https://www.letta.com/) / [MemGPT](https://arxiv.org/abs/2310.08560)** | Inspiration for smart compaction: evicted turns kept verbatim in searchable recall storage the agent pages back with tools, and [file-style search over the transcript](https://www.letta.com/blog/benchmarking-ai-agent-memory/) (74.0% on LoCoMo). OpenMem does this in a proxy and an MCP server, so no Letta server is needed. |
|
|
129
|
+
| **[rtk](https://github.com/rtk-ai/rtk)** | Compresses shell command output before the agent sees it; `install-coding-agent` runs `rtk init` when it is installed. Inspired the context proxy's compression of large tool results (reimplemented, not bundled). |
|
|
130
|
+
| **[opencode-clm](https://github.com/bcmyguest/opencode-clm)** | OpenCode plugin for [Context Language Models](https://arxiv.org/abs/2609.37725): the model edits a file mirror of its own context. Same goal as smart compaction, with the model doing the trimming ([comparison](https://bcmyguest.github.io/openmem/docs/context-research/)). |
|
|
131
|
+
| **[Meridian](https://github.com/rynfar/meridian)** | Bridges a Claude subscription to an Anthropic-compatible API; optional Hindsight model backend ([guide](https://bcmyguest.github.io/openmem/docs/model-configuration/)). |
|
|
132
|
+
| **[OpenCode](https://opencode.ai/)** / **[Claude Code hooks](https://code.claude.com/docs/en/hooks)** / **[Codex hooks](https://developers.openai.com/codex/hooks)** | The agent hook and plugin APIs OpenMem translates between ([compatibility](https://bcmyguest.github.io/openmem/docs/compatibility/)). |
|
|
133
|
+
|
|
134
|
+
Research notes and benchmark results for the context proxy: [Context research](https://bcmyguest.github.io/openmem/docs/context-research/).
|
|
132
135
|
|
|
133
|
-
More setup analogues
|
|
136
|
+
More setup analogues: [Pluggable memory providers](https://github.com/bcmyguest/openmem/blob/main/docs/memory-providers.md).
|
|
137
|
+
|
|
138
|
+
> Formerly **personal-memory**. Use the `openmem` CLI and MCP server name; installers drop the old `personal-memory` MCP entry.
|
|
134
139
|
|
|
135
140
|
## License
|
|
136
141
|
|
|
@@ -5,12 +5,23 @@ import { CODING_AGENTS, DEFAULT_AGENT_IDS } from "./agents.mjs";
|
|
|
5
5
|
export const AGENT_IDS = Object.freeze(CODING_AGENTS.map((a) => a.id));
|
|
6
6
|
export { DEFAULT_AGENT_IDS };
|
|
7
7
|
|
|
8
|
-
/**
|
|
8
|
+
/**
|
|
9
|
+
* @typedef {"retain" | "recall" | "reflect" | "consolidate" | "bank_scope" | "knowledge_pages" | "initiatives" | "ingest_status"} Feature
|
|
10
|
+
*/
|
|
9
11
|
|
|
10
12
|
/** @type {Record<string, Partial<Record<Feature, boolean>>>} */
|
|
11
13
|
export const PROVIDER_CAPABILITIES = {
|
|
12
|
-
hindsight: {
|
|
13
|
-
|
|
14
|
+
hindsight: {
|
|
15
|
+
retain: true,
|
|
16
|
+
recall: true,
|
|
17
|
+
reflect: true,
|
|
18
|
+
consolidate: true,
|
|
19
|
+
bank_scope: true,
|
|
20
|
+
knowledge_pages: true,
|
|
21
|
+
initiatives: true,
|
|
22
|
+
ingest_status: true,
|
|
23
|
+
},
|
|
24
|
+
mem0: { retain: true, recall: true, reflect: true, consolidate: false, bank_scope: true, ingest_status: true },
|
|
14
25
|
cognee: { retain: true, recall: true, reflect: true, consolidate: true, bank_scope: true },
|
|
15
26
|
};
|
|
16
27
|
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/** Hook side of the context store contract (docs/context-store.md). */
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
/** Marker in the installed smart-compact command body; survives command expansion. */
|
|
6
|
+
export const SMART_COMPACT_MARKER = "openmem:smart-compact";
|
|
7
|
+
/** Prompt that `/smart-compact` sends in every agent (Claude Code command file, OpenCode 2 command). */
|
|
8
|
+
export const SMART_COMPACT_BODY = `<!-- ${SMART_COMPACT_MARKER} -->
|
|
9
|
+
OpenMem will trim this session's earlier context on the next request. Reply with one short line acknowledging this; do not summarize the conversation. After the trim, use \`smart_compact_search\` with this session's id to look up anything earlier.`;
|
|
10
|
+
/** Claude Code command file (`~/.claude/commands/smart-compact.md`): frontmatter plus SMART_COMPACT_BODY. */
|
|
11
|
+
export const SMART_COMPACT_COMMAND = `---
|
|
12
|
+
description: Trim this session's context on the next request (OpenMem)
|
|
13
|
+
---
|
|
14
|
+
${SMART_COMPACT_BODY}
|
|
15
|
+
`;
|
|
16
|
+
const SMART_COMPACT_PREFIX = /^\s*\/smart-compact(?:\s|$)/;
|
|
17
|
+
const SMART_COMPACT_TAG = "<command-name>/smart-compact</command-name>";
|
|
18
|
+
/** ASCII whitespace only, so the hooks and the proxy trim the same characters (session ids, OPENMEM_STATE_DIR). */
|
|
19
|
+
const ASCII_TRIM_RE = /^[ \t\n\v\f\r]+|[ \t\n\v\f\r]+$/g;
|
|
20
|
+
const SID_UNSAFE_RE = /[^A-Za-z0-9._-]/gu;
|
|
21
|
+
|
|
22
|
+
/** `$OPENMEM_STATE_DIR/context` (value trimmed), default `~/.local/share/openmem/context`. */
|
|
23
|
+
export function contextRoot(home, env = process.env) {
|
|
24
|
+
const state = String(env.OPENMEM_STATE_DIR || "").replace(ASCII_TRIM_RE, "") || path.join(home, ".local", "share", "openmem");
|
|
25
|
+
return path.join(state, "context");
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Contract sanitizer (docs/context-store.md): trim surrounding ASCII whitespace, replace every character
|
|
30
|
+
* outside `[A-Za-z0-9._-]` with `_`, throw on an empty result.
|
|
31
|
+
*/
|
|
32
|
+
export function sanitizeSessionId(sessionId) {
|
|
33
|
+
const sid = String(sessionId ?? "").replace(ASCII_TRIM_RE, "").replace(SID_UNSAFE_RE, "_");
|
|
34
|
+
if (!sid) throw new Error("empty session id");
|
|
35
|
+
return sid;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function sessionsDir(home, env) {
|
|
39
|
+
const root = contextRoot(home, env);
|
|
40
|
+
const dir = path.join(root, "sessions");
|
|
41
|
+
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
42
|
+
fs.chmodSync(root, 0o700);
|
|
43
|
+
fs.chmodSync(dir, 0o700);
|
|
44
|
+
return dir;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function writePrivate(file, text) {
|
|
48
|
+
const temporary = `${file}.${process.pid}.tmp`;
|
|
49
|
+
fs.writeFileSync(temporary, text, { mode: 0o600 });
|
|
50
|
+
fs.renameSync(temporary, file);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Write `sessions/<sid>.json`. Returns the path, or null without a session id. */
|
|
54
|
+
export function registerSession({ home, env, sessionId, agent, cwd, bank, now = new Date() }) {
|
|
55
|
+
if (!sessionId) return null;
|
|
56
|
+
const sid = sanitizeSessionId(sessionId);
|
|
57
|
+
const file = path.join(sessionsDir(home, env), `${sid}.json`);
|
|
58
|
+
const registration = {
|
|
59
|
+
session_id: sid,
|
|
60
|
+
agent,
|
|
61
|
+
cwd,
|
|
62
|
+
bank,
|
|
63
|
+
registered_at: now.toISOString().replace(/\.\d{3}Z$/, "Z"),
|
|
64
|
+
};
|
|
65
|
+
writePrivate(file, `${JSON.stringify(registration)}\n`);
|
|
66
|
+
return file;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Write the empty `sessions/<sid>.force` flag. Returns the path, or null without a session id. */
|
|
70
|
+
export function writeForceFlag({ home, env, sessionId }) {
|
|
71
|
+
if (!sessionId) return null;
|
|
72
|
+
const file = path.join(sessionsDir(home, env), `${sanitizeSessionId(sessionId)}.force`);
|
|
73
|
+
writePrivate(file, "");
|
|
74
|
+
return file;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** True for `/smart-compact …`, Claude Code's command tag, or the expanded command body. */
|
|
78
|
+
export function isSmartCompactPrompt(prompt) {
|
|
79
|
+
const text = String(prompt || "");
|
|
80
|
+
return SMART_COMPACT_PREFIX.test(text) || text.includes(SMART_COMPACT_TAG) || text.includes(SMART_COMPACT_MARKER);
|
|
81
|
+
}
|