Sign In

jamgate

Package Overview
Dependencies
Maintainers
1
Versions
37
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

jamgate - npm Package Compare versions

Comparing version
0.11.0
to
0.11.1
+1
-1
dist/version.js

@@ -9,2 +9,2 @@ /**

*/
export const VERSION = "0.11.0";
export const VERSION = "0.11.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)