Skip to main content
Glama
README.md
# owner-memory

**One memory about you for every AI agent.** Tell Claude once where your documents live, who
Bob is and what your projects are about — every agent you use knows it from then on: Claude Code
in any project, Claude Desktop, a voice assistant, your own scripts.

> «reply to Bob in Telegram, he writes about the TON purchase» → the agent already knows which
> project "TON purchase" belongs to, where its code and server are, and who Bob is.

[Русская версия](README.ru.md)

## What it is

```
            ┌────────────────────────────────────────┐
            │  Postgres + pgvector                   │  your data, on your machine
            └───────────────────┬────────────────────┘
            ┌───────────────────┴────────────────────┐
            │  owner-memory service  127.0.0.1:8750  │  HTTP API, Bearer token
            └──────┬─────────────────┬───────────────┘
        ┌──────────┴──────┐  ┌───────┴────────────────┐
        │ MCP server      │  │ Claude Code plugin     │
        │ `memory`        │  │ (hooks)                │
        └──────┬──────────┘  └───────┬────────────────┘
   Claude Code, Claude Desktop,      cards of what a message is about
   any MCP-capable agent             arrive in context by themselves
```

- **Entities** — you (`me`), `project`, `person`, `place` (folders, cities), `channel`
  (Telegram, e-mail), `thing` (devices, a car), `topic` — with **aliases** (words people use
  about them) and **relations** ("Bob works_on Shop").
- **Facts** — about an entity or about you in general, with **history**: a new fact can
  *supersede* an old one ("moved to Berlin") instead of erasing it.
- **Lookup** — a free phrase resolves to the entities it names (aliases match with your
  language's morphology or word for word) plus the facts that fit it.
- **Search by meaning** — a small local multilingual model (~220 MB, CPU, nothing leaves your
  machine) embeds every message, fact and entity; results by words and by meaning are fused,
  so «когда созвон?» finds the message about the webinar.

## Install — one command

Needs Docker (or your own Postgres, see below) and, for the agent side, Claude Code.

```bash
curl -fsSL https://raw.githubusercontent.com/AlexB00M/owner-memory/main/install.sh | bash -s -- --lang english
```

It starts Postgres + the service in Docker (listening on 127.0.0.1 only), creates your token in
`~/.config/owner-memory/token`, installs the `owner-memory` tools with [uv](https://docs.astral.sh/uv),
registers the MCP server `memory` in Claude Code and Claude Desktop, and installs the Claude Code
plugin. Then fill it:

```bash
owner-memory status
owner-memory bootstrap                 # scans ~/Projects and your folders into a DRAFT
$EDITOR ~/.config/owner-memory/draft.json
owner-memory bootstrap --apply
```

…or just talk: "my documents are in ~/Documents/Personal", "Bob is my partner on Shop" — the
plugin nudges Claude to save lasting things.

### Options

| option | meaning |
|---|---|
| `--lang russian` | Postgres text search config for morphology (`english`, `russian`, `german`, …; default `simple` — no stemming). Fixed when the database is created |
| `--native --dsn postgresql://user@host:5432/db` | no Docker: your own Postgres with the `vector` extension created; the service runs as a login agent (launchd / systemd `--user`) |
| `--port 8750` | service port (clients then need `OWNER_MEMORY_URL`) |
| `--with SPEC` | extra package for the MCP server (see *Voice commands*) |
| `--no-embed` | no local model: search by words only |
| `--no-ingest` | do not archive Claude Code sessions every 30 minutes |
| `--no-mcp`, `--no-plugin` | skip that part |

Remove: `./uninstall.sh` (data kept) or `./uninstall.sh --purge` (Docker data deleted).

## Use

**In Claude Code** nothing to do: the plugin shows your card at session start and the cards of
whatever a message names. Claude saves new facts with the MCP tools:

| tool | |
|---|---|
| `mem_lookup` | phrase → cards (path, server, relations, facts) + facts |
| `mem_entity`, `mem_entities` | one card / a list |
| `mem_entity_save` | create or extend an entity (summary, attrs, aliases); matches kind + exact name only |
| `mem_relate`, `mem_unrelate` | "src relation dst" |
| `mem_remember` | a fact, optionally `about` an entity, `supersedes` an older one |
| `mem_facts` | facts of an entity / kind / with history |
| `mem_conversations`, `mem_conversation_context` | search past conversations of every agent; the messages around a hit |
| `mem_forget`, `mem_entity_delete` | only on explicit request; `forget` refuses phrases shorter than 3 characters or matching more than 5 facts |

### Conversations

Every Claude Code session goes into the memory when it ends (and before its context is
compacted): your messages and the assistant's answers become searchable, and a cheap model
(`claude -p --model haiku`, your own subscription) writes a 5–10 line summary — what was
discussed, decided, proposed, left open — tagged with the projects it was about. Opened in a
project folder, a session starts with that project's card and its latest summaries; opened
anywhere else it is the assistant over everything: an overview of all your projects.
Decisions and ideas are saved as you go (`kind=decision` / `idea`).

The installer also archives every session each 30 minutes (`owner-memory ingest-claude --all
--summarize --idle 3600`: summaries only for sessions untouched for an hour), which catches
sessions the plugin never saw — SDK apps, older sessions, other tools.
Which sessions to take — `~/.config/owner-memory/ingest.json`:
`{"skip": ["~/.assistant/router"], "sources": {"~/.assistant": "assistant"}, "no_summary": []}`.
The summarizer command: `OWNER_MEMORY_SUMMARIZER` (it must read the prompt on stdin).

Vectors live in the same database (`embedding` columns, `message_chunks` for the pieces of long
messages): `pg_dump` moves them with everything else; the database remembers which model made
them, so a server with the same model recomputes nothing. `POST /v1/embed` gives other local
tools the same model's vectors (e.g. matching voice commands by meaning).

**Anything else** talks HTTP: `Authorization: Bearer $(cat ~/.config/owner-memory/token)`.

```bash
curl -s -H "Authorization: Bearer $(cat ~/.config/owner-memory/token)" \
  -d '{"query": "reply to Bob about the TON purchase"}' -H 'Content-Type: application/json' \
  http://127.0.0.1:8750/v1/lookup
```

The contract (pydantic models, `/v1/*`) is `owner_memory.contract`; `pip install owner-memory`
without extras installs only it, for clients.

### Languages and names

Morphology comes from Postgres (`--lang`). Stemmers mangle names, so aliases also match word
for word — in inflected languages store the case forms of names: `Вася, Васи, Васе, Васю`.

### Voice commands (optional)

If `jarvis-mcp` (the SDK of the Jarvis voice assistant) is installed next to the MCP server (`--with /path/to/jarvis-mcp`), the server also publishes fast voice
commands for the Jarvis voice assistant («что ты знаешь про …», «запомни, что …»). Without it
nothing depends on Jarvis.

## Privacy

Everything runs on your machine: the service binds to 127.0.0.1, the token file is `0600`, and
no data leaves unless you move the service yourself. Do not store passwords, tokens or card
numbers — store *where* things are, not the secrets themselves.

## Configuration

| variable | default | |
|---|---|---|
| `OWNER_MEMORY_URL` | `http://127.0.0.1:8750` | clients: where the service is |
| `OWNER_MEMORY_TOKEN_FILE` | `~/.config/owner-memory/token` | clients and the service |
| `OWNER_MEMORY_TOKEN` | — | the service: token value instead of the file (Docker, servers) |
| `OWNER_MEMORY_DSN` | `postgresql://owner_memory@127.0.0.1:5432/owner_memory` | the service |
| `OWNER_MEMORY_TS_CONFIG` | `simple` | the service: text search config of a NEW database |
| `OWNER_MEMORY_HOST` / `_PORT` | `127.0.0.1` / `8750` | the service |
| `OWNER_MEMORY_EMBED` | `1` | the service: `0` — no semantic search |
| `OWNER_MEMORY_EMBED_MODEL` | `sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2` | any 384-dim fastembed model; a new model re-embeds everything |
| `OWNER_MEMORY_MODELS_DIR` | `~/.cache/owner-memory/models` | where the model is downloaded |

## Development

```bash
uv sync --all-extras
uv run pytest            # service tests need Postgres+pgvector: OWNER_MEMORY_TEST_DSN
uv run ruff check . && uv run mypy src tests
```

MIT License.

Maintenance

ActivityMaintained
ResponsivenessNo issues