+1
-1
@@ -9,2 +9,2 @@ /** | ||
| */ | ||
| export const VERSION = "0.11.0"; | ||
| export const VERSION = "0.11.1"; |
+1
-1
| { | ||
| "name": "jamgate", | ||
| "version": "0.11.0", | ||
| "version": "0.11.1", | ||
| "mcpName": "io.github.amirj4m/jamgate", | ||
@@ -5,0 +5,0 @@ "description": "A neutral, cross-agent memory quality gate for AI agents, delivered as an MCP server — a gate, not a store.", |
+187
-139
@@ -7,9 +7,13 @@ # Jamgate | ||
| > A neutral memory quality-gate for AI agents — **a gate, not a store.** One shared | ||
| > memory of you — who you are, how you're doing, what you're working on — that every AI | ||
| > agent reads from and writes to, kept honest at write time. Local-first, no cloud calls, | ||
| > one dependency. | ||
| > Every AI tool I use keeps its own memory, so I kept re-introducing myself to all of them. | ||
| > Jamgate is one memory file on my machine that any MCP client can read and write, with a | ||
| > quality gate in front deciding what actually gets written. It runs locally and has one | ||
| > runtime dependency. | ||
| One command wires Jamgate into every MCP client on your machine: | ||
| I built it for myself and I'm the only person who has used it in anger, which is worth | ||
| knowing before you read the rest. [What it can't do](#honest-limits) is a section, not a | ||
| footnote. | ||
| One command wires it into every MCP client on your machine: | ||
| ```bash | ||
@@ -22,16 +26,15 @@ npx jamgate setup | ||
| ## The problem: memory quality, not storage | ||
| ## Why a gate and not just a store | ||
| You are one person, but every AI you use is a separate island. You design with one, | ||
| research with another, code with a third — and none of them know what the others know, | ||
| so you re-explain "what I'm working on" every time. | ||
| Sharing memory between agents turns out to be the easy half. I had a working shared store | ||
| early on and the problem it created was worse than the one it solved: within a week it was | ||
| full of "jam is on a call", the same fact three times in slightly different words, and a | ||
| stale preference from a month earlier being handed to an agent as though it were current. | ||
| The tools that try to fix this mostly **store everything**, so shared memory bloats with | ||
| junk: one production audit of a leading memory system found **97.8% of its stored entries | ||
| were junk** ([source](https://github.com/mem0ai/mem0/issues/4573)) — duplicates, trivia, | ||
| one-off chatter, stale states. Sharing memory is the easy part. Keeping the shared memory | ||
| *clean and current* is the unsolved part. | ||
| I'm not the only one. A production audit of one leading memory system found 97.8% of its | ||
| stored entries were junk — duplicates, trivia, one-off chatter, dead states | ||
| ([issue #4573](https://github.com/mem0ai/mem0/issues/4573)). If you share memory across | ||
| agents without filtering it, all you have built is a faster way to spread junk. | ||
| Jamgate sits in the **write path** and decides what deserves to be remembered, before it | ||
| is stored: | ||
| So Jamgate sits in the write path and decides what gets stored: | ||
@@ -47,13 +50,8 @@ ``` | ||
| └──────────────────────────────────┘ └──────────────────────────────────────┘ | ||
| everything piles up, 98% junk small, current, trustworthy | ||
| everything piles up, 98% junk small, and still true | ||
| ``` | ||
| ## The idea | ||
| It runs as an [MCP](https://modelcontextprotocol.io) server, so any MCP client (Claude Code, | ||
| Claude Desktop, Cursor, and seven others) talks to the same memory file on your machine. | ||
| **Jamgate is one shared memory of you that every agent plugs into — kept honest by a | ||
| quality gate.** It runs as an [MCP](https://modelcontextprotocol.io) server, so any | ||
| MCP-capable agent (Claude Code, Claude Desktop, Cursor, …) connects to the *same* memory | ||
| on your machine. Because it filters at write time, that memory stays small, accurate, and | ||
| contradiction-free instead of bloating with junk. | ||
| ``` | ||
@@ -64,6 +62,6 @@ Agent → [ Jamgate quality gate ] → local store (~/.jamgate/memory.json) | ||
| ## What it does — the gate layers | ||
| ## The gate layers | ||
| A memory is kept only if it is **durable** (still true after this session) and would | ||
| **change a future answer**. The gate is a hybrid pipeline, cheapest checks first: | ||
| A memory is kept if it is still true after this session and would change a future answer. | ||
| Cheapest checks run first: | ||
@@ -76,3 +74,3 @@ | Layer | What it does | | ||
| | **Transience filter** | Statements pinned to this instant ("it's raining right now") are refused unless you type them as `state`, where a short TTL ages them out on their own. | | ||
| | **Agent salience** | Uses the calling agent's own understanding as the main "is this worth remembering?" filter — no extra LLM call of our own. | | ||
| | **Agent salience** | Uses the calling agent's own understanding as the main "is this worth remembering?" filter — no second LLM call of its own. | | ||
| | **Exact dedup** | Identical facts are never stored twice. | | ||
@@ -85,9 +83,66 @@ | **Time-aware supersession** | Every memory is a timestamped event; a newer fact retires an older one on the same `subject` by recency — no contradiction pile-up, and it never throws your own stale words back at you. | | ||
| Every rejection comes back with a reason the calling agent can act on — the agent is the | ||
| only party able to correct the call, and a bare "rejected" just teaches it to work around | ||
| the gate. | ||
| Every rejection comes back with a reason the calling agent can act on. This matters more than | ||
| it sounds: the agent is the only party in a position to fix the call, and a bare "rejected" | ||
| just teaches it to retry with slightly different wording until something sticks. | ||
| Everything is taggable, expirable, and deletable — you always see and control what's | ||
| remembered. | ||
| Note what is *not* in that table: nothing here understands your memory. These are rules, | ||
| regexes and cosine thresholds. See [Honest limits](#honest-limits). | ||
| ## Honest limits | ||
| Read this before the feature list, not after it. Everything below is measured or observed, | ||
| and none of it is fixed yet. | ||
| **Recall often puts the wrong memory first.** On my own store — 12 real memories, 17 queries | ||
| I wrote — the right memory came back at rank 1 in **10 of 17** cases, and appeared anywhere | ||
| in the top 5 in 13. Turning on the optional embeddings *used* to make this worse than leaving | ||
| them off; that's fixed, but "the answer is in there somewhere" is still an accurate | ||
| description of recall on a store of any size. This is the weakest part of the project and | ||
| the thing I'd fix next. | ||
| **Nobody outside me has installed it.** Twenty-two releases, ten supported clients, one user. | ||
| I've simulated a cold install (fresh `HOME`, empty npm cache, published package rather than | ||
| my working copy) and it held up, but simulation is not a stranger on their own machine. | ||
| **macOS and Windows have never actually been run.** Their config paths are unit-tested and | ||
| CI is Linux-only. If you are on a Mac and `jamgate setup` writes to the wrong place, you are | ||
| the first person to find out. Please open an issue. | ||
| **Embeddings only attach when a memory is saved.** Install the optional semantic package | ||
| today and every memory you saved before that stays invisible to semantic recall until you | ||
| save it again. There is no `reindex` command. This is a straightforward gap, not a hard | ||
| problem, and it isn't done. | ||
| **"Store-agnostic" is a seam, not a feature.** Everything above `src/store/` depends on a | ||
| `MemoryStore` interface rather than a concrete backend, which is a real design property you | ||
| can check in the source. But the bundled file store is the only implementation. There is no | ||
| mem0 adapter, no Graphiti adapter, and **no way for you to point Jamgate at your own store | ||
| today.** If a future write-up of mine implies otherwise, this line is the correct one. | ||
| **The quality judgments are rules and numbers, not understanding.** The gate cannot tell that | ||
| "moved to Berlin last spring" and "no longer lives in Athens" are the same event. It matches | ||
| subjects, compares cosines against thresholds I set from measurements, and applies regexes. | ||
| It is genuinely good at the mechanical cases — exact duplicates, credentials, recency on a | ||
| shared subject — and blind to anything requiring judgment. A thin LLM classifier for the | ||
| ambiguous cases exists on a branch and is not in this release. | ||
| **One JSON file, read whole on every operation.** At my 66 records that is free. There is no | ||
| index and no pagination, so at some size it stops being free; I don't know what that size is | ||
| because I've never had a store big enough to find out. | ||
| **Semantic search is English-only.** The bundled model is `all-MiniLM-L6-v2`. On other | ||
| scripts its similarity degenerates into "is this the same language" (the Greek for *bicycle* | ||
| scored 0.62 against an unrelated Greek memory), so non-Latin text is deliberately not | ||
| embedded at all and falls back to lexical matching, which does work in every script. | ||
| **A memory is text, and recall puts it into your agent's context.** The gate decides whether | ||
| something is worth keeping, not whether it is safe to act on. If a memory contains | ||
| instructions, those words come back verbatim on the next recall, in a place the model reads. | ||
| That is true of every memory system. Jamgate narrows the surface — it never scrapes screens, | ||
| never mines chat logs, refuses credentials, and only writes on an explicit `save_memory` | ||
| call — but it cannot make text inert. Treat the store as trusted input and look at what goes | ||
| in; `jamgate export` prints all of it. | ||
| Remote mode has its own set of limits, listed under [Remote mode](#remote-mode-limits). | ||
| ## Quick start | ||
@@ -214,3 +269,3 @@ | ||
| each entry shape is verified against the vendor's official docs. Agents whose config lives in a | ||
| non-JSON format we can't safely round-trip (TOML / YAML) are listed as **manual** with the | ||
| non-JSON format I can't safely round-trip (TOML / YAML) are listed as **manual** with the | ||
| one-liner to add yourself. | ||
@@ -234,3 +289,3 @@ | ||
| ¹ **Manual** — these use TOML/YAML; rather than risk mangling comments/formatting we don't | ||
| ¹ **Manual** — these use TOML/YAML; rather than risk mangling comments or formatting I don't | ||
| auto-edit them. Add Jamgate by hand: **Codex CLI** → | ||
@@ -280,3 +335,3 @@ `[mcp_servers.jamgate]` with `command = "npx"` and `args = ["jamgate"]` in `~/.codex/config.toml`; | ||
| for every agent the `skills` CLI finds on your machine (it wired 17, including Cursor, Copilot | ||
| and Claude Code, on the machine we tested): | ||
| and Claude Code, on the machine I tested it on): | ||
@@ -413,6 +468,7 @@ ```bash | ||
| You've already told another AI product who you are. Starting from zero on a new one is the worst | ||
| part of switching. `jamgate import --from <vendor>` takes the memory list you exported from | ||
| **Claude** or **ChatGPT** and replays it through the same gate a live save goes through — so you | ||
| get day-one memory instead of a cold start, without smuggling in duplicates or junk. | ||
| If you've been using Claude or ChatGPT for a while, they already know things about you, and | ||
| starting from an empty file is the annoying part of trying anything new. | ||
| `jamgate import --from <vendor>` takes the memory list you copy out of either one and replays | ||
| it through the same gate a live save goes through, so duplicates and junk don't come along | ||
| with it. | ||
@@ -441,14 +497,14 @@ ```bash | ||
| | --- | --- | --- | | ||
| | **Claude** | Settings → Capabilities → **"View and edit your memory"** | Copy the list (or ask Claude: *"Write out your memories of me verbatim, exactly as they appear in your memory"*) into a `.md`/`.txt` file. Anthropic's own memory-transfer format is `[date saved, if available] - memory content` — exactly what we parse. | | ||
| | **Claude** | Settings → Capabilities → **"View and edit your memory"** | Copy the list (or ask Claude: *"Write out your memories of me verbatim, exactly as they appear in your memory"*) into a `.md`/`.txt` file. Anthropic's own memory-transfer format is `[date saved, if available] - memory content` — which is what the parser expects. | | ||
| | **ChatGPT** | Settings → Personalization → Memory → **"Manage memories"** | Select the list and copy it into a `.md`/`.txt` file. A trailing `(saved 2026-01-09)` is understood. | | ||
| Dates are optional. Bullets (`-`, `*`, `1.`), markdown headings, horizontal rules and code fences | ||
| are handled. If a future export *does* ship structured memory JSON, we'll read that too — | ||
| best-effort, looking for entries under memory-ish keys — and we accept the `.zip` or the extracted | ||
| are handled. If a future export *does* ship structured memory JSON, it reads that too — | ||
| best-effort, looking for entries under memory-ish keys — and it accepts the `.zip` or the extracted | ||
| folder directly and pick the memory-shaped file out of it. | ||
| ### What we read, and what we deliberately don't | ||
| ### What it reads, and what it deliberately doesn't | ||
| - ✅ **Curated memory / profile entries only** — the list you reviewed and kept in the source app. | ||
| - ❌ **We never mine your conversation logs.** `conversations.json`, `chat.html`, | ||
| - ❌ **It never mines your conversation logs.** `conversations.json`, `chat.html`, | ||
| `message_feedback.json` and friends are recognized by name, skipped, and reported as skipped. | ||
@@ -458,3 +514,3 @@ Inferring facts about you from raw chat history is exactly the low-consent behavior this project | ||
| message telling you where your memories actually live. | ||
| - ❌ **We never fetch anything from a vendor account.** You download your own export, yourself. | ||
| - ❌ **It never fetches anything from a vendor account.** You download your own export, yourself. | ||
| Jamgate reads a local file and nothing else. | ||
@@ -467,3 +523,3 @@ | ||
| - **source `user-confirmed`** — you curated these in the source product. Not `user-explicit` | ||
| (you didn't dictate them to Jamgate), not `agent-inferred` (they aren't our guess). | ||
| (you didn't dictate them to Jamgate), not `agent-inferred` (they aren't a guess by this tool). | ||
| - **type inferred conservatively** — `preference` or `identity` only when the wording is obvious; | ||
@@ -493,3 +549,3 @@ otherwise left **untyped**. A wrong type is worse than no type. | ||
| - **You pay the platform directly — we host nothing.** A tiny always-on instance with a small | ||
| - **You pay the platform directly. I host nothing.** A tiny always-on instance with a small | ||
| persistent disk runs roughly **$5–7/month** on Railway or Render. That bill is between you and | ||
@@ -502,3 +558,3 @@ the platform; Jamgate takes no cut and runs no cloud. | ||
| you. Treat it like a password. There are no per-user accounts (one instance = one person; see | ||
| [Honest limits](#honest-limits-read-this)). | ||
| [Honest limits](#remote-mode-limits)). | ||
@@ -561,3 +617,3 @@ ### Deploy to Render (works today) | ||
| unchanged. Whether it's your own memory or a whole team's, the rule is one instance per person | ||
| (see [Honest limits](#honest-limits-read-this)). | ||
| (see [Honest limits](#remote-mode-limits)). | ||
@@ -775,24 +831,17 @@ ### Run it | ||
| ### Honest limits (read this) | ||
| ### Remote mode limits | ||
| - **Whoever holds the token holds the memory.** There are no per-user accounts — the token *is* | ||
| These are on top of the [general limits](#honest-limits) above. | ||
| - **Whoever holds the token holds the memory.** There are no per-user accounts; the token *is* | ||
| the authentication. Treat it like a password: strong, secret, rotated on suspicion. | ||
| - **One instance = one human.** Jamgate's memory is *of one person*, by design. There is no | ||
| multi-user tenancy, no per-identity isolation or access control. That's a deliberate scope | ||
| choice, not a missing feature — it keeps the security surface to a single secret and a single | ||
| store. If several people each want a memory, run one instance per person. | ||
| - **Concurrency is single-process.** Multiple agents hitting one instance at once is safe (writes | ||
| are serialized by a lock and re-read before write). This holds for one Jamgate process on one | ||
| host; it is not a distributed multi-node store. | ||
| - **No TLS in the box.** If you skip the reverse proxy, you're sending a bearer token in the | ||
| - **One instance is one human.** There is no multi-user tenancy, no per-identity isolation, no | ||
| access control. That was a scope decision, and it keeps the security surface down to one | ||
| secret and one store, but if three people each want a memory you run three instances. | ||
| - **Concurrency is single-process.** Several agents hitting one instance at once is safe — | ||
| writes take a lock and re-read before writing. That holds for one process on one host. It is | ||
| not a distributed store and will not survive being run twice against the same file. | ||
| - **No TLS in the box.** Skip the reverse proxy and you are sending a bearer token in the | ||
| clear. Don't. | ||
| - **A memory is text, and recall puts it in your agent's context.** The gate decides *whether* | ||
| something is worth keeping, not whether it is safe to act on. If a memory contains | ||
| instructions — because you saved a page that contained them, or an agent inferred a fact | ||
| from an untrusted source — those words come back verbatim on the next recall, in a place the | ||
| model reads. This is inherent to every memory system; Jamgate reduces the surface (it never | ||
| scrapes screens, never mines chat logs, refuses credentials, and requires an explicit | ||
| `save_memory` call) but it cannot make text inert. Treat your memory store as trusted input | ||
| and review what goes in — `jamgate export` prints all of it. | ||
| - **One memory is one fact, up to 32 KB.** Larger saves are refused rather than truncated. If | ||
| - **One memory is one fact, up to 32 KB.** Bigger saves are refused rather than truncated. If | ||
| you want a document remembered, save the conclusion. | ||
@@ -802,82 +851,78 @@ | ||
| Jamgate is deliberately small and opinionated. It is **not** trying to be a hosted memory | ||
| platform or a knowledge graph — it's the write-time quality layer those systems are | ||
| weakest at, packaged as a drop-in local MCP server. | ||
| There are no benchmark numbers here. This category has had two of them retracted in public | ||
| and I am not adding a third from a project with one user. What follows is a capability | ||
| comparison, and the rows where Jamgate loses are the ones worth reading. | ||
| | | **Jamgate** | **Mem0 / OpenMemory** | **Zep / Graphiti** | | ||
| | --- | --- | --- | --- | | ||
| | Core model | Write-time quality **gate** over a flat store | LLM-extracted memory layer | Temporal knowledge **graph** | | ||
| | Where memory lives | Local file on your machine | Hosted platform or self-hosted store | Graph server (self-hosted or cloud) | | ||
| | Their strength | — | Rich extraction, broad SDKs/integrations, scale | Powerful entity/relationship & temporal modeling | | ||
| | Gate **before** write | ✅ core design | Partial (dedup/update) | Partial | | ||
| | Source-trust hierarchy | ✅ | — | — | | ||
| | Refers conflicts back to you | ✅ | — | — | | ||
| | LLM calls of its own | ❌ none | ✅ required | ✅ required | | ||
| | Dependencies / infra | 1 dep, no server | SDK + service/DB | Graph DB + service | | ||
| | Best for | Keeping one shared personal memory clean, locally | Full-featured app-scale memory | Complex relational/temporal reasoning | | ||
| | Core model | Rule-based gate in front of a flat file | LLM-extracted memory layer | Temporal knowledge graph | | ||
| | Where memory lives | A JSON file on your machine | Hosted platform or self-hosted store | Graph server (self-hosted or cloud) | | ||
| | Gate before write | Core design | Partial (dedup/update) | Partial | | ||
| | Source-trust hierarchy | Yes | Not that I can find | Not that I can find | | ||
| | Refers conflicts back to you | Yes | No | No | | ||
| | LLM calls of its own | None | Required | Required | | ||
| | Dependencies / infra | 1 runtime dep, no server | SDK + service/DB | Graph DB + service | | ||
| | **Retrieval quality** | **Weak.** Fuzzy lexical + optional local embeddings; 10/17 top-1 on my own store | **Better.** Real vector retrieval, reranking, tuned over many deployments | **Better.** Graph traversal plus vector search | | ||
| | **Understands what a memory means** | **No.** Regexes, subject matching, cosine thresholds | **Yes.** LLM extraction is the whole design | **Yes.** Entity and relationship extraction | | ||
| | **Entity / relationship reasoning** | **None.** Flat records with a `subject` string | Some | **This is what it is for** | | ||
| | **Scale** | **Untested past ~100 records.** One file, read whole, no index | Production deployments | Production deployments | | ||
| | **Multi-user / teams** | **No.** One instance, one person, one token | Yes | Yes | | ||
| | **Language support** | Lexical recall in any script; semantic is **English-only** | Multilingual models | Multilingual models | | ||
| | **SDKs** | MCP and a small REST API | **Python, TS, and more** | **Python, TS, and more** | | ||
| | **Maturity** | **One developer, one user, seventeen releases** | Funded team, wide adoption | Funded team, wide adoption | | ||
| | Best for | One person's cross-agent memory, kept small and current, on their own disk | Application-scale memory with real retrieval | Relationship and temporal reasoning | | ||
| The Jamgate column is verified by the test suite. The other two columns are read from those | ||
| projects' own public documentation as of **August 2026** and describe their default behaviour, | ||
| not the ceiling of what they can be configured to do — if we have a row wrong, open an issue | ||
| and we'll fix it. | ||
| The Jamgate column is checked by the test suite and by the measurements in | ||
| [`DECISIONS.md`](./DECISIONS.md). The other two are read from those projects' public | ||
| documentation as of **August 2026** and describe default behaviour, not the ceiling of what | ||
| they can be configured to do. If a row is wrong, open an issue and I will fix it — including | ||
| the ones that are unflattering to them. | ||
| Mem0, OpenMemory, Zep, and Graphiti are capable systems built for different goals; if you | ||
| need managed scale or graph reasoning, they're the right tool. Jamgate's bet is that for | ||
| *personal* cross-agent memory, the hard part is quality at write time — and that it should | ||
| be local, free, and one command to install. | ||
| Short version: if you want the best retrieval, use Mem0. If your memory is really a graph of | ||
| people and events, use Zep. Jamgate is worth a look if what you want is one small memory of | ||
| yourself that several agents share, on a disk you own, and you care more about it staying | ||
| clean than about it being clever. | ||
| ## Privacy | ||
| - **Everything is local.** The memory store, the gate, and (if enabled) the embedding | ||
| model all run on your machine. **Your memories are never sent anywhere** — Jamgate makes | ||
| no outbound request carrying your data, has no telemetry, and talks to no cloud AI. | ||
| The one network access in the whole product is the optional embedding model's **first-run | ||
| download** from Hugging Face (~23 MB, cached, and only if you installed that optional | ||
| package); it downloads weights, it does not upload text. `npx` itself fetching the package | ||
| from npm is the other, and both stop after install. | ||
| - **The decision log is local too.** Every gate decision (saved / duplicate / superseded / | ||
| conflict / possible_duplicate / rejected, with its reason) is appended to a strictly | ||
| local, size-capped JSONL file that rotates automatically and **never leaves your | ||
| machine**. It exists to collect real usage data for a future local quality classifier. | ||
| It lives **next to the store**: `gate.log` in the same directory as `JAMGATE_STORE` when | ||
| that is set, otherwise `~/.jamgate/gate.log`. `JAMGATE_GATE_LOG` overrides the path | ||
| outright, and `JAMGATE_GATE_LOG=off` disables logging. (Following the store is what makes | ||
| the log writable under a hardened systemd unit with `ProtectHome=true` — see D-037.) | ||
| - **Nothing leaves the machine** — no telemetry, no accounts, no keys. | ||
| Your memories are never sent anywhere. There is no outbound request carrying your data, no | ||
| telemetry, no accounts, no keys, and nothing talks to a cloud model. The store, the gate and | ||
| the embedding model all run on your machine. | ||
| Two things do touch the network, both of them downloads and neither carrying your text: `npx` | ||
| fetching the package from npm, and — only if you installed the optional semantic package — the | ||
| embedding model's first-run download from Hugging Face (~23 MB, then cached). Both stop after | ||
| install. | ||
| There is also a local decision log. Every gate verdict (saved, duplicate, superseded, | ||
| conflict, possible_duplicate, rejected) is appended to a size-capped JSONL file that rotates | ||
| on its own and never leaves the machine. I keep it because a future local classifier will need | ||
| real examples to be any good. It lives beside the store — `gate.log` in the same directory as | ||
| `JAMGATE_STORE`, or `~/.jamgate/gate.log`. `JAMGATE_GATE_LOG` overrides the path and | ||
| `JAMGATE_GATE_LOG=off` turns it off. It holds the memory text, so if that bothers you, turn it | ||
| off. (It follows the store rather than the home directory so it stays writable under a | ||
| hardened systemd unit with `ProtectHome=true`; see D-037.) | ||
| ## Status | ||
| Early but real, and now installable with one command. The MVP core, robustness, | ||
| intelligence, and optional remote layers all work today (see [`CHANGELOG.md`](./CHANGELOG.md) | ||
| for the full scope): | ||
| I use this daily, it holds my real memory, and it has not lost a record. That is the strongest | ||
| claim I can make honestly. It is not battle-tested, because there has only ever been one | ||
| battle. | ||
| - **Gate core** — rule pre-filter, exact dedup, time-aware supersession, source-trust | ||
| conflict guard, over a local flat-file store. | ||
| - **Robustness** — atomic durable writes, type-based expiry, concurrency-safe locking, | ||
| automatic schema migration. | ||
| - **Intelligence** — trusted client provenance, fuzzy recall, optional local embeddings | ||
| with graceful fallback, auto-subject derivation, local decision log. | ||
| - **Remote mode** *(optional)* — self-hosted Streamable HTTP transport with bearer-token | ||
| auth, so one instance can serve all of your agents (phone, browser, laptop) from one | ||
| shared memory. stdio stays the default. A plain **REST API** (`/v1/memory`) runs on the | ||
| same port behind the same token, for app backends that don't speak MCP. | ||
| - **Namespaces (scopes)** *(optional)* — attach a `scope` to keep several isolated memories | ||
| in one instance; the whole gate applies per scope. Omit it for the default single-tenant | ||
| behaviour. | ||
| - **One-click install** — `npx jamgate setup` wires every detected client (Claude Code, | ||
| Claude Desktop, Cursor, Windsurf, Gemini CLI, VS Code / Copilot, Cline, Roo Code, OpenCode, | ||
| Zed) in one idempotent, backup-first command, plus a Cursor deeplink and a Claude Desktop | ||
| `.mcpb` bundle. | ||
| - **Deploy your own** *(no terminal)* — a `Dockerfile`, a Render blueprint, and a Railway | ||
| config so a non-technical user can click a button, log into a platform, and get their own | ||
| hosted instance with a generated token and a persistent disk. We host nothing. | ||
| - **Bring your memory with you** — `jamgate import --from claude|chatgpt` replays another | ||
| product's memory export through the gate, so a new setup starts with day-one memory. Curated | ||
| entries only; conversation logs are never mined. | ||
| What works today: the gate itself (rule pre-filter, credential refusal, exact dedup, | ||
| time-aware supersession, the source-trust conflict guard), atomic durable writes with locking | ||
| and schema migration, fuzzy recall in any script with optional local embeddings on top, the | ||
| `setup` wizard for ten clients, and `import --from claude|chatgpt` for moving your memory off | ||
| another product. Optional and less exercised: remote mode over HTTP with a bearer token and | ||
| MCP OAuth, a small REST API on the same port, and namespaces. Those last three work and are | ||
| tested, but I am the only person who has ever pointed anything at them — the local stdio path | ||
| is the one that gets used every day. | ||
| Verified end-to-end over the MCP protocol (both stdio and HTTP) and covered by an automated | ||
| test suite (460+ tests) on Node 20.x and 22.x. Next: a thin classifier for ambiguous cases | ||
| (trained on the local decision log) and multi-device sync (see [`DECISIONS.md`](./DECISIONS.md)). | ||
| **Goal: impact, not profit — open-source (MIT), built in the open.** | ||
| 491 tests on Node 20 and 22, run against a real MCP handshake on both transports. The full | ||
| history is in [`CHANGELOG.md`](./CHANGELOG.md), and every non-obvious decision, including the | ||
| ones I got wrong and reversed, is written up in [`DECISIONS.md`](./DECISIONS.md). | ||
| Next: better recall ranking, a `reindex` command, and a thin LLM classifier for the ambiguous | ||
| cases the rules cannot judge. MIT, and I am not trying to make money from it. | ||
| ## Development | ||
@@ -895,9 +940,12 @@ | ||
| This is an impact project. The most valuable contributions are around **write-time | ||
| quality** (selective capture, dedup, contradiction handling, expiry) — the part the whole | ||
| field is weakest at. See [`AGENTS.md`](./AGENTS.md) to get oriented, then | ||
| [`RULES.md`](./RULES.md). | ||
| The most useful thing you can do right now is install it and tell me what broke, especially | ||
| on macOS or Windows, which I have never run. After that: recall ranking, which is the part | ||
| I'm least happy with. | ||
| [`AGENTS.md`](./AGENTS.md) gets you oriented and [`RULES.md`](./RULES.md) has the detail. | ||
| Both are written for an AI agent as much as for a person, since most of this was built with | ||
| one. | ||
| ## License | ||
| [MIT](./LICENSE) |
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
335659
0.94%933
5.42%