Metadata-Version: 2.4
Name: convo-mem
Version: 0.2.0
Summary: A memory bank distilled from coding-agent session history, served over MCP
Requires-Python: >=3.11
Description-Content-Type: text/markdown
Requires-Dist: PyYAML>=6
Requires-Dist: zstandard>=0.22
Provides-Extra: mcp
Requires-Dist: mcp>=1.2; extra == "mcp"

<!-- mcp-name: io.github.new-aige-codez/memtool -->

# convo-mem

One memory bank distilled from every coding agent's session history, served
over MCP.

`convo-mem` reads the transcripts your coding agents already write — Claude
Code, Codex and Gemini CLI, into a single bank — extracts the decisions,
failures, knowledge and open threads buried in them, and files each one as a
record that cites the exact turn it came from. The bank is plain Markdown on
disk — greppable, diffable, and readable without this tool.

One bank across agents is the point. The reason you rejected an approach in
Codex last week is a record you can still be stopped by in Claude Code today,
and every record carries the `agent` whose session it came from, so you can
tell which one you were talking to.

The CLI is the product. The MCP server and the skills are shells over it.

## Install

```bash
pip install convo-mem              # the pipeline
pip install "convo-mem[mcp]"       # ...plus the retrieval server
```

The command and the distribution are both `convo-mem`. The command used to be
`memtool`; the distribution never could be, because an unrelated package holds
`memtool` on PyPI along with the `memtool` import name, and sharing either
would collide in `site-packages`.

From a checkout, for development:

```bash
pip install -e ".[mcp]"
```

## Use

```bash
convo-mem status                 # what project, sessions and bank this dir resolves to
convo-mem search "postgres"      # which conversation was that? (no model call)
convo-mem search "postgres" --agent codex --session 1a2b3c4d
convo-mem init --dry-run         # price the run before it spends anything
convo-mem init                   # build a bank from session history
convo-mem init --resume          # continue an interrupted one from what is on disk
convo-mem usage                  # what the rolling 5h / 7d windows have actually cost
convo-mem lint                   # nightly sweep: revisit triggers, clustering, views
convo-mem verify --calibrate 20  # model triage of the review queue
convo-mem mcp                    # the MCP retrieval server (stdio; blocks)
convo-mem skills install         # put the six skills where your agent looks
convo-mem vault-init             # open the bank as an Obsidian vault, in place;
                                 #   then obsidian://open?path=<url-encoded bank path>
convo-mem obsidian link          # print that link again; writes nothing
convo-mem <command> --help
```

Every command derives its project from the current directory (the git root, or
the **main** repo when you are in a worktree) and its bank from
`<project>/memory`, prints what it resolved and where each value came from, and
accepts `--project PATH` to operate on another project. `.memconfig.yaml`
overrides any of it and is never required.

Work directories (`.memtool-init/`, `.memtool-verify/`, …), the stripped
transcript corpus and the chunk corpus live under the current directory.
`MEMTOOL_HOME` overrides that if you want them somewhere fixed.

## Sources

Three agents are read today, into one bank:

| agent | read from | override | exercised on real sessions |
|---|---|---|---|
| `claude_code` | `~/.claude/projects/<munged cwd>/*.jsonl` | `CLAUDE_CONFIG_DIR` | yes — 109 sessions across two projects |
| `codex` | `~/.codex/sessions/**/rollout-*.jsonl` | `CODEX_HOME` | yes — 83 rollouts, one project, end to end |
| `gemini` | `~/.gemini/tmp/<slug>/chats/*.json` | `GEMINI_CLI_HOME` | **not yet** — see below |

That last column is not decoration. `gemini` is implemented and tested, but
the only Gemini CLI session on the machine it was written on holds **7
records, all of them harness notices, and 0 conversational turns** — so the
reader has never yet been handed a real Gemini conversation to parse. Its
record shapes were ported from the installed 0.49.0 bundle's own source
rather than confirmed against parsed messages, and both on-disk shapes (the
legacy single JSON object and the current append-only JSONL with `$rewindTo`
replay) are covered by unit tests. Treat it as ready to try and worth
reporting on, not as proven the way the other two are.

`convo-mem status` lists every folder each adapter resolves for this project
and how many sessions are in it, so an agent you use but that shows `0
sessions` is visible rather than silently absent. Each record and each
manifest row carries the `agent` it came from; session ids are unique only
*within* an agent, so every agent but Claude Code gets a namespaced short id.

Surfaces that keep no readable transcript on this machine are listed by name
with the reason (`sources.EXCLUDED`) — cloud-hosted agents that never write
locally, and Windsurf and Antigravity, whose on-disk conversations are
encrypted. They are refused with that explanation rather than reading as "not
built yet".

## MCP

Any MCP client can read the bank. Four tools: `list_sessions`,
`search_session`, `read_session`, `get_record` — every response capped at ~4k
estimated tokens, paging anchors instead of silent truncation.

```bash
convo-mem mcp list                    # what each client would get, and its current state
convo-mem mcp register                # write it into Claude Code, Gemini CLI and Cursor's own config
convo-mem mcp register --client claude --dry-run
```

`register` writes into each client's **project-scoped** config — Claude
Code's `.mcp.json`, Cursor's `.cursor/mcp.json`, Gemini CLI's
`.gemini/settings.json` — merging in only `mcpServers.convo-mem` and backing
up whatever was there first. Codex is not covered yet (TOML, no confirmed
project-scope file); `mcp list` says so rather than pretending it doesn't
exist.

The entry it writes carries no absolute path, so all three files are safe to
**commit**: the server derives its project from where it is launched, and a
project-scoped config is already sitting in the project it configures. This
repo commits its own three. To register by hand instead, or for a client
`register` doesn't cover:

```json
{
  "mcpServers": {
    "convo-mem": {
      "command": "convo-mem",
      "args": ["mcp"],
      "_comment": "or zero-install: uvx --from 'convo-mem[mcp]' convo-mem mcp"
    }
  }
}
```

A **global** config is the one case that does need the project spelled out —
there is no project directory for it to sit in, so add
`"env": { "MEMTOOL_PROJECT": "/path/to/your/project" }`, and accept that it
binds every client session to that one project.

`--project`, `--bank` and `--stripped` work as flags too; `MEMTOOL_PROJECT`,
`MEMTOOL_BANK` and `MEMTOOL_STRIPPED` are the environment equivalents, since
clients configure servers through either. Resolution is reported on **stderr** —
stdout is the protocol.

## Skills

Six Agent Skills ship in the package: `recall`, `related`, `remember`,
`status`, `unblock`, `update`. `recall` is the guardrail — it checks the bank
before you explore an idea, rather than after.

```bash
convo-mem skills list                        # where each client looks, what is there
convo-mem skills install                     # -> .agents/skills (Cursor reads it too)
convo-mem skills install --client claude     # or claude | cursor | codex | all
convo-mem skills install --client all --global
```

One source, copied on demand. `list` distinguishes **current** from **stale**,
because a drifted copy an agent still follows is the failure worth catching.

## Running from a checkout without installing

```bash
PYTHONPATH=src python -m convo_mem.cli <command>
```

## Requirements

Python 3.11+, PyYAML and zstandard (pruned sessions are read back through the
zstd archive). The `[mcp]` extra takes `mcp>=1.2` and works on both SDK major
versions: 2.x renamed `FastMCP` to `MCPServer` and removed the old import
path, so the server accepts either. Verified against 1.29.1 and 2.1.0.

The extraction pipeline calls Claude models and is calibrated against specific
ones; reading a bank over MCP has no such dependency.
