RemaGraph
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.6.4-beta (pre-1.0 beta; published on PyPI — uv 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.6.4-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)
- Install (see "Installation" above).
- Initialize:
remagraph init --project myproject source ~/.local/state/remagraph-myproject/env.sh
- 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 tags — tags 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, carrieshandoff_notestatus_update— a status update; automatically supersedes the prior record for the sametask_iddiscovered_constraint— a newly discovered constraint; caninvalidatesexisting, now-wrong memoriesfleet_member— owned by the dispatching coordinator, records/recycles fleet members (task_id=fleetauto-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. default → project-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:
- 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.jsonmetadata consistency, etc). - The source project's
state_diris resolved via the shared project registry (db.get_registered_state_dir(from_project)) — not a hardcoded path. Iffrom_projecthas never been registered (no priorremagraphcommand 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 ambientREMAGRAPH_STATE_DIR/REMAGRAPH_HOMEthe same way any other "default"-project usage does, since"default"is deliberately never registered in the normal course of things. - Records that heuristically look like they belong to
to_project(aLIKEmatch againsttask_id/tags/agent_id/summary) are copied into the target project's own DB withproject_idforced toto_project, and the originals are markedstatus='invalidated'in the source with amigrated-to:<to_project>breadcrumb appended tolearnings. - 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 validation —
task_id/agent_idare checked against format rules via Pydantic validators - Path safety —
REMAGRAPH_STATE_DIRrejects system directory paths - Audit rotation —
audit-YYYYMM.jsonl, split automatically by month - DB size cap — SQLite
max_page_countset 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_versiondecide 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 viaremagraph_status's compatibility handshake fields, without waiting for a write to fail. See the "Version Compatibility" section ofDESIGN.md - Cross-project registry —
project_registryautomatically records known projects and theirstate_dir, backingremagraph_search'scross_project_labelread-only cross-project lookups. See the "Cross-Project Collaboration" section ofDESIGN.md - Stale-record cleanup —
cleanup_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_DIRor pytest'stmp_path.
Resources
DESIGN.md— the design source of truth: schema, arbitration rules, cross-project collaboration, version compatibilityCHANGELOG.md— version historyCONTRIBUTING.md— how to contributeSECURITY.md— how to report a vulnerabilitydocs/architecture.md— system architecturedocs/task-memory-convention.md— plain-language guide to the task-memory conventiondocs/audit.md— the audit log contractdocs/governance/checklist.md— the governance checklist
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file remagraph-0.6.4.tar.gz.
File metadata
- Download URL: remagraph-0.6.4.tar.gz
- Upload date:
- Size: 590.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2ca4729a958bf6ec0efacc720d8d026e29c6bb91472d9ad277b498c23821bc72
|
|
| MD5 |
a02ff0d19efdda74cb6b8a993478b5ce
|
|
| BLAKE2b-256 |
d3603c02ef89fc2e82002831399a9f8d88ac7d9b60f93b0eb8e8c5a7da2b31ae
|
Provenance
The following attestation bundles were made for remagraph-0.6.4.tar.gz:
Publisher:
publish.yml on aiken884/RemaGraph
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
remagraph-0.6.4.tar.gz -
Subject digest:
2ca4729a958bf6ec0efacc720d8d026e29c6bb91472d9ad277b498c23821bc72 - Sigstore transparency entry: 2472961331
- Sigstore integration time:
-
Permalink:
aiken884/RemaGraph@eae974b19f3773638cffe0d63d00e6218efb3adc -
Branch / Tag:
refs/tags/v0.6.4-beta - Owner: https://github.com/aiken884
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@eae974b19f3773638cffe0d63d00e6218efb3adc -
Trigger Event:
push
-
Statement type:
File details
Details for the file remagraph-0.6.4-py3-none-any.whl.
File metadata
- Download URL: remagraph-0.6.4-py3-none-any.whl
- Upload date:
- Size: 135.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ccb919209ae5f9eec903f309af217f7edd5ce8511273b663ed2138d7a1d5c158
|
|
| MD5 |
584a41bdf8816685f90a218f225aae61
|
|
| BLAKE2b-256 |
cc9904fcb781cdbc0ee0226b99045b240ac509d2f35ae62540e8815b2fa31349
|
Provenance
The following attestation bundles were made for remagraph-0.6.4-py3-none-any.whl:
Publisher:
publish.yml on aiken884/RemaGraph
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
remagraph-0.6.4-py3-none-any.whl -
Subject digest:
ccb919209ae5f9eec903f309af217f7edd5ce8511273b663ed2138d7a1d5c158 - Sigstore transparency entry: 2472961400
- Sigstore integration time:
-
Permalink:
aiken884/RemaGraph@eae974b19f3773638cffe0d63d00e6218efb3adc -
Branch / Tag:
refs/tags/v0.6.4-beta - Owner: https://github.com/aiken884
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@eae974b19f3773638cffe0d63d00e6218efb3adc -
Trigger Event:
push
-
Statement type: