Generated banner for Memoir
Generated logo for Memoir

Memoir

Memory server

First committed by zhangfengcdt

Published in zhangfengcdt/memoir. Publisher page

629 GitHub stars

What it is

Hierarchical Agent Memory with Git-Like Version Control
— the description by zhangfengcdt

AutoGineer overview, from the brain’s own files

Memoir is a memory system designed to replace opaque vector databases with a transparent, versioned, and cryptographically secure storage layer. By utilizing ProllyTrees, it enables hierarchical semantic paths instead of UUIDs, allowing for efficient O(log n) lookups. It addresses common AI memory issues like context contamination and token waste by providing branch, commit, merge, and rollback capabilities. Memoir integrates with various agents through plugins and an MCP server, supporting both keyword-based and LLM-powered semantic search.

How it works

Memory model: Not stated

AutoGineer overview, from the brain’s own files

Memoir organizes memory into a hierarchical structure using semantic paths, such as profile.professional.skills.python. It uses a ProllyTree-based store to manage data, allowing for Git-like operations such as branching and versioning. The system includes a classifier to categorize memories and a search engine for retrieval. It provides a CLI for manual interaction, hooks for automatic memory capture in supported agents, and an MCP server for integration with various AI development tools.

Folders
FolderRoleFiles
.githubagent-config10
docsdocs41
scriptsscripts9
srcsource-code216
teststests53
.agentsfolder1
.claude-pluginfolder1
benchmarksfolder10
packagingfolder3
pluginsfolder187
staticfolder2

The agent writes

Requirements

Runtimes: Python >=3.10

API keys (by name): ANTHROPIC_API_KEY, OPENAI_API_KEY

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Google Antigravity, Kiro, OpenCode, Amp, Roo Code, Cline, JetBrains Junie, Devin (ex-Windsurf)

Set it up

  1. This brain runs code automatically: 7 hooks (claude-code, codex), 2 scripts. Review Makefile, README.md, plugins/claude-code/hooks/hooks.json, plugins/codex/hooks/hooks.json before opening the folder in Claude Code. No step below turns a hook on for you.

    • Makefile: pip install -e .
    • README.md: curl -LsSf https://astral.sh/uv/install.sh | sh
    • plugins/claude-code/hooks/hooks.json: bash ${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh
    • plugins/claude-code/hooks/hooks.json: bash ${CLAUDE_PLUGIN_ROOT}/hooks/user-prompt-submit.sh
    • plugins/claude-code/hooks/hooks.json: bash ${CLAUDE_PLUGIN_ROOT}/hooks/stop.sh
    • plugins/claude-code/hooks/hooks.json: bash ${CLAUDE_PLUGIN_ROOT}/hooks/session-end.sh
    • plugins/codex/hooks/hooks.json: bash "${PLUGIN_ROOT}/hooks/session-start.sh"
    • plugins/codex/hooks/hooks.json: bash "${PLUGIN_ROOT}/hooks/user-prompt-submit.sh"
    • plugins/codex/hooks/hooks.json: bash "${PLUGIN_ROOT}/hooks/stop.sh"
  2. Not scanned by AutoGineerThe author’s README also describes installing it as a Claude Code plugin marketplace. Read its install section: AutoGineer did not scan that path. https://github.com/zhangfengcdt/memoir/blob/7fd1b3ef704fc554596571d5b9c8b73d7f2b0c5d/README.md#install-a-plugin-for-your-agent
  3. Not scanned by AutoGineerIts dependencies are installed by pip or uv when you run it and were not scanned by AutoGineer (7 declared). https://pypi.org/project/memoir-ai/
  4. First committed by zhangfengcdt. Published in zhangfengcdt/memoir. Licence: Apache License 2.0.

Usage

AutoGineer overview, from the brain’s own files

  • CLI-based memory management
  • Automatic context injection for coding agents
  • Version-controlled memory branching
  • Semantic search across stored facts
  • Cross-machine memory synchronization
“memoir remember "I prefer using Python for data analysis" -p preferences.coding.languages”
Stores the fact under the specified semantic path for later retrieval.
“memoir recall "what are my coding preferences?"”
Performs a semantic search to retrieve the relevant stored memory.

Documentation by zhangfengcdt

Memoir

<div align="center"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://www.memoir-ai.dev/images/memoir.png"> <source media="(prefers-color-scheme: light)" srcset="https://www.memoir-ai.dev/images/memoir-light.png"> <img src="https://www.memoir-ai.dev/images/memoir.png" alt="Memoir Logo" width="200" height="200"> </picture>

Git for AI Memory

Hierarchical Memory with Git-Like Version Control

</div>

Image: Python Image: License Image: Status Image: Website Image: Docs

<p align="center"> <img src="docs/_static/memoir-demo.gif" alt="Memoir demo" width="900"> </p>

Memoir is a high-performance semantic memory system for AI agents that brings Git-like version control to AI memory management. It replaces opaque vector databases with transparent, versioned, cryptographically secure memory storage using hierarchical semantic paths.

Project page: memoir-ai.dev — full overview, demos, and roadmap.

Why agents need versioned memory

AI memory is a Global Variable anti-pattern. Every production agent hits the same three walls: context contamination, token rent, and memory drift. Memoir brings version control to your agent's mind.

Your agent doesn't respect your git state. Context contamination happens every time you git checkout. Without branch-aware memory, your agent tries to apply experimental refactor patterns to stable production hotfixes.

You're paying "token rent" on a flat file. Using CLAUDE.md or MEMORY.md as a global store is a cache-killer. Every minor memory update invalidates your entire prefix cache, forcing you to pay full price to re-process your entire conversation.

Your agent's memory is code without version control. Today's AI memory — CLAUDE.md, vector stores, scratchpads — is treated like an append-only blob. One bad session poisons every future retrieval. Without memoir blame or memoir checkout, there's no way to audit who taught the agent a rule or revert a hallucination without wiping the whole store.

Key Features

  • Git-like Versioning — Branch, commit, merge, and rollback memories with cryptographic integrity.

  • Semantic Paths — Replace UUID keys with meaningful paths like profile.professional.skills.python.

  • O(log n) Lookups — Fast hierarchical search instead of expensive vector operations.

  • Memory Aggregation — Automatic consolidation of related memories at semantic locations.

  • Clean Architecture — Proper separation of storage, classification, and search layers.

  • Multiple Search Engines — Choose between fast keyword-based or intelligent LLM-powered search.

<!-- ## Multi-agent sessions <p align="center"> <img src="docs/_static/memoir-multi-agent.gif" alt="Multiple agent sessions working with Memoir" width="900"> <br> <em>Multiple agent sessions working with Memoir.</em> </p> -->

Install from PyPI

pip install memoir-ai

The distribution name on PyPI is memoir-ai. The Python import is import memoir and the CLI is memoir.

Install a plugin for your agent

Memoir ships as a plugin for several coding and personal-assistant agents. Expand the one you use:

<details> <summary><b>Claude Code</b></summary>

Inside a Claude Code session, run:

/plugin marketplace add zhangfengcdt/memoir
/plugin install memoir@memoir

No manual pip install needed if you have uv on PATH — the plugin auto-resolves to uvx --from memoir-ai memoir when the bare memoir binary isn't installed. Don't have uv? Install it once with the standard one-liner:

curl -LsSf https://astral.sh/uv/install.sh | sh

That's enough — the plugin handles the rest. It registers hooks for session start, user-prompt-submit, and stop, so your project gets automatic context injection and auto-captured memories. See the Claude Code plugin guide for the full slash-command and hook reference.

</details>

<details> <summary><b>Codex</b></summary>

Memoir's Codex plugin is distributed from this repository's Codex marketplace. In Codex, run /plugins, add the memoir marketplace from zhangfengcdt/memoir, restart Codex if prompted, then choose Memoir Plugins and install memoir.

You can also register the marketplace from the CLI:

codex plugin marketplace add zhangfengcdt/memoir

While developing from a local checkout, use codex plugin marketplace add /absolute/path/to/memoir instead. The repo marketplace lives at .agents/plugins/marketplace.json and points Codex at ./plugins/codex, relative to the repository root.

No manual pip install needed if you have uv on PATH — the Codex plugin resolves the Memoir CLI the same way the Claude Code plugin does: memoir on PATH first, then uvx --from memoir-ai==<pinned> memoir, then uv tool run --from memoir-ai==<pinned> memoir.

Enable Codex hooks with [features].hooks = true in ~/.codex/config.toml or pass --enable hooks for a smoke run. The Codex plugin ships lifecycle hooks; memory-recall, memoir-onboard, memoir-remember, memoir-status, and memoir-ui skills; Codex-specific transcript parsing; and local marketplace metadata. See the Codex plugin guide for setup, limitations, and the real Codex smoke-test flow.

</details>

<details> <summary><b>Hermes</b></summary>

Memoir is a memory provider for Hermes, the Nous Research personal-assistant agent. Install the plugin into your Hermes home and activate it:

hermes plugins install zhangfengcdt/memoir/plugins/hermes   # or: cp -r plugins/hermes ~/.hermes/plugins/memoir
hermes memory setup                                         # choose "memoir"

Hermes then auto-captures durable facts (people, schedule, preferences, standing instructions) each turn and exposes memoir_recall / memoir_remember / memoir_forget / memoir_sync / memoir_status tools. Capture/classification run on your host-selected model via direct provider APIs (never the claude CLI). See the Hermes plugin guide for install, configuration, model selection, and proxy routing.

</details>

<details> <summary><b>OpenClaw</b> (community)</summary>

Memoir is a memory plugin for OpenClaw, the personal-assistant gateway. It lives in its own repo, zhangfengcdt/openclaw-memoir. Install it into the memory slot, allow conversation access, and restart the gateway:

openclaw plugins install https://github.com/zhangfengcdt/openclaw-memoir   # or: --link /path/to/openclaw-memoir
openclaw config set plugins.entries.memory-memoir.hooks.allowConversationAccess true
systemctl --user restart openclaw-gateway

OpenClaw then auto-captures durable facts each turn (remembered across your sessions by default) and exposes memoir_recall / memoir_remember / memoir_forget / memoir_status tools plus an in-chat /memoir command. Set a capture model + provider key in config — plugins.entries.memory-memoir.config.{model,apiKey} (OpenClaw keeps its own keys in a secret store; use a temperature=0-capable model like anthropic/claude-haiku-4-5). See the OpenClaw plugin guide for configuration, scoping, model selection, and tool-profile notes.

</details>

<details> <summary><b>OpenCode</b> (community)</summary>

opencode-memoir is a community-maintained plugin that brings Memoir's long-term memory workflows to OpenCode through its native plugin system. Follow the install instructions in that repository.

</details>

<details> <summary><b>Any MCP host</b> (Claude Desktop, Cursor, Cline, Windsurf, VS Code, Zed, …)</summary>

Memoir ships an MCP server (memoir-mcp) on the official Model Context Protocol SDK, so any MCP-compatible host gets git-versioned memory — including the memoir_branches / memoir_checkout / memoir_commits versioning tools no other memory server has. No install needed if you have uv; add to your host's mcpServers config:

{
  "mcpServers": {
    "memoir": {
      "command": "uvx",
      "args": ["--from", "memoir-ai[mcp]", "memoir-mcp"],
      "env": { "MEMOIR_STORE": "~/.memoir/mcp" }
    }
  }
}

Recall is LLM-free by default (keyless), with opt-in single-call or multi-level tiered LLM modes; the store auto-creates on first use. See the MCP server guide for per-host config (VS Code/Zed/Continue/LibreChat differ slightly), recall modes + LLM setup, remote HTTP for ChatGPT/Claude.ai connectors, and the one-click Claude Desktop .mcpb.

</details>

Quick look

Memoir's CLI defaults to Anthropic claude-haiku-4-5 as of v0.1.6 — set your key first:

export ANTHROPIC_API_KEY="sk-..."

Note that if you do not set any model api keys, it will try to use the claude -p command to authenticate via claude code's subscription.

Then create a store and round-trip a memory:

# 1. Create a memoir store
memoir new my-memoir-store
cd my-memoir-store

# 2. Store with an explicit path (offline, no LLM call)
memoir remember "Sarah prefers tabs and 2-space indents" -p preferences.coding.style

# 3. Store with auto-classification (LLM picks the path; needs API key)
memoir remember "I work in Pacific time"

# 4. Read back by path (offline)
memoir get preferences.coding.style

# 5. Semantic search (LLM-backed)
memoir recall "what does Sarah prefer?"

# 6. Watch a file by indexing it on the fly
memoir watch add ~/papers/transformer.pdf -n research

# 7. Search the indexed content
memoir search "transformer attention mechanism"

# 8. Open the visual explorer (auto-opens in your browser)
memoir ui

Curious what the UI looks like before installing? Browse the UI Gallery.

Prefer a different model? memoir recall "..." --model gpt-4o-mini (needs OPENAI_API_KEY), or set MEMOIR_LLM_MODEL in your shell. Resolution order: --model flag → MEMOIR_LLM_MODEL → claude-haiku-4-5.

See the full Quickstart for the Python API and version-control workflow.

Documentation

Full docs live at zhangfengcdt.github.io/memoir:

  • Quickstart — five-minute tour of the core loop.

  • CLI Reference — every command, flag, and exit code.

  • UI — the visual explorer (Tree / Graph / Timeline / Places + /stats).

  • Claude Code — plugin install, slash commands, hooks, lifecycle.

  • Codex — plugin install, hooks, skills, transcript parsing, smoke-test evidence.

  • Architecture — taxonomy, classifier, store, search.

  • API Reference — Python SDK.

  • Examples — context branching, memory debugging, reproducible testing.

Contributing

Memoir is alpha and contributions are very welcome — especially from people building coding agents, since that's the audience we're optimizing for. Good first paths in:

  • Pick an issue from the issue tracker or open one describing a gap.

  • Fork the repo, branch off main, and run make ci before opening a PR (lint, tests, docs build must be green).

  • Bug reports with a minimal reproducer and benchmark / taxonomy proposals for coding-agent use cases are particularly appreciated.

License

Apache License 2.0 — see LICENSE.

docs/cloud.md

Cloud Sync

memoir remote, push, pull, and fetch round-trip a local memoir store with memoir-cloud. The commands exist in every install but need a login (or MEMOIR_API_KEY); without one, memoir behaves exactly as before (COMMUNITY tier) and the cloud commands exit 1 asking you to run memoir login.

From the root of a local clone of your code repo:

memoir login                 # once per machine (add --url <gateway> for a non-production gateway)
memoir push --create         # New: create <handle>/<repo name> from this repo's memories
# or
memoir pull <owner>/<store>  # Open: link an existing cloud store and pull it

Inside a code repo, memoir uses that repo's store, ~/.memoir/<slug>, the same one the Claude Code plugin uses there (see Store resolution), so there is no MEMOIR_STORE to set. memoir login saves the gateway, so there is no --url either.

There is no clone. Local stores are created automatically (by the Claude Code plugin on session start, or by the first memoir command), so linking is always done on a store that already exists, and pull adopts the cloud history when that store is still empty.

For a hands-on walkthrough see Cloud sync commands on the CLI page.

Logging in

memoir login works like gh auth login: it prints a short code and a link, opens the browser, and waits while you click Authorize on the cloud (signed in there). The cloud mints a key named memoir CLI (<hostname>), which you can see and revoke on its keys page. memoir login --with-key reads a key from stdin instead, for headless machines. memoir logout revokes the key on the cloud when reachable and deletes it locally.

Logins are kept per gateway in ~/.config/memoir/cloud.json ($XDG_CONFIG_HOME/memoir/cloud.json when that is set), mode 0600 in a 0700 directory, like gh's hosts file. You can be logged in to production and staging side by side:

memoir login                                   # production (the first login becomes the default)
memoir login --url https://api-gateway-staging-3ce9.up.railway.app
memoir login --status                          # lists both, * marks the default
memoir logout --url https://api-gateway-staging-3ce9.up.railway.app   # just that one
memoir logout --all

--default makes a login's gateway the default for new links. A file written by an older memoir (one login) is read as a single entry and rewritten in the new shape on the next login.

Agent accounts (memoir login --agent)

An agent working in a repo on a machine with no saved login has another way in. memoir login --agent, run inside the repo, asks the cloud for an agent account: a throwaway account that owns exactly one store, named after the repo, provisioned over HTTP with no human in the loop. The cloud returns a token once; memoir keeps it with the store, under <store>/.git/memoir-cloud/token (mode 0600), never in cloud.json, so no other repo on the machine picks it up. origin is linked to the new store and memoir push works from there.

memoir login --agent            # inside the repo: agent-k7x2m9 owns agent-k7x2m9/<repo name>
memoir push
memoir cloud open               # a single-use link into the web UI (the account has no password)
memoir claim                    # later, as yourself: the store moves into your account

The cloud cannot verify that a human agreed to this, so it rate-limits creation per address, caps an agent store at 5 branches and 2,000 memories per branch (a push beyond that is refused with branch limit (5) reached or memory limit (2000) exceeded on this branch), and deletes an agent account idle for 30 days. memoir claim lifts all three: it logs you in (the normal browser approval) when the machine has no login yet, moves the store into your account (--name <other> when you already own a store of that name), rewrites origin to the new address, and keeps the token, which now belongs to you and is still scoped to that one store, so pushes continue without another login. It warns, without failing, when the cloud store was provisioned for a different repo URL than this clone's origin. The token can create no other store (memoir push --create is refused with it). The Claude Code plugin's /memoir:push offers an agent account when the machine has no login; claiming is a memoir claim in a terminal, as yourself.

WhatResolution
key for a request to gateway GMEMOIR_API_KEY (wins for every gateway) → the store's own agent token, when G issued it → the login saved for G → none: the command stops before any request with not logged in to G: run `memoir login --url G`
gateway for a new link (push --create, remote add)--url → MEMOIR_CLOUD_URL → the saved default (only while MEMOIR_API_KEY is unset) → production

A saved key is only ever sent to the gateway that issued it. Gateways are compared as scheme + host[:port], case-insensitively. Once a store is linked, its remote's URL decides the gateway, and therefore the key.

Remotes

A store can link to several cloud stores, like git remote. The default remote is origin; add more with --name and pick one with --remote:

memoir remote add zhangfengcdt/demo --name staging --url https://api-gateway-staging-3ce9.up.railway.app
memoir remote list                 # name, address, gateway, logged in?
memoir push                        # to origin, with origin's gateway key
memoir push --remote staging       # to staging, with staging's key
memoir pull --remote staging
memoir remote remove staging

Each remote keeps its own state: branches under refs/remotes/<remote>/… (proposal branches under <remote>/cloud/…), the pushed record .git/memoir-cloud/pushed-<remote>, and the repo-metadata record repo-meta-<remote>. memoir status lists every remote as <name>: <owner>/<store> @ <gateway>.

Store resolution

-s → MEMOIR_STORE → repo mode → current directory.

Repo mode applies when you're inside a git work tree that is not itself a memoir store. The store is ~/.memoir/<slug>, where the slug is the main worktree root with / and . replaced by - (exactly the plugin's derivation, so linked worktrees share the main repo's store). Cloud commands print it first, e.g. store: ~/.memoir/-Users-me-code-sedona (repo sedona). --repo forces repo mode even when MEMOIR_STORE is set. remote add and pull create the store on first use; other commands stop with a hint when it doesn't exist yet. With no arguments, push --create names the cloud store after the repo, and remote add proposes <handle>/<repo name>.

Addresses

A cloud store is addressed GitHub-style as <owner>/<store>, for example feng-zhang/demo. owner is your handle (chosen once in the gateway's web app), store is the store name. The address is also a URL: https://<gateway>/feng-zhang/demo opens the store page in a browser and is the git remote memoir configures.

PartRules
handle1–39 letters, digits or hyphens; no leading, trailing or double hyphen
store name1–100 letters, digits, ., _ or -; not starting with .; not ending in .git

Both are matched case-insensitively by the server. Memoir validates an address locally before any network call and rejects the server's internal str_... ids with a message pointing at the address form. If your account has no handle yet, every cloud command tells you to choose one at <gateway>/app.

What syncs

A memoir store is an ordinary non-bare git repo. Its commits track one file, data/prolly_config_tree_config, which holds the ProllyTree root hash. The memory data itself lives in node files under .git/prolly/nodes/files/<hash>, which git does not track. Sync therefore has two halves, and the cloud serves both under the store's address:

HalfCarriesTransport
Gitcommits, branches, tagsstandard git smart-HTTP via the git binary memoir already requires
Chunksthe node files, keyed by filenamea small HTTP protocol under <address>/chunks: negotiate → upload the missing ones in multipart batches (up to 500 per request, 4 in flight) → download missing

Node filenames are prollytree node hashes and are treated as opaque identifiers; nothing is re-hashed. When the server advertises Memoir-Accept-Encoding: gzip on its chunk routes, upload batches are sent gzip-compressed (Content-Encoding: gzip), which cuts the bytes on the wire about five-fold; against a server that doesn't, they go out raw as before. v1 syncs the whole node directory. Repeat pushes are incremental twice over: after a successful push (or a fetch) memoir records the hashes the server confirmed under .git/memoir-cloud/pushed-origin, so the next push computes what is new locally and sends only that, with no negotiate round trip. If that record is missing, or the server rejects a ref with missing chunk, memoir falls back to negotiating the whole set and rebuilds the record.

Commands

CommandWhat it does
memoir remote add [<owner>/<store>] [--url <gateway>] [--force]Resolve the address (404 → store <owner>/<store> not found (or you don't own it)), then set the git remote origin to https://<gateway>/<owner>/<store>. With no argument, proposes <your handle>/<store directory name> and asks before resolving.
memoir remote show / removePrint the address, gateway, branch and cloud summary; or unlink.
memoir push [--branch <b>] [--create <store>] [--to <cloud branch>] [--force]Upload every chunk the cloud is missing (batched; only the node files some commit reaches, never the dead ones memoir gc removes), then git push. --create <store> first creates that cloud store under your handle and links it under --remote (default origin). Default branch: current. Prints pushed main to <owner>/<store>: 7,361 chunks (6,900 new, 41.3 MB sent (gzip)) in 41.2 s, git in 2.4 s.
memoir fetchgit fetch all branches, tags, and refs/cloud/*; download every chunk not present locally. Moves no local branch.
memoir pull [<owner>/<store>] [--remote <name>] [--url <gateway>] [--branch <b>] [--force]With an address, links the remote first when it doesn't exist yet (as remote add would; in a code repo the store is created too), so memoir pull <owner>/<store> is the one-command way to start from an existing cloud store. If the remote already points at that address it just pulls; if it points at a different store or gateway, nothing changes and the command exits 1 (pull never relinks silently). Then fetch, then fast-forward the branch. A branch that does not exist locally is created from the cloud; a pristine local store (only prollytree's initial commit, no memories) adopts the cloud history. --force replaces the local branch with the cloud copy, discarding local memories on it; the previous tip is kept under refs/memoir/backup/<branch> and printed.
memoir statusShows origin: <owner>/<store> when a cloud remote is configured.
memoir login --agent / memoir claim [--name <store>] / memoir cloud openAgent accounts: provision one for this repo (no login needed), move its store into your account, open it in the web UI. See Agent accounts.

All commands support --json; the JSON carries the address as origin, never an id.

Rules

Fast-forward only. User branches on the cloud never rewind. If the cloud is ahead, memoir push exits with code 6 and remote has commits you don't have; run memoir pull first. If local and cloud histories have diverged, memoir pull also exits 6 (local and cloud histories have diverged; cloud merge is not available yet) and points at memoir pull --force, the one explicit way to discard the local memories on that branch and take the cloud copy. Linking a store that already holds its own memories to a cloud store with a different history is the same situation and gets the same answer. Cloud-side merge is planned; memoir does not attempt a local merge of cloud history.

Chunks before refs. push only runs git push after every batch has succeeded. A failed upload never results in a git push, so no cloud ref ever points at a commit whose root chunk is missing. The server enforces the same invariant: it refuses to advance a ref unless the root hash in the pushed commit is an uploaded chunk. A 502 (object store unavailable) is retried with backoff and then surfaced as object store unavailable, retry later; an interrupted push simply resumes on the next run, with already-written chunks reported as existing. A chunk the server rejects fails the push and is named in the error.

cloud/* branches are read-only locally. Branches under refs/cloud/* are cloud-owned proposal branches. fetch makes them visible as origin/cloud/...; push refuses a branch whose name starts with cloud/.

Root chunk check. After pull, memoir verifies that the chunk named by the tracked root hash exists locally and errors otherwise, so the store is never left pointing at missing data.

Code repo metadata

When the store is the memory store of a code repo (the Claude Code plugin's ~/.memoir/<slug> stores, where the slug is the repo's path), memoir remote add and every successful memoir push also report that repo to memoir-cloud, so the cloud's store list and store page can show its link, description, language and topics.

  • Always, from the local clone: the origin URL normalised to https, host, owner and name, default branch, current branch and commit, and the repo directory name.

  • For GitHub repos, when reachable within 2 seconds: description, topics, language, visibility, stars and homepage from the GitHub API, authenticated with gh auth token when the GitHub CLI is logged in. Offline, rate-limited or private-without-token simply means these fields are left out.

  • The document is sent only when it changed since the last send (recorded in .git/memoir-cloud/repo-meta-origin). Collecting or sending it can never fail remote add or push. A store that maps to no code repo sends nothing, and nothing is written to the store itself.

Key handling

  • The API key comes from MEMOIR_API_KEY or, when that is unset, from the store's agent token (<store>/.git/memoir-cloud/token, mode 0600; see Agent accounts) or the login file ~/.config/memoir/cloud.json (mode 0600; see Logging in). It is never written to .git/config or anywhere else, and never printed.

  • Git gets it per invocation as -c http.extraHeader="Authorization: Bearer <key>"; git runs with GIT_TERMINAL_PROMPT=0 so an invalid key fails fast instead of prompting.

  • The key is redacted from any error output that echoes a command.

  • A 401 from the gateway is reported as not signed in: run `memoir login` (or set MEMOIR_API_KEY).

Environment variables

VariableEffect
MEMOIR_API_KEYAPI key; overrides the one saved by memoir login and a store's agent token.
MEMOIR_CLOUD_URLGateway URL used by login, remote add and push --create when --url is not passed; overrides the gateway saved by memoir login. Default: the production gateway. After linking, the gateway is read back from the origin URL.

Exit codes

CodeMeaning
1HTTP / auth / address error, or cloud sync not enabled
2branch not found (locally for push, on the cloud for pull)
3no store configured
5git operation failed
6non-fast-forward: cloud is ahead (push) or histories diverged (pull)

Out of scope for now

Merging diverged histories, a reachability walk so only chunks referenced by the pushed commit are synced, and proposal review from the CLI.

512 files · 489 not served here

Advantages

  • Provides Git-like version control for AI memory, allowing for branching, merging, and rolling back. evidence: README.md
  • Uses hierarchical semantic paths for O(log n) lookups, offering better performance than traditional vector databases. evidence: README.md

Limitations

  • Requires an API key for LLM-powered features like intelligent classification and semantic search. evidence: README.md
  • Some advanced features like document watching require additional dependencies or manual configuration. evidence: pyproject.toml

Security

Risk level: Medium risk

This brain runs

Git hooks (5)

  • .pre-commit-config.yaml: pre-commit hooks from https://github.com/pre-commit/pre-commit-hooks at v6.0.0 (contributor tooling: runs only after pre-commit install) · uses the network
  • .pre-commit-config.yaml: pre-commit hooks from https://github.com/pycqa/isort at 6.0.1 (contributor tooling: runs only after pre-commit install) · uses the network
  • .pre-commit-config.yaml: pre-commit hooks from https://github.com/astral-sh/ruff-pre-commit at v0.12.9 (contributor tooling: runs only after pre-commit install) · uses the network
  • .pre-commit-config.yaml: pre-commit hooks from https://github.com/PyCQA/bandit at 1.8.6 (contributor tooling: runs only after pre-commit install) · uses the network
  • .pre-commit-config.yaml: pytest

Agent instructions that run or fetch something (73)

  • CLAUDE.md: `make ci` runs the full pipeline (lint, test, security, docs).
  • CLAUDE.md: tests use the fake gateway in `tests/fake_cloud.py` (real `git http-backend`, no network).
  • CLAUDE.md: When touching the mod run `claude plugin validate plugins/claude-code` and `claude plugin test plugins/claude-code`;
  • CLAUDE.md: Run with `pytest`.
  • CLAUDE.md: Deep structural details (layouts, refactor history, per-file line counts) intentionally omitted — use `rg` / `git log` when you need them.
  • CLAUDE.md: flipping it later (`git init`, or `rm -rf .git`) surfaces a warning at SessionStart but does not block writes.
  • CLAUDE.md: When changing a prompt, **run the harness against haiku before merging**.
  • CLAUDE.md: The harness has two modes: **gate** (deterministic shell-hook tests, no LLM, sub-second per case — pins the recall-trigger gate in `hooks/user-prompt-submit.sh`) and **LLM mode** (`run` / `case` / `adhoc` against `claude -p` for prompt templates).
  • CLAUDE.md: # Gate mode — no LLM cost, run on every commit.
  • CLAUDE.md: plugins/claude-code/tests/prompt-harness/runner.py run --prompt stop_capture --model haiku
  • CLAUDE.md: plugins/claude-code/tests/prompt-harness/runner.py run --prompt stop_capture --model sonnet
  • CLAUDE.md: Every run drops `system.txt` (the assembled prompt actually sent), `input.txt`, `output.txt`, `command.sh` (replayable), and `result.json` per case under `/tmp/memoir-prompt-tests/<UTC-timestamp>/`.
  • CLAUDE.md: Skill prompts (`skills/<name>/SKILL.md`) are evaluated by the orchestrating Claude rather than dispatched as system prompts to a model, so they are *not* covered by this harness — to test those, run the slash command in a real session and inspect behavior.
  • CLAUDE.md: **Build the docs locally:** `make docs` (mkdocs) → `site/index.html`, or `make docs-live` for auto-reload.
  • plugins/claude-code/skills/memoir-onboard/SKILL.md: bash -c 'source "${CLAUDE_PLUGIN_ROOT}/hooks/common.sh" >/dev/null 2>&1; in_git_repo && echo codebase:onboard || echo project:onboard'
  • plugins/claude-code/skills/memoir-onboard/SKILL.md: Store: !`bash -c 'if [ -n "${MEMOIR_STORE:-}" ];
  • plugins/claude-code/skills/memoir-onboard/SKILL.md: `$MEMOIR` is a wrapper that resolves the right invocation for this machine — `memoir` on PATH if installed, otherwise `uvx --from memoir-ai==<pin> memoir`, otherwise `uv tool run --from memoir-ai==<pin> memoir` (pin lives in `scripts/resolve-memoir-cli.sh`).
  • plugins/claude-code/skills/memoir-onboard/SKILL.md: Wrap **every** memoir call — both branches A and B, both reads and writes — in a subshell that cd's into the store first, and use `"$MEMOIR"` (NOT bare `memoir`) so the call works on machines without a global memoir install:
  • plugins/claude-code/skills/memoir-onboard/SKILL.md: `test.strategy` — test layout, how to run tests, what coverage emphasizes.
  • plugins/claude-code/skills/memoir-onboard/SKILL.md: bash -c 'source "${CLAUDE_PLUGIN_ROOT}/hooks/common.sh" >/dev/null 2>&1; concurrent_session_warning'
  • plugins/claude-code/skills/memoir-onboard/SKILL.md: If the command prints anything, stop and report: "Concurrent session detected — run /memoir:onboard after the other session finishes, or set a distinct MEMOIR_STORE."
  • plugins/claude-code/skills/memoir-onboard/SKILL.md: `git log --oneline -20` and `git log --stat -5` for recent change patterns (informs lessons / rules).
  • plugins/claude-code/skills/memoir-onboard/SKILL.md: Run `git log --stat <last_sha>..HEAD` to enumerate changed paths since the last onboarding pass.
  • plugins/claude-code/skills/memoir-onboard/SKILL.md: Run the confirmation check (`memoir status` → path == `$STORE_PATH`) before doing any writes.
  • plugins/claude-code/skills/memoir-onboard/SKILL.md: `python3 ${CLAUDE_PLUGIN_ROOT}/skills/memoir-onboard/extractors.py walk <root>` — JSON list of `{path, size, mtime_ns, kind}` plus `snapshot_hash`.
  • plugins/claude-code/skills/memoir-onboard/SKILL.md: `python3 ${CLAUDE_PLUGIN_ROOT}/skills/memoir-onboard/extractors.py extract <path>` — `key=value` blob for one file (with `kind=` first, `extractor.stdlib.fields=[…]` for provenance).
  • plugins/claude-code/skills/memoir-onboard/SKILL.md: `python3 ${CLAUDE_PLUGIN_ROOT}/skills/memoir-onboard/extractors.py snapshot-hash <root>` — just the hash.
  • plugins/claude-code/skills/memoir-onboard/SKILL.md: `python3 ${CLAUDE_PLUGIN_ROOT}/skills/memoir-onboard/extractors.py tree <root>` — pruned tree.
  • plugins/claude-code/skills/memoir-onboard/SKILL.md: `python3 ${CLAUDE_PLUGIN_ROOT}/skills/memoir-onboard/extractors.py shape <root>` — `{shape, overview}` JSON.
  • plugins/claude-code/skills/memoir-onboard/SKILL.md: bash -c 'source "${CLAUDE_PLUGIN_ROOT}/hooks/common.sh" >/dev/null 2>&1; concurrent_session_warning'
  • plugins/claude-code/skills/memoir-onboard/SKILL.md: For each file in the walk result, run `extractors.py extract <path>` and capture the structured blob.
  • plugins/claude-code/skills/memoir-onboard/SKILL.md: python3 -c "import json,sys; print('\n'.join(e['path'] for e in json.loads(sys.argv[1])['files']))" "$WALK_JSON" \
  • plugins/claude-code/skills/memoir-onboard/SKILL.md: **added** (in walk, not in store) → run `extract <path>`, write `files.<san>.meta` and `files.<san>.summary`.
  • plugins/claude-code/skills/memoir-onboard/SKILL.md: **modified** (same path, different `(size, mtime_ns)`) → re-run `extract <path>`, write both keys.
  • plugins/claude-code/skills/memoir-onboard/SKILL.md: If a cold run fails partway through, the `_meta.*` keys act as commit markers.
  • plugins/claude-code/skills/memory-recall/SKILL.md: Run this preamble first and reuse `$STORE` and `$MEMOIR` for every memoir invocation below:
  • plugins/claude-code/skills/memory-recall/SKILL.md: `$MEMOIR` is a wrapper that resolves the right invocation for this machine — `memoir` on PATH if installed, otherwise `uvx --from memoir-ai==<pin> memoir`, otherwise `uv tool run --from memoir-ai==<pin> memoir` (pin lives in `scripts/resolve-memoir-cli.sh`).
  • plugins/claude-code/skills/memory-recall/SKILL.md: that way recall works on machines where memoir isn't `pip install`ed but `uv` is.
  • plugins/codex/skills/memoir-onboard/SKILL.md: bash -c 'source "${PLUGIN_ROOT}/hooks/common.sh" >/dev/null 2>&1; in_git_repo && echo codebase:onboard || echo project:onboard'
  • plugins/codex/skills/memoir-onboard/SKILL.md: Store: !`bash -c 'if [ -n "${MEMOIR_STORE:-}" ];
  • plugins/codex/skills/memoir-onboard/SKILL.md: python3 - "$manifest" <<'PY'
  • plugins/codex/skills/memoir-onboard/SKILL.md: `$MEMOIR` is a wrapper that resolves the right invocation for this machine — `memoir` on PATH if installed, otherwise `uvx --from memoir-ai==<pin> memoir`, otherwise `uv tool run --from memoir-ai==<pin> memoir` (pin lives in `scripts/resolve-memoir-cli.sh`).
  • plugins/codex/skills/memoir-onboard/SKILL.md: Wrap **every** memoir call — both branches A and B, both reads and writes — in a subshell that cd's into the store first, and use `"$MEMOIR"` (NOT bare `memoir`) so the call works on machines without a global memoir install:
  • plugins/codex/skills/memoir-onboard/SKILL.md: `test.strategy` — test layout, how to run tests, what coverage emphasizes.
  • plugins/codex/skills/memoir-onboard/SKILL.md: bash -c 'source "${PLUGIN_ROOT}/hooks/common.sh" >/dev/null 2>&1; concurrent_session_warning'
  • plugins/codex/skills/memoir-onboard/SKILL.md: If the command prints anything, stop and report: "Concurrent session detected - run memoir-onboard after the other session finishes, or set a distinct MEMOIR_STORE."
  • plugins/codex/skills/memoir-onboard/SKILL.md: `git log --oneline -20` and `git log --stat -5` for recent change patterns (informs lessons / rules).
  • plugins/codex/skills/memoir-onboard/SKILL.md: Run `git log --stat <last_sha>..HEAD` to enumerate changed paths since the last onboarding pass.
  • plugins/codex/skills/memoir-onboard/SKILL.md: Run the confirmation check (`memoir status` → path == `$STORE_PATH`) before doing any writes.
  • plugins/codex/skills/memoir-onboard/SKILL.md: `python3 ${PLUGIN_ROOT}/skills/memoir-onboard/extractors.py walk <root>` — JSON list of `{path, size, mtime_ns, kind}` plus `snapshot_hash`.
  • plugins/codex/skills/memoir-onboard/SKILL.md: `python3 ${PLUGIN_ROOT}/skills/memoir-onboard/extractors.py extract <path>` — `key=value` blob for one file (with `kind=` first, `extractor.stdlib.fields=[…]` for provenance).
  • plugins/codex/skills/memoir-onboard/SKILL.md: `python3 ${PLUGIN_ROOT}/skills/memoir-onboard/extractors.py snapshot-hash <root>` — just the hash.
  • plugins/codex/skills/memoir-onboard/SKILL.md: `python3 ${PLUGIN_ROOT}/skills/memoir-onboard/extractors.py tree <root>` — pruned tree.
  • plugins/codex/skills/memoir-onboard/SKILL.md: `python3 ${PLUGIN_ROOT}/skills/memoir-onboard/extractors.py shape <root>` — `{shape, overview}` JSON.
  • plugins/codex/skills/memoir-onboard/SKILL.md: bash -c 'source "${PLUGIN_ROOT}/hooks/common.sh" >/dev/null 2>&1; concurrent_session_warning'
  • plugins/codex/skills/memoir-onboard/SKILL.md: For each file in the walk result, run `extractors.py extract <path>` and capture the structured blob.
  • plugins/codex/skills/memoir-onboard/SKILL.md: python3 -c "import json,sys; print('\n'.join(e['path'] for e in json.loads(sys.argv[1])['files']))" "$WALK_JSON" \
  • plugins/codex/skills/memoir-onboard/SKILL.md: **added** (in walk, not in store) → run `extract <path>`, write `files.<san>.meta` and `files.<san>.summary`.
  • plugins/codex/skills/memoir-onboard/SKILL.md: **modified** (same path, different `(size, mtime_ns)`) → re-run `extract <path>`, write both keys.
  • plugins/codex/skills/memoir-onboard/SKILL.md: If a cold run fails partway through, the `_meta.*` keys act as commit markers.
  • plugins/codex/skills/memoir-onboard/SKILL.md: A subsequent forced memoir-onboard run will rewrite cleanly.
  • plugins/codex/skills/memoir-remember/SKILL.md: python3 - "$manifest" <<'PY'
  • plugins/codex/skills/memoir-remember/SKILL.md: bash "$PLUGIN_ROOT/scripts/ensure-store.sh" "$STORE" >/dev/null
  • plugins/codex/skills/memoir-status/SKILL.md: Run:
  • plugins/codex/skills/memoir-status/SKILL.md: python3 - "$manifest" <<'PY'
  • plugins/codex/skills/memoir-status/SKILL.md: bash "$PLUGIN_ROOT/scripts/status-cmd.sh"
  • plugins/codex/skills/memoir-ui/SKILL.md: Run:
  • plugins/codex/skills/memoir-ui/SKILL.md: python3 - "$manifest" <<'PY'
  • plugins/codex/skills/memoir-ui/SKILL.md: bash "$PLUGIN_ROOT/scripts/memoir-ui-ctl.sh" start "$STORE"
  • plugins/codex/skills/memory-recall/SKILL.md: Run this preamble first and reuse `$STORE` and `$MEMOIR` for every memoir invocation below:
  • plugins/codex/skills/memory-recall/SKILL.md: python3 - "$manifest" <<'PY'
  • plugins/codex/skills/memory-recall/SKILL.md: `$MEMOIR` is a wrapper that resolves the right invocation for this machine — `memoir` on PATH if installed, otherwise `uvx --from memoir-ai==<pin> memoir`, otherwise `uv tool run --from memoir-ai==<pin> memoir` (pin lives in `scripts/resolve-memoir-cli.sh`).
  • plugins/codex/skills/memory-recall/SKILL.md: that way recall works on machines where memoir isn't `pip install`ed but `uv` is.

Install scripts (2)

  • Makefile (make install): pip install -e .
  • README.md: curl -LsSf https://astral.sh/uv/install.sh | sh · uses the network

MCP servers (1)

  • README.md (memoir): uvx --from memoir-ai[mcp] memoir-mcp

Hooks (7)

  • plugins/claude-code/hooks/hooks.json (SessionStart): bash ${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh
  • plugins/claude-code/hooks/hooks.json (UserPromptSubmit): bash ${CLAUDE_PLUGIN_ROOT}/hooks/user-prompt-submit.sh
  • plugins/claude-code/hooks/hooks.json (Stop): bash ${CLAUDE_PLUGIN_ROOT}/hooks/stop.sh
  • plugins/claude-code/hooks/hooks.json (SessionEnd): bash ${CLAUDE_PLUGIN_ROOT}/hooks/session-end.sh
  • plugins/codex/hooks/hooks.json (SessionStart): bash "${PLUGIN_ROOT}/hooks/session-start.sh"
  • plugins/codex/hooks/hooks.json (UserPromptSubmit): bash "${PLUGIN_ROOT}/hooks/user-prompt-submit.sh"
  • plugins/codex/hooks/hooks.json (Stop): bash "${PLUGIN_ROOT}/hooks/stop.sh"
  • Medium risk: runs-git-hook-remote-exec (.pre-commit-config.yaml:2)
  • Medium risk: runs-git-hook-remote-exec (.pre-commit-config.yaml:23)
  • Medium risk: runs-git-hook-remote-exec (.pre-commit-config.yaml:30)
  • Medium risk: runs-git-hook-remote-exec (.pre-commit-config.yaml:40)
  • Medium risk: runs-install-script-remote-exec (README.md:86)
  • Medium risk: runs-mcp-server-unpinned-runner (README.md:153)
  • Low risk: network-instructions (Makefile:37)
  • Low risk: scripts-present (benchmarks/classifier.py)
  • Low risk: scripts-present (benchmarks/locomo/run.py)
  • Low risk: scripts-present (plugins/claude-code/hooks/session-end.sh)
  • Low risk: scripts-present (plugins/claude-code/hooks/session-start.sh)
  • Low risk: scripts-present (plugins/claude-code/hooks/stop.sh)
  • Low risk: scripts-present (plugins/claude-code/hooks/user-prompt-submit.sh)
  • Low risk: network-instructions (plugins/claude-code/skills/memory-recall/SKILL.md:20)
  • Low risk: scripts-present (plugins/codex/hooks/session-start.sh)
  • Low risk: scripts-present (plugins/codex/hooks/stop.sh)
  • Low risk: scripts-present (plugins/codex/hooks/user-prompt-submit.sh)
  • Low risk: network-instructions (plugins/codex/skills/memory-recall/SKILL.md:36)
  • Low risk: network-instructions (pyproject.toml:57)
  • Low risk: scripts-present (scripts/cc-smoke/run.sh)
  • Low risk: scripts-present (scripts/check_version_consistency.py)

Attribution and licence

First committed by
GitHub avatar of zhangfengcdtzhangfengcdt
Declared authors
  • zhangfengcdt (declared in pyproject.toml)
Publisher
Feng Zhang (Community)
Source
zhangfengcdt/memoir · commit 7fd1b3e
Licence
Apache License 2.0 (files served here)
  • ATTRIBUTION.md (written by AutoGineer)
Synced
Contributors
zhangfengcdt, rapidSpace, disafronov, KevFoxCodeCraft, Ottohere-Mourn

AutoGineer is not affiliated with or endorsed by zhangfengcdt.

Install from source

489 of its files are not served here, so there is no ZIP. zhangfengcdt/memoir at 7fd1b3e