Skip to main content

RemaGraph

License: Apache-2.0 PyPI CI Python 3.11+

Ruff Checked with mypy REUSE status PRs Welcome

Ko-fi PayPal

Every agent leaves a trace. RemaGraph is a lightweight MCP tool that captures what an AI coding agent leaves behind while it works, so whoever picks up next can follow the trail.


RemaGraph is a lightweight MCP (Model Context Protocol) tool built for AI coding agents that work across many tasks and hand-offs without a human in the loop for every step. Its job is simple: capture what an agent learned, decided, or ran into along the way, and make that trail retrievable later — by the same agent, or by a completely different one picking up the work. It complements CodeGraph: CodeGraph tracks what's structurally wrong with the code; RemaGraph tracks what happened while someone (or something) was working on it.

Item Status
Version 0.7.1-beta (pre-1.0 beta; published on PyPIuv tool install remagraph / pip install remagraph)
Status v2: security / governance / reliability + cross-project collaboration + CLI (init/auto/store/search/status/maintain/link/migrate-project/install-hooks/serve)
Task memory convention docs/task-memory-convention.md
Release prep docs/reviews/v2-release-prep.md
Design SOT DESIGN.md
v1 closeout status docs/reviews/v1-closeout-status.md
Architecture docs/architecture.md
Audit contract docs/audit.md
Governance checklist docs/governance/checklist.md
Contributing CONTRIBUTING.md
Changelog CHANGELOG.md

Installation

RemaGraph is published on PyPI. Recommended install:

uv tool install remagraph

or with plain pip:

pip install remagraph

Prefer a specific tag, or want the bleeding edge from main? Install straight from the git repo:

# Pinned to a specific release tag
uv tool install git+https://github.com/aiken884/RemaGraph.git@v0.7.1-beta

# Whatever is currently on main
uv tool install git+https://github.com/aiken884/RemaGraph.git

Or install from source for local development:

git clone https://github.com/aiken884/RemaGraph.git
cd RemaGraph
uv pip install -e .

Dependencies: Python ≥3.11, model2vec, mcp (FastMCP), pydantic.

Quick Start (5 minutes, no coding required)

  1. Install (see "Installation" above).
  2. Initialize:
    remagraph init --project myproject
    source ~/.local/state/remagraph-myproject/env.sh
    
  3. Run a task in one shot — reads memory, executes, writes memory back:
     remagraph auto --task-id fix-login-001 --agent-id my-ai -- echo "swap this for your actual command"
    
    or use the wrapper script:
    curl -O https://raw.githubusercontent.com/aiken884/RemaGraph/main/examples/simple/remagraph-task.sh
    chmod +x remagraph-task.sh
    TASK_ID=fix-login-001 AGENT_ID=my-ai ./remagraph-task.sh python my_agent.py
    

If you just want to check memory first, with no execution and no writes:

remagraph auto --recall-only --task-id fix-login-001 --agent-id my-ai

No code required. Full plain-language walkthrough: docs/task-memory-convention.md.

New users may also find docs/internal/alpha-test-playbook.md useful as an onboarding guide — it includes scenarios and a feedback template.

Note: this repository is public and the package is published on PyPI, but it's still a pre-1.0 beta (see BOUNDARIES.md — no frozen public API yet).

MCP Quick Start

1. MCP client configuration

Point any MCP client at RemaGraph. Example configs for common clients follow.

Note (since the BUG 1 fix): remagraph serve now must be bound to a single project at startup — via either the --project <id> argument or the REMAGRAPH_PROJECT environment variable. If neither is set, it fails fast and never enters the MCP stdio loop, which prevents a process from silently reading and writing across projects if it happens to inherit another project's environment variables. Each project maps to its own dedicated remagraph serve process; a single running process cannot switch between projects dynamically.

Claude Desktop (claude_desktop_config.json):

{
  "mcpServers": {
    "remagraph": {
      "command": "remagraph",
      "args": ["serve", "--project", "myproject"],
      "env": {
        "REMAGRAPH_STATE_DIR": "/home/user/.local/state/remagraph-myproject"
      }
    }
  }
}

Cursor (.cursor/mcp.json):

{
  "mcpServers": {
    "remagraph": {
      "command": "remagraph",
      "args": ["serve"],
      "env": {
        "REMAGRAPH_PROJECT": "myproject"
      }
    }
  }
}

OpenCode / Claude Code — any client that supports stdio MCP works the same way as above.

2. Environment variables

Variable Description Default
REMAGRAPH_STATE_DIR Directory where the SQLite DB lives ~/.local/state/remagraph/
REMAGRAPH_PROJECT The current project binding (remagraph serve requires either this env var or --project at startup) none
REMAGRAPH_FANOUT_CAP Max number of "other" project database connections search --cross-project-label/--include-related will open in a single call (--fanout-cap takes precedence over this env var) 50
REMAGRAPH_FANOUT_HARD_CAP Hard ceiling for the cap above, only meant for explicit opt-in increases (rarely needs adjusting) 200
REMAGRAPH_RESTRICTED_PREFIXES Comma-separated list of project_id prefixes (e.g. "team-a-,team-b-") that a deployment wants to forbid from ever using the default DB; the safety valve raises SafetyValveError if a matching project_id resolves to the default state dir. Empty by default — RemaGraph imposes no naming convention of its own none (no prefix restricted)

Directories are created automatically when missing (mode 0700); DB files are created at mode 0600. Paths are checked against a security denylist that rejects system directories.

3. CLI basics

# Start the stdio MCP server (must be bound to a single project via --project or REMAGRAPH_PROJECT)
remagraph serve --project myproject

# Initialize / run a task in one shot
remagraph init --project myproject
remagraph auto --task-id T001 --agent-id my-agent -- make test

# Query (task-id alone is fine)
remagraph search --task-id T001
remagraph search --query "FastMCP lifecycle" --top-k 5
remagraph status --limit 10

MCP Tools

RemaGraph exposes five tools over MCP (stdio transport), compatible with Claude Desktop, Cursor, and other mainstream MCP clients: remagraph_store, remagraph_search, remagraph_status, remagraph_maintain, and remagraph_migrate_project.

remagraph_store — write memory

An agent writes a memory record; it must pass five arbitration rules before landing in SQLite + the FTS5 index.

Parameter Type Description
project_id str Project identifier (same format rules as task_id, required)
task_id str Task identifier (alphanumeric plus -_, max 64 characters)
agent_id str Agent identifier (same format constraints as task_id)
kind "task_handoff" | "status_update" | "discovered_constraint" | "fleet_member" Memory kind (fleet_member is recorded/recycled by the dispatching coordinator)
summary str One-line summary (indexed for FTS5 full-text search)
learnings list[str] Key takeaways
handoff_note str Hand-off note (required when kind is task_handoff)
tags list[str] Free-form classification tags (optional)
invalidates list[str] Memory IDs to invalidate (used with discovered_constraint)
labels list[str] Namespaced labels (optional), in namespace:value form (e.g. dep:opencode, topic:auth, kind:bug). Convention is a small, controlled set of namespace prefixes such as dep:/topic:/kind:; max length 64 characters. This is a distinct concept from tagstags is free-form, labels is a controlled vocabulary, and a batch with any malformed label is rejected outright (reason: "invalid_label"). Used for exact matching by remagraph_search's cross_project_label; see the "Cross-Project Collaboration" section of DESIGN.md

Behavior of the four kind values (PPLX Priority B):

  • task_handoff — a task hand-off record, carries handoff_note
  • status_update — a status update; automatically supersedes the prior record for the same task_id
  • discovered_constraint — a newly discovered constraint; can invalidates existing, now-wrong memories
  • fleet_member — owned by the dispatching coordinator, records/recycles fleet members (task_id=fleet auto-supersedes)

remagraph_search — query memory

FTS5 BM25 full-text search (trigram tokenizer, CJK-aware) plus tag/kind/agent_id/task_id filtering.

Parameter Type Description
query str Search keywords (Chinese, English, Japanese, and Korean all supported)
top_k int Max results to return (default 20, max 100)
kind str Filter by memory kind (optional)
status "active" | "superseded" | "invalidated" Filter by status (optional)
tags list[str] Filter by tags (optional)
project_id str Restrict to a single project (optional)
agent_id str Filter by agent (optional)
task_id str Filter by task (optional)
all_projects bool Default false; when true, removes the project_id filter within "this one database file" — each project is its own independent SQLite file, and this flag never opens any other file
cross_project_label str Optional. When provided, this switches entirely to the cross-project label search path: via the shared project registry, it runs an exact label match across the current project plus every other known project, each its own independent database file (full-text/filter params like query/kind/tags don't apply on this path). Orthogonal to all_projects — the two are independent dimensions. Fan-out is capped at 50 "other" known projects; beyond that, the response is flagged cross_project_fanout_capped: true (see response fields below) instead of silently truncating and pretending the result set is complete. See the "Cross-Project Collaboration" section of DESIGN.md
include_related bool Default false. A third, fully independent dimension from cross_project_label/all_projects: when true, fans out — in addition to the normal FTS query against the current project — to projects found within related_hops via a project_edges traversal (db.recall_related()), i.e. projects explicitly declared as related through the remagraph link CLI subcommand. Unlike cross_project_label, matching is still by the normal FTS query, not exact label match. Requires project_id as the traversal starting point; if project_id is omitted, this gracefully degrades to an ordinary search (no related fan-out) rather than raising an error
related_hops int Default 1 (only directly-declared relations). Max 5. BFS traversal depth used when include_related=true; has no effect otherwise

Short queries (≤2 characters) return an empty result set instead of raising an error. Beyond results/has_more, every response always carries cross_project_fanout_capped (bool; only meaningful when cross_project_label is used — ordinary queries always get false). When cross_project_label is used, each result also carries source_project_id marking which project it came from. Every result includes the full field set (id/project_id/summary/agent_id/kind/task_id/timestamp/score/learnings/handoff_note/tags/status/created_at/updated_at — everything except embedding).

remagraph_status — query a project's latest state

Returns all active status_update memories, deduplicated by task_id (only the newest record per task survives). Also includes version-compatibility handshake info, so callers don't have to wait for a remagraph_store write to fail before learning about a version mismatch.

Parameter Type Description
project_id str Restrict to a single project (optional)
limit int Max results to return (default 20, max 100)
all_projects bool Default false; true removes the project_id filter

Beyond the existing latest array, the response always includes these compatibility handshake fields:

Field Type Description
server_code_version int Schema version of the code currently running
db_schema_version int | null The schema version actually recorded in the database's _meta table (a defensive read)
min_reader_version int | null Oldest code version allowed to read this database; null if the database predates this mechanism
min_writer_version int | null Oldest code version allowed to write to this database; same null behavior as above
upgrade_hint str | null Upgrade guidance text embedded in the database; null if absent
read_only bool Whether the current connection is in read-only degraded mode (see "Governance & Security" below)

remagraph_maintain — run DB maintenance

Runs automatic database maintenance (WAL checkpoint, prune superseded/invalidated memories, FTS5 optimize, VACUUM, integrity check), gated by the same safety valve (maintenance.safety_validate_project) used by the CLI maintain subcommand.

Parameter Type Description
project_id str Project to run maintenance on (required)
force bool Default false; when true, every maintenance step runs unconditionally instead of only the ones whose threshold has actually been crossed

Note: unlike the CLI maintain subcommand, this MCP tool has no dry_run option — every call executes for real.

Response (success): {"status": "ok", "stats": {...}}. Response (failure): {"status": "error", "reason": "..."}.

stats is produced by maintenance.run_maintenance(); most fields only appear when the corresponding step actually ran:

Field Type Description
project_id str Echoes the project maintained
started_at str ISO-8601 UTC timestamp when maintenance started
wal_checkpoint str "done" if PRAGMA wal_checkpoint(TRUNCATE) ran
pruned_count int Number of superseded/invalidated memories deleted (older than prune_superseded_age_days, default 90 days; capped per task by prune_superseded_max_per_task, default 5)
fts_optimized bool true if the FTS5 index was optimized
vacuum str "done" if VACUUM ran (triggered once DB file size exceeds vacuum_threshold_mb, default 50 MB)
size_before_mb float DB file size in MB immediately before VACUUM; only present when vacuum ran
integrity str Result of PRAGMA quick_check; expected "ok" — any other value raises and is recorded as an audit violation
skipped bool true when the connection was already downgraded to the read-only schema tier (see "Version Compatibility" in DESIGN.md); every write step above is skipped entirely
skip_reason str "read_only_schema_tier" when skipped is true

remagraph_migrate_project — one-time cross-project migration

One-time migration of memories from a source project to a target project's independent DB (e.g. defaultproject-a), marking the originals invalidated in the source. Performs a real migration — this tool and the CLI's migrate-project subcommand (cli.cmd_migrate_project) both call the same shared core implementation (store.migrate_project_memories), so they always produce the same end state for the same inputs.

Parameter Type Description
from_project str Source project (required)
to_project str Target project (required)
dry_run bool Default false; when true, only computes and reports how many records would be migrated — no writes happen, and the count uses the exact same match query as a real run, so it always agrees with the count a subsequent real run reports

How it works:

  1. The target project is validated through the same safety_validate_project(to_project, require_env_match=False) safety valve used elsewhere (project-id naming-convention rules, project.json metadata consistency, etc).
  2. The source project's state_dir is resolved via the shared project registry (db.get_registered_state_dir(from_project)) — not a hardcoded path. If from_project has never been registered (no prior remagraph command has resolved a state_dir for it), the call fails with a clear error rather than silently treating it as zero migratable records. from_project == "default" is the one exception: it resolves via the ambient REMAGRAPH_STATE_DIR/REMAGRAPH_HOME the same way any other "default"-project usage does, since "default" is deliberately never registered in the normal course of things.
  3. Records that heuristically look like they belong to to_project (a LIKE match against task_id/tags/agent_id/summary) are copied into the target project's own DB with project_id forced to to_project, and the originals are marked status='invalidated' in the source with a migrated-to:<to_project> breadcrumb appended to learnings.
  4. If either the source or target database is currently in the read-only degraded schema-compatibility tier (see "Version Compatibility" below), the migration is rejected with a clear error instead of failing silently or partially.

Response (success): {"status": "ok" | "dry-run", "from": "...", "to": "...", "dry_run": true|false, "migrated_count": N, "skipped_ids": [...]}. Response (failure): {"status": "error", "reason": "..."}.

Governance & Security

  • Rate limiting — per-agent token bucket (60 calls / 60 seconds) to prevent abuse
  • Input validationtask_id / agent_id are checked against format rules via Pydantic validators
  • Path safetyREMAGRAPH_STATE_DIR rejects system directory paths
  • Audit rotationaudit-YYYYMM.jsonl, split automatically by month
  • DB size cap — SQLite max_page_count set to a 100MB soft limit
  • Migration — built-in schema version tracking and a migration chain
  • Version-compatibility degradation — when a database's schema version is newer than the running code, the database's own min_reader_version/min_writer_version decide one of three outcomes: fully compatible (normal reads and writes), read-only degraded (writes rejected, reads unaffected), or refused outright. Callers can learn this ahead of time via remagraph_status's compatibility handshake fields, without waiting for a write to fail. See the "Version Compatibility" section of DESIGN.md
  • Cross-project registryproject_registry automatically records known projects and their state_dir, backing remagraph_search's cross_project_label read-only cross-project lookups. See the "Cross-Project Collaboration" section of DESIGN.md
  • Stale-record cleanupcleanup_superseded() can purge non-active records older than 90 days

CLI Subcommands (for headless agents)

Besides MCP mode, remagraph supports the following CLI subcommands (all with JSON output):

# One-shot, most recommended: read memory → run the command → write memory
remagraph auto --task-id task-001 --agent-id my-agent -- make test

# Initialize
remagraph init --project myproject

# Write memory
remagraph store \
  --task-id task-001 --agent-id my-agent --kind status_update \
  --summary "Task complete, all tests passing, no regressions found" \
  --learnings '["Watch out for FastMCP lifecycle handling"]' \
  --tags '["python","mcp"]'

# Query (task-id alone is fine, query is not required)
remagraph search --task-id task-001
remagraph search --query "FastMCP lifecycle" --top-k 5

# Query latest status
remagraph status --limit 10

Plain-language convention: docs/task-memory-convention.md. Full spec: DESIGN.md; audit contract: docs/audit.md.

Development & Verification

# uv is recommended
uv sync --all-extras
uv run ruff check src tests
uv run mypy src/
uv run pytest -m 'not slow'
REMAGRAPH_STATE_DIR=$(mktemp -d) uv run pytest tests/smoke
  • CI pipeline: smoke → adversarial → lint (ruff + mypy) → test (coverage ≥80%); plus gitleaks, pip-audit, and mutmut (non-blocking).
  • Never let tests default to writing production state — smoke tests must use REMAGRAPH_STATE_DIR or pytest's tmp_path.

Resources

License

Apache-2.0. RemaGraph is an independent project — its source code is entirely self-authored and does not contain or derive from any other project's code.

Support

If RemaGraph is quietly keeping your agents' memory straight, you can support its development on Ko-fi (card or PayPal) or directly via PayPal. Entirely optional — RemaGraph is, and stays, free.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

remagraph-0.7.1.tar.gz (613.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

remagraph-0.7.1-py3-none-any.whl (144.7 kB view details)

Uploaded Python 3

File details

Details for the file remagraph-0.7.1.tar.gz.

File metadata

  • Download URL: remagraph-0.7.1.tar.gz
  • Upload date:
  • Size: 613.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for remagraph-0.7.1.tar.gz
Algorithm Hash digest
SHA256 2faa866d6c4c084a71c7678ec4f5e793fa9e8e367f5109fe0bb9f141dfa4bbd1
MD5 141514ac2fceee1e56e1ee73b9288aff
BLAKE2b-256 8cb6ab89d780da8c35d8ee569d6c3d7685ba3b8b0fb3426b5ea796aa59e5a57e

See more details on using hashes here.

Provenance

The following attestation bundles were made for remagraph-0.7.1.tar.gz:

Publisher: publish.yml on aiken884/RemaGraph

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file remagraph-0.7.1-py3-none-any.whl.

File metadata

  • Download URL: remagraph-0.7.1-py3-none-any.whl
  • Upload date:
  • Size: 144.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for remagraph-0.7.1-py3-none-any.whl
Algorithm Hash digest
SHA256 4f0d29c821aa33749cdb17b84d19ded08435307b190ae9e3505a93e001883d2b
MD5 12ff37cf0625a64d5eed4eab655f9a66
BLAKE2b-256 7da8c3f011480f978220fc598694657ba59f113f4353a3129c6f1f5ae3009eda

See more details on using hashes here.

Provenance

The following attestation bundles were made for remagraph-0.7.1-py3-none-any.whl:

Publisher: publish.yml on aiken884/RemaGraph

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page