agentleFS
MyMemoAIMyMemoAI/openmymemo/AGENTS.md

openmymemo

AGENTS.md29 starsChanged 32 days agoApache-2.0View on GitHub

A local-first, open-source AI memory folder with an approval panel. docs/product-design.md is the product definition; if an implementation would contradict it, update the design doc first (§12 and §13 record where v0.1 and v0.2 differ from earlier plans).

  • Installs packages
  • Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.

    Of the AGENTS.md files we read, the 31,843 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.

  • In this repository3 other files it gives its agents.

The file

We split this AGENTS.md into the rules it gives an agent

5 rules. About 0 are common, 1 is distinctive, and 4 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 4

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    All user data is plain text: memories/*.md is the source of truth for memory content.

    line 8
  2. Very specific:

    Don't weaken the panel API guard (guard in web.py: Host, Origin, X-OpenMyMemo header) or the /mcp token check.

    line 12
  3. Very specific:

    All writes go through Vault methods, which lock, re-read from disk, write atomically and update meta and history.

    line 78
  4. Very specific:

    Don't add a root .mcp.json: Claude Code would treat it as project config for everyone working on this repo.

    line 82
  5. Distinctive:

    Commit messages are imperative English.

    line 83

≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
AGENTS.md

OpenMyMemo — agent guide

A local-first, open-source AI memory folder with an approval panel. docs/product-design.md is the product definition; if an implementation would contradict it, update the design doc first (§12 and §13 record where v0.1 and v0.2 differ from earlier plans).

Non-negotiables

  • Local only: no cloud storage, sync, accounts or telemetry, except the optional OpenMyMemo Cloud connector (product-design.md §16), which does nothing until the person signs in and never holds memory in readable form at rest unless the person also turns on MyMemo Memory sync (product-design.md §20): a separate consent, shown with what MyMemo stores, who can read it and how to delete it. Sync never sends a private topic the person didn't pick, and when the folder and MyMemo disagree, the folder wins. The server listens on 127.0.0.1 only. Memory text leaves the computer only when the person turns the OpenMyMemo Assistant on with a remote model, and only to that model (product-design.md §17), or turns on MyMemo Memory sync, and only to MyMemo (§20); a model on this computer keeps everything on the computer, and private topics never go to a remote model.
  • All user data is plain text: memories/*.md is the source of truth for memory content; metadata, history, activity, proposals and settings under .openmymemo/ are plain text too. Don't introduce a database.
  • Every AI write goes through a proposal (proposals.py) and never edits files directly. A change that applies without the user (the default, or a connector set to auto) must stay undoable, must never write into a private topic, and must never silently change a memory the user wrote last (last_actor); the table in product-design.md §5.5 is normative. MyMemo Memory sync (product-design.md §20) follows the same rule: what MyMemo's AI features and web apps propose arrives as proposals from cloud-* connectors and is decided here; only the person's own edits on MyMemo's memory page are applied directly, as their own edits (actor: user).
  • Works with zero external dependencies: anything that needs a model endpoint is optional and degrades instead of failing.
  • No dependency on MyMemo services, accounts or databases. The OpenMyMemo Cloud connector is the one optional piece that talks to MyMemo (the relay and, with the person's consent, MyMemo Memory sync); everything else works without it, and removing it changes nothing else. Code and UI patterns may be borrowed from MyMemo's own apps; other runtime coupling may not.
  • Don't weaken the panel API guard (guard in web.py: Host, Origin, X-OpenMyMemo header) or the /mcp token check.

Commands

uv sync
uv run pytest                               # all tests, including MCP end to end over stdio and real HTTP
uv run ruff check src tests scripts
uv run openmymemo --vault /tmp/v init       # CLI
uv run python scripts/demo_vault.py /tmp/d  # demo data
cd web && pnpm install && pnpm build        # panel → src/openmymemo/static/ (commit the build output)
cd web && pnpm test                         # panel tests (vitest)
cd desktop && pnpm install && pnpm tauri dev # Mac app (needs Rust); `pnpm tauri build` for the .app
python3 scripts/stage_desktop.py && (cd desktop/src-tauri && cargo test)  # Mac or Windows app tests (`python` on Windows)

Code map

FileResponsibility
src/openmymemo/mdfile.pyParse and rewrite topic files (frontmatter, sections, memory lines; format-1 header migration); untouched lines must survive byte for byte
src/openmymemo/vault.pyThe vault: sync (editor edits → meta/history), add/update/archive/restore/rollback, settings, locking; documents (type: document files, product-design.md §23): one doc:<slug> memory each, kept out of memories() and topics() so sync, tidy-up, search by meaning and dedupe never see them; documents(), add_document, update_document
src/openmymemo/topics.pyThe 14 default topics, groups, classification keywords
docs/MEMORY_FORMAT.mdThe folder format; change it before changing what the code reads or writes
docs/distribution.md, llms-install.md, glama.jsonWhere OpenMyMemo is published and listed, the shared listing details, and the setup guide AI agents such as Cline follow; glama.json names who may claim the Glama listing
src/openmymemo/textutil.pySimilarity, search scoring, rule-based classification
src/openmymemo/secrets.pySecret patterns for the Memory safety score (product-design.md §18.2): keys and tokens, passwords, payment cards (Luhn), US SSNs and Chinese resident IDs (check character) in memories outside private topics; reports memory id and kind, never the matched text
src/openmymemo/score.pyThe Memory safety score (product-design.md §18.2): five areas by rules (secrets.py, connector access, stale changes, upkeep, a recent commit whose tree holds every memory file, or a full export (transfer.is_full_export), as backup), dismissals and the last full export in .openmymemo/score.json, one line a day in score.jsonl; issues name memory or app ids and never carry memory text. /api/score, /api/score/dismiss, openmymemo status
src/openmymemo/overview.pyWhat the panel's Home page shows (product-design.md §18.1), served at /api/overview: memories per group, 30-day growth, sources (you, apps, imports), private as a count, each app's last use and 7-day reads/writes, what waits, reads and writes per day, the safety score and its top three issues; never memory text
src/openmymemo/brief.pyThe daily brief (product-design.md §18.3) for one local calendar day, by rules: changes applied per app (private ones only counted), what waits, reads per app with the topics read most, the safety change from score.jsonl, one long-unchanged non-private memory to resurface; quiet when nothing happened; counts_line is the notification text (counts and app names, no memory text). /api/brief, openmymemo brief
src/openmymemo/notices.pyWhich notifications are due (product-design.md §18.4) for the desktop app to show: yesterday's brief (from the set time, skipped when quiet), changes waiting more than 3 days (once a week), new secret-pattern or private-access safety issues (once each; the first look only notes what's there). .openmymemo/notify.json remembers what went out. Counts and app names only. /api/notices, /api/notices/sent
src/openmymemo/feedback.pySend feedback (product-design.md §21): the GitHub issue form and email links with the OpenMyMemo version and system filled in, never anything from the folder; /api/feedback, openmymemo feedback, FeedbackDialog.vue
src/openmymemo/connectors.pyConnector permissions, tokens, revocation tombstones
src/openmymemo/clients.pyThe catalog of AI apps (product-design.md §15.1): detection, status, one-click connect and disconnect by editing an app's MCP config (JSON or Codex TOML) or running its mcp add, and the manual snippets
src/openmymemo/appfiles.pyWriting other apps' files (their MCP configs, Codex's hooks.json): atomic, permissions kept from the first byte, through symlinks, with a one-time <file>.openmymemo-backup
src/openmymemo/proposals.pyProposal lifecycle, dedupe, auto-apply and undo
src/openmymemo/context.pyCompiles what an AI sees (documents first and whole, within half the budget when there are memories too), MEMORY.md, log.md, search (search_documents for documents, by their words)
src/openmymemo/transfer.pyImport (ChatGPT / Claude / Markdown / JSON, and other apps' memory files) and export
src/openmymemo/memfiles.pyFinds other AI apps' memory and instructions files (CLAUDE.md, AGENTS.md, GEMINI.md, rules, memory.md) for import: known names and places only, never a whole tree, nothing else read
src/openmymemo/mcp_server.pyMCP tools (mcp SDK 2.x MCPServer); relayed= builds the OpenMyMemo Cloud variant (queue wording only with cloud.queue_enabled(); never the local ASK_NOTE)
src/openmymemo/ask.pyAsking in the app (product-design.md §22): whether memory_propose asks the person about a change that waits (protected or approval only, never private or sensitive, never relayed, per-app ask), and how: an elicitation/create request during the call up to protocol 2025-11-25, an input_required result with an SDK-sealed request_state from 2026-07-28; the question's wording. Proposals.asked / answered record it; an accept applies as the app's change, into the digest
src/openmymemo/web.pyPanel API, /mcp and /cloud/callback combined into one ASGI app; panel_server() is the uvicorn server that starts OpenMyMemo Cloud once its port is bound
src/openmymemo/cloud.pyOpenMyMemo Cloud (product-design.md §16): the per-computer link (cloud.json, never in the folder), linking with PKCE and a loopback callback, and the bridge: one outbound WebSocket that answers relayed tool calls as cloud-<slug> connectors and files the offline queue (HPKE-sealed proposals) through proposals.py, and carries MyMemo Memory sync's frames for sync.py when the person turned it on. The wire format is pinned by tests/fixtures/cloud/ (the MyMemo service tests against the same files); tests/cloud_fake.py is a fake service built from it
src/openmymemo/sync.pyMyMemo Memory sync (product-design.md §20), off until the person turns it on: the per-computer sync.json next to cloud.json (consent, picked private topics, cursors and hashes of what was sent; never memory text, never in the folder), building sync_push frames from the folder (private topics only when picked; a tombstone when a memory turns private), filing sync_ops from MyMemo (its AI's and web apps' proposals through proposals.py as cloud-* connectors, the person's own MyMemo edits as actor: user edits, the first merge's memories as cloud-mymemo proposals after the preview, which never expire: MyMemo keeps a memory that waits until the person decides it) and reporting their outcomes, later decisions included. The wire format is pinned by tests/fixtures/cloud/sync/
src/openmymemo/assistant/OpenMyMemo Assistant (product-design.md §17), off by default: settings.py (per-computer assistant.json next to cloud.json, Keychain on macOS, OPENMYMEMO_ASSISTANT_* overrides, monthly usage), client.py (OpenAI-compatible chat or Anthropic Messages over httpx2, and task for MyMemo's hosted model, which takes only a fixed task name and the material; TRANSPORT is the test hook), schema.py (checks the model's JSON), guard.py (what may be sent: read scope, private topics, and a search of everything outgoing for withheld text), core.py (Assistant: available(feature), json_call(...) that returns None instead of raising, propose(...) as connector assistant; privacy and spending rules are enforced here, not in callers), features.py (model-powered import splitting with the rule parser as cross-check, and sort suggestions), tidy.py (Tidy up, §17.6: near-duplicate candidates from textutil.similarity, chunked calls with a per-run call limit and a dry-run estimate, one batch_id of proposals, "not twice" by a fingerprint in idempotency_key, and the per-computer schedule that Scheduler runs inside the panel's process), checks.py (the second look at an app's proposal within check_budget, called by Proposals.propose(check=True); only ever more cautious), chats.py (reading ChatGPT/Claude exports and Claude Code/Codex transcripts in known shapes, chunking newest first with private text left out, the cost estimate, extraction with evidence, ChatImport for the import preview), tell.py (Tell OpenMyMemo, §19: preview turns what the person typed into add/update/archive changes against the memories search and the profile topics give, checks the answer, falls back to rules; apply saves what the person kept as their own edits, version-checked; /api/tell/preview, /api/tell/apply), session.py (openmymemo session-end --hook: per-app consent in assistant.json, a detached worker that files the Assistant's proposals from a transcript), mymemo.py (MyMemo's hosted model, §17.8, offered to everyone unless OPENMYMEMO_ASSISTANT_MYMEMO=0 turns it off on a computer where the settings don't already use it (settings.mymemo_offered); the plan's monthly use in dollars from /models (usage.cost_usd, cost_usd_included: cost_text, the meter's usage_bar/used_share) and a limited-time offer (cost_usd_regular_included, offer_ends_at: offer_text, includes_text), nothing hard-coded about price, allowance or offer: token exchange of the OpenMyMemo Cloud device token or PKCE sign-in through cloud.py's Linker and /cloud/callback, tokens refreshed with rotation, every request bound to the sign-in (generation and service) it started with, the service's 402/429/503 kept as pauses that send features to their rules, sign-out with revoke; tests/assistant_fake.py is its fake service, from tests/fixtures/cloud/assistant/). Every feature keeps its rule-based path as the fallback
src/openmymemo/recall/Recall (product-design.md §17.4): hybrid.py (search: keyword search fused with vectors by reciprocal rank fusion, exact matches first, the Assistant's query expansion and rerank with model=True; recall for openmymemo recall; similar for checking proposals and tidy-up), index.py (the plain-file cache in .openmymemo/index/: incremental by content hash, one model per index, flock + atomic replace), embed.py (the Embedder interface: the local ONNX model, or the Assistant endpoint's /embeddings, which never gets private topics from a remote model), local.py (the list of local models, SHA-256 pins in model_pins.json, downloads into the per-computer folder, the optional openmymemo[semantic] runtime), semantic.py (the switch: status, on, off). With no index and no model help, search returns exactly context.search's results
src/openmymemo/cli.pyTyper CLI
src/openmymemo/doctor.pyopenmymemo doctor: setup checks (folder, uv, panel port, each app's config and which folder it uses, OpenMyMemo Cloud) that print paths and counts, never memories, and never write: it parses the topic files itself instead of calling Vault.sync()
src/openmymemo/codex.pyCodex session hook: merges it into ~/.codex/hooks.json and takes it out again (Codex doesn't run plugin hooks)
web/Vue 3 + Tailwind v4 panel source; all copy lives in web/src/i18n.ts
web/src/components/ConnectApps.vueThe app list with Connect / Disconnect / Set up, used by the Connectors page and the first-run guide; ConnectNote shows what's left to do, ConnectorPanel a connected app's permissions, CloudRow the OpenMyMemo Cloud row (sign-in, status, setup for ChatGPT and claude.ai, its web apps)
web/src/views/DocumentsView.vueThe Documents page (product-design.md §23.4): list, read, edit with a live diff and a version check (409 when it changed elsewhere), private switch, rename, versions, archive and restore; diff.ts is the line diff, and DocumentDiff shows it here and on the Changes page
web/src/desktop.tsThe Mac layout switch (?desktop=1), the shell's commands and shortcuts; MemoriesDesktopView, MemoryInspector, DesktopSidebar, DesktopToolbar are its screens; memorySaves.ts queues the inspector's saves per memory. PageHeader becomes the window toolbar there
desktop/Mac and Windows app (Tauri 2, product-design.md §14, §15.2): src-tauri/src/core.rs installs the core (non-editable) and finds or starts the server for the folder, launcher.rs writes the openmymemo launcher AI apps run on a Mac, winlauncher.rs installs desktop/launcher (a small program, since Windows has no sh) as that command on Windows, install.rs moves the app from the disk image to Applications, main.rs has the window, menus, menu-bar item, notifications, settings and link handling; tauri.windows.conf.json makes the Windows installer (NSIS, per user); scripts/stage_desktop.py stages the core, uv and on Windows the launcher before each build
.claude-plugin/Claude Code plugin manifest and marketplace (the repo root is the plugin)
plugin.json, mcp.json, .agents/plugins/Codex plugin (Agent Plugins format) and its marketplace
skills/Skills shared by the Claude Code and Codex plugins
integrations/hooks/Session-start and session-end hook scripts shared by Claude Code (plugin hooks SessionStart and SessionEnd in integrations/claude-code/hooks/hooks.json) and Codex (user-level SessionStart and Stop hooks installed by setup codex; integrations/codex/setup.sh runs it from the installed plugin). The session-end one prints nothing, always exits 0 and hands the work to a background process
integrations/claude-desktop/.mcpb manifest; build with scripts/build_mcpb.py
integrations/icons/, web/public/logo.png, .claude-plugin/icon.pngThe OpenMyMemo logo at each size (black on a white rounded square), rendered from integrations/icons/logo.svg by scripts/make_icons.py; .claude-plugin/icon.png is the listing icon in Claude's plugin directory, which takes it only from the first submission

Conventions

  • Everything user-facing is English: docs, panel copy, CLI output, MCP tool names and descriptions. Chinese belongs only in data handling (classifier keywords, parsing pasted pages, test fixtures), because users' memories may be in Chinese.
  • File formats (memories/*.md, connectors.yaml, .openmymemo/*) are a public contract specified in docs/MEMORY_FORMAT.md: change the spec first and keep reading older files.
  • Topic slugs are the file names; titles come from the files.
  • All writes go through Vault methods, which lock, re-read from disk, write atomically and update meta and history.
  • The mcp SDK is 2.x: from mcp.server.mcpserver import MCPServer, Context; static resources can't take a Context.
  • Plugins run uv run from the installed copy of this repo, so anything the package needs at runtime must be inside the repo (and inside the .mcpb staging list in scripts/build_mcpb.py). Keep the version in pyproject.toml, src/openmymemo/__init__.py, both plugin.json files, server.json (the MCP Registry entry, both of its versions), the .mcpb manifest, web/package.json, the Mac app (desktop/package.json, desktop/src-tauri/tauri.conf.json, desktop/src-tauri/Cargo.toml) and the version line at the top of README.md in sync (tests/test_packaging.py checks), and run uv lock after a bump.
  • CI (.github/workflows/ci.yml) is three jobs, one per runner: the Python tests and lint on Linux (Python 3.11 and 3.13), the Python tests and the Mac app's tests on macOS (Python 3.12), and the panel (its tests, and that the committed build matches web/) with packing the .mcpb. The main ruleset requires these three checks by name, so renaming a job means updating it. To release: bump the version, merge, then push a tag v<version>; .github/workflows/release.yml publishes the .mcpb, wheel and sdist as a GitHub release, the wheel and sdist on PyPI (trusted publishing, environment pypi), and then server.json on the MCP Registry (GitHub OIDC; the registry checks the mcp-name: line in README.md, so keep it).
  • Don't add a root .mcp.json: Claude Code would treat it as project config for everyone working on this repo. The Claude Code MCP server is declared inline in .claude-plugin/plugin.json.
  • Commit messages are imperative English; one topic per PR.
  • OpenMyMemo Cloud (called MyMemo Cloud until its launch on 2026-10-19; the id stays mymemo-cloud) is listed by default and does nothing until the person signs in; it can be hidden in Settings (or openmymemo cloud settings --hide) and is always listed while linked (product-design.md §16.11). settings.json is format 2: an older file's show is ignored, because 0.2.8 and older wrote "show": false as their default. Only the live relay is launched: cloud.FEATURES stays empty, so hello() doesn't advertise queue, and nothing user-facing may promise the offline queue until both sides turn it on; cloud.queue_enabled() (the same constant) keeps welcome.queued and a plan's queue out of the panel and the CLI, leaves item frames unfiled and unacknowledged, and the queue wording out of the relayed tool descriptors (tests/fixtures/cloud/bridge/hello.json). It reads OPENMYMEMO_CLOUD_URL (the service; overrides the one chosen in Settings, default https://api.mymemo.ai) and OPENMYMEMO_CLOUD_DIR (the folder of cloud.json and settings.json). tests/conftest.py gives every test its own HOME, cloud folder and a local URL; set both yourself before trying openmymemo cloud … or the panel's sign-in by hand, so nothing touches your real link or MyMemo.
  • MyMemo Memory sync (product-design.md §20, sync.py) is off until the person turns it on, a consent of its own on a linked computer; hello() lists sync only then (read from sync.json at each connection, so cloud.FEATURES and queue_enabled() are unchanged), and turning it on or off makes the bridge say hello again. Its state is sync.json next to cloud.json, bound to the link's device, and never holds memory text. What comes from MyMemo is filed through proposals.py as cloud-* connectors, except the person's own edits on MyMemo's memory page (from: "user"), which are applied as theirs after a version check. Tests drive it with FakeSync in tests/cloud_fake.py; the frames are pinned by tests/fixtures/cloud/sync/, byte-identical in the MyMemo service (tests/test_sync.py checks the folder's digest).
  • The OpenMyMemo Assistant is off until turned on in Settings → Assistant or with openmymemo assistant set. Code that uses it builds Assistant.from_settings(vault), checks available(feature), calls json_call with material in Data blocks (never mixed into the instructions; memories through assistant.memory_data(...), topic lists from assistant.topic_choices(), both of which leave out what may not be sent; guard.py refuses anything else that would leak) and falls back to the rule path on None; it writes only through Assistant.propose. Tests use a fake endpoint (openmymemo.assistant.client.TRANSPORT, an httpx2.MockTransport); tests/conftest.py keeps the Keychain and the shell's OPENMYMEMO_ASSISTANT_* variables out.
  • Search by meaning is optional twice over: the local model is opt-in (Settings → Assistant → "Search by meaning on this computer", openmymemo semantic on), downloaded on demand, never bundled; onnxruntime and tokenizers are the semantic extra, never default dependencies. A model is downloadable only once its files are pinned in src/openmymemo/recall/model_pins.json by scripts/pin_embedding_models.py. Tests never download: tests/recall/recall_harness.py has a deterministic stand-in embedder and replays recorded model answers; tests/recall/ is the recall test set (hit@k must not fall below baseline.json).
  • The Mac app adds nothing to the panel's API: it is the same panel in another layout. New panel features go into the web screens; give the Mac layout its own version only where the design has one. A native command the panel calls must be listed in desktop/src-tauri/build.rs and granted in capabilities/default.json, because the panel is a remote origin to Tauri.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.