@aabadin/project-memory-context
v0.8.2
Published
Portable project memory context CLI — bootstraps semantic enrichment workflows for any AI coding agent.
Maintainers
Readme
@aabadin/project-memory-context (PMC)
Portable project memory context — bootstraps semantic enrichment workflows for any AI coding agent.
pmc installs, configures, and runs a complete pipeline that:
- Maps your codebase into a knowledge graph (via graphifyy)
- Extracts every top-level symbol (functions, classes, interfaces, etc.)
- Enriches each symbol with LLM-generated semantics (responsibility, inputs, outputs, dependencies)
- Persists everything as searchable memories that survive across sessions
This gives your AI agent persistent, recallable knowledge of your entire codebase without re-reading files.
Table of Contents
- Concept & Objective
- Architecture
- Models
- Installation
- Setup
- CLI Reference
- Environment Variables
- OpenCode Session Startup
- OpenCode Auto-Refresh Hook
- Recommended Optional Plugin: opencode-pty
- Project Structure
- 9 Base Project-Context Memories
- Credits
Concept & Objective
AI coding agents (OpenCode, Claude Code, Cursor, etc.) work within a single session. When a session ends, the agent forgets everything it learned about your codebase.
Project-Memory-Context (PMC) solves this by creating a persistent semantic layer between your codebase and your agent:
| Component | What it does | |---|---| | Visit (graphifyy) | AST-level static analysis — builds a dependency graph of your entire codebase | | Symbol extraction | Regex+parser extraction of all top-level symbols (classes, functions, interfaces, etc.) | | Semantic enrichment | Calls a local LLM (Ollama) to describe each symbol's responsibility, inputs, outputs, and role | | Agent Memory | Stores each enriched symbol as a searchable vector memory (hybrid BM25 + semantic) | | Project Context | 9 auto-generated "base memories" about your project's stack, structure, architecture, etc. |
The result: your agent can recall what a file does, how symbols connect, and what the project architecture looks like — across sessions, without re-scanning.
Architecture
┌─────────────────────────────────────────────────────────────────────┐
│ PMC Package (@aabadin/...) │
│ │
│ cli/setup.mjs cli/bootstrap.mjs cli/enrich-queue.mjs│
│ cli/context.mjs cli/project-context.mjs cli/doctor.mjs │
│ cli/build-worklist.mjs cli/enrich.mjs cli/status.mjs │
│ cli/sanitize.mjs cli/finalize.mjs ... │
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ src/ │ templates/ │ │
│ │ ├── providers/ │ ├── opencode/ (commands, │ │
│ │ │ ├── local-model-provider │ │ agents, autostart) │ │
│ │ │ └── cloud-api-provider │ ├── claude-code/ │ │
│ │ ├── extractors/ (stack, │ ├── cursor/ │ │
│ │ │ structure, symbols) │ └── generic/ │ │
│ │ ├── retrieval/ (query-engine) └───────────────────────────────┘ │
│ │ ├── setup-bootstrap.mjs │
│ │ ├── template-installer.mjs │
│ │ ├── enrichment-driver.mjs │
│ │ ├── enrichment-config.mjs │
│ │ ├── sync-manifest.mjs │
│ │ ├── platform.mjs │
│ │ └── ... │
│ └──────────────────────────────────────────────────────────────── │
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ MCP Servers (installed by pmc setup) │ │
│ │ └── agent-memory → npx -y @aabadin/agent-memory-mcp │ │
│ │ (LanceDB + hybrid search) │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ External Dependencies │ │
│ │ ├── Ollama (local LLM for enrichment) │ │
│ │ ├── graphifyy (Python pkg, AST-level knowledge graph) │ │
│ │ └── agent-memory-mcp (MCP server, hybrid BM25+vector DB) │ │
│ └──────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘Layer details
PMC CLI layer (cli/*.mjs): Each file is a single command dispatchable via pmc <command>. They import from src/ for shared logic.
PMC source layer (src/*.mjs): Shared utilities, providers, extractors, and state management.
Agent Memory MCP (@aabadin/agent-memory-mcp): A TypeScript MCP server backed by LanceDB with hybrid BM25 + vector search. Stores every enriched symbol as a searchable memory. Embeddings are generated locally using Xenova/bge-m3 via ONNX — no API keys, no network after initial download. See Credits for the original repo.
Graphify (graphifyy): A Python package by obra that performs AST-level structural analysis of your codebase. Produces a graph.json, graph.html, and GRAPH_REPORT.md showing file-level dependencies, imports, and module clustering. No LLM calls during graph generation. See Credits for the original repo.
Models
Embedding Model: Xenova/bge-m3
| Property | Value |
|---|---|
| Model | Xenova/bge-m3 |
| Dimensions | 1024 |
| Pooling | CLS (first token) |
| Runtime | ONNX via @huggingface/transformers v4.2.0 |
| Cache | Local ONNX model cache (~1 GB on first download) |
| Provider | Runs entirely locally inside the agent-memory-mcp process |
Used for: converting every memory into a dense vector for semantic similarity search. The ONNX runtime downloads the model once on first run and caches it locally — no network calls during normal operation.
LLM: deepseek-coder-v2:16b-ctx16k (Ollama)
| Property | Value | |---|---| | Model | deepseek-coder-v2 | | Provider | Ollama | | Context | 32K tokens | | Size | 16B parameters | | Hardware | Local GPU/CPU via Ollama |
Used for: semantic enrichment — reading source code fragments and producing structured descriptions of each symbol's responsibility, inputs, outputs, dependencies, and role.
Alternative models (configure via OLLAMA_MODEL env var):
qwen3-coder:30b— larger, better reasoningcodellama:13b— good for code tasksdeepseek-coder-v2:16b-ctx16k— default, best balance of speed and quality
Installation
npm install -g @aabadin/project-memory-contextOr run without installing:
npx @aabadin/project-memory-context setupSystem requirements:
- Node.js ≥ 18
- Ollama installed and running
- Python 3 (for graphifyy)
- git (required to install graphifyy from source fork — see note below)
- ~2 GB free disk space (for embedding model cache + LanceDB)
Note — graphifyy fork: PMC currently installs graphifyy from a fork that adds Razor/CSHTML support for ASP.NET MVC projects. This is a temporary measure while PR #1085 is under review. Once merged, PMC will revert to installing from PyPI. To install manually:
pip install git+https://github.com/adrianabadin/graphify.git@feat/cshtml-mvc-razor-extractionIf you prefer the stable PyPI release (without Razor support):
pip install graphifyy
Setup
Run pmc setup in your project root:
cd /path/to/your/project
pmc setupThe interactive prompt asks for:
- Ollama base URL (default:
http://localhost:11434) - Ollama model name (default:
deepseek-coder-v2:16b-ctx16k)
It then:
- Installs
graphifyyvia pip - Creates
.planning/project-memory-context/with full directory structure - Writes MCP config for
agent-memoryand per-agent enrichment config files - Installs agent-specific templates (commands, agents config, autostart snippets)
- Runs the environment doctor to verify everything works
Single-agent setup
pmc setup # Auto-detects your agent
pmc setup --opencode # Force OpenCode
pmc setup --claude # Force Claude Code
pmc setup --cursor # Force Cursor
pmc setup --antigravity # Force Antigravity CLI
pmc setup --generic # Generic (writes README-SETUP.md)Note: The generated commands invoke
pmcdirectly. Make sure the CLI is installed globally:npm install -g @aabadin/project-memory-context
Multi-agent setup (combinable flags)
pmc setup --opencode --claude # OpenCode + Claude Code
pmc setup --opencode --claude --cursor # All three
pmc setup --opencode --cursor # OpenCode + Cursor only
pmc setup --claude --antigravity # Claude Code + AntigravityEach agent gets its own configuration:
- OpenCode:
.opencode/opencode.jsonwithmcp.agent-memoryentry +AGENTS.mdautostart + global commands/agents/skills - Claude Code:
.claude/project-memory-context.jsonenrichment config +.mcp.json+ global commands/skills/agents/enrich.mdsubagent - Antigravity:
AGENTS.mdautostart +.agents/skills/<cmd>/SKILL.md(cada comando PMC como skill/slash command) +.agents/skills/{pmc-skill,enrich}/SKILL.md. Nota: Antigravity no soporta subagentes por archivo (feature request abierta);enrichse instala como skill invocable por el modelo y por slash command/enrich. - Cursor:
.cursor/project-memory-context.jsonenrichment config +.mcp.json - All agents:
.mcp.jsonat project root (universal fallback)
Automated detection
When run without flags, pmc setup detects your agent by checking (in order):
.opencode/directory → OpenCodeCLAUDE.mdfile → Claude Code.claude/directory → Claude Code.cursorrulesfile → Cursor.cursor/directory → Cursor.agents/directory → Antigravity~/.config/opencode/exists → OpenCode (global)- Otherwise → Generic
CLI Reference
pmc setup
Interactively bootstraps PMC in the current project.
pmc setup [--opencode] [--claude] [--cursor] [--antigravity] [--generic]| Flag | Description |
|---|---|
| --opencode | Install configs for OpenCode |
| --claude | Install configs for Claude Code |
| --cursor | Install configs for Cursor |
| --antigravity | Install configs for Antigravity CLI |
| --generic | Generic setup (README only) |
| (no flags) | Auto-detect agent(s) |
What it creates:
.planning/
project-memory-context/
install.json
enrichment/
graph/
intake/
runs/
project-context/
detected/ (auto-detected metadata)
declared/ (user-declared metadata)
materialized/ (9 base memories)
markdown/ (human-readable context)
state/ (refresh state)
.opencode/opencode.json (if opencode)
.claude/project-memory-context.json (if claude-code)
.cursor/project-memory-context.json (if cursor)
.mcp.json (universal MCP)
AGENTS.md (autostart snippet, if opencode)
project-memory-context.md
project-memory-context workflow.mdpmc map-project
Portable, non-interactive bootstrap for any repo. Runs all stages.
pmc map-project [target-repo] [--all] [--stage-a] [--stage-b] [--enrich]| Argument / Flag | Description |
|---|---|
| target-repo | Path to the target repo (default: current dir) |
| --stage-a | Intake + graphify structural mapping |
| --stage-b | Symbol extraction + build enrichment worklist |
| --all | Both stages |
| --enrich | Start enrichment queue in background (requires at least one stage) |
Examples:
# Full pipeline (setup + graphify + symbols + enrichment)
pmc map-project . --all
# Graphify only
pmc map-project . --stage-a
# Symbols + enrichment only (after graphify)
pmc map-project . --stage-b --enrich
# Custom model
OLLAMA_MODEL=qwen3-coder:30b pmc map-project . --all --enrichEnvironment variables for map-project:
| Variable | Default | Description |
|---|---|---|
| OLLAMA_URL | http://localhost:11434 | Ollama REST endpoint |
| OLLAMA_MODEL | deepseek-coder-v2:16b-ctx16k | Ollama model |
| PMC_CONCURRENCY | 8 | Parallel slots for worklist |
| PMC_GRAPHIFY_PATH | (auto-detect) | Custom path to graphify executable |
pmc enrich
Run the semantic enrichment queue.
pmc enrich [project-dir]The enrichment queue:
- Reads
worklist.jsonfor pending symbols - For each symbol, extracts the source code fragment
- Calls the local Ollama LLM with a structured prompt
- Stores the result as a memory via
agent-memory-mcp - Updates
graph.json,symbol-index.json, andworklist.json
Internal pipeline per symbol:
Symbol → semantic-unit (code fragment + imports)
→ local-model-provider (Ollama) → structured report
→ normalize-semantic-report → memory payload
→ agent-memory: store → memoryId
→ finalize-enrichment (graph + index + worklist)pmc get-context
Render project context for the current directory or a specific target.
pmc get-context [target] [depth] [focus]
pmc get-context {symbol|file|query} <target> [depth] [focus]
pmc get-context --refresh| Option | Description |
|---|---|
| target | Symbol key or file path to focus on (default: project overview) |
| depth | Output verbosity (default: compact) |
| focus | Output focus (all, dependencies, callers, containment) |
| --refresh | Re-detect files and refresh stale memories |
Depth levels:
- compact — symbol name + one-line summary
- extended — full LLM-generated description
- deep — includes all neighbors (depends on / depended by)
- disk — includes raw source code
pmc enrich-status
Show enrichment progress and system health.
pmc enrich-statusOutput:
Enrichment config:
Preferred modes: local-model, cloud-api, agent-subagent
Local model: deepseek-coder-v2:16b-ctx16k @ http://localhost:11434
Worklist:
Total symbols: 314
Pending: 201
Enriched: 87
Stale: 21
Failed: 5pmc doctor
Run environment diagnostics to check that all dependencies are available.
pmc doctorChecks:
- node-version — Node.js ≥ 18?
- python — Python 3 available?
- graphifyy — graphifyy package installed?
- ollama — Ollama reachable?
- memory-db-path — MEMORY_DB_PATH set and writable?
- embedding-cache — EMBEDDING_CACHE_PATH configured?
pmc init-project
Initialize PMC project state and install agent-facing templates.
pmc init-project [--agent opencode|claude-code|cursor|generic]Creates the .planning/project-memory-context/ directory tree, default configuration files, and agent-specific command snippets for the current project.
pmc sync-context
Apply pending sync-manifest operations to agent-memory.
pmc sync-contextpmc sanitize
Clean up stale enrichment artifacts and rebuild worklist state.
pmc sanitizepmc project-context
Materialize or refresh the 9 base project-context memories.
pmc project-context [--refresh]| Flag | Description |
|---|---|
| (none) | Generate all 9 memories from scratch |
| --refresh | Only refresh memories whose source files have changed |
Environment Variables
PMC variables
| Variable | Default | Description |
|---|---|---|
| PMC_CLOUD_API_KEY | (none) | API key for cloud enrichment fallback |
| PMC_CONCURRENCY | 8 | Parallel enrichment slots |
| PMC_GRAPHIFY_PATH | (auto-detect) | Custom path to graphify executable |
| PMC_GRAPHIFY_BIN | (auto-detect) | Alternative to PMC_GRAPHIFY_PATH |
| PMC_GLOBAL_CONFIG | ~/.config/opencode/project-memory-context.json | Override global config path |
| PMC_LOCAL_MODEL_BASE_URL | http://localhost:11434 | Ollama URL for enrichment |
| PMC_LOCAL_MODEL_NAME | (from setup) | Ollama model for enrichment |
Agent Memory MCP variables
| Variable | Required | Description |
|---|---|---|
| MEMORY_DB_PATH | Yes | Path to LanceDB database directory |
| EMBEDDING_MODEL | No | Xenova/bge-m3 (default) |
| EMBEDDING_DIMENSIONS | No | 1024 (inferred from model) |
| EMBEDDING_POOLING | No | cls (inferred from model) |
| EMBEDDING_CACHE_PATH | No | Content-addressed binary embedding cache |
| MEMORY_DECAY_HALF_LIFE | No | 30 days (set 0 to disable) |
| ENABLE_HARDCOPY | No | true to enable JSON file backup |
| HARDCOPY_PATH | If hardcopy | Directory for JSON mirror files |
OpenCode Session Startup
pmc init . (or pmc install-pmc) installs .opencode/plugins/pmc.mjs — an auto-loaded plugin that OpenCode picks up at startup with no manual wiring required. It also writes the PMC MCP server entries into .opencode/opencode.json (merging non-destructively with existing config).
On every OpenCode startup the plugin runs a zero-token Node runtime (runSessionStartRuntime) that:
- Launches
pmc refresh-context --enrichdetached (hash-incremental — only changed files are re-processed) - Launches background enrichment + watchdog if pending symbols exist
- Ensures exactly one detached file watcher per project (see OpenCode File Watcher below)
- Writes the startup snapshot to
.planning/project-memory-context/runs/session-start/latest.jsonand.planning/project-memory-context/runs/session-start/latest.md
The startup sequence adds less than 100ms of wall time and zero tokens to the session. Startup uses detached Node child processes today, not PTY tools. If the plugin is disabled, the manual fallback is pmc session-start ..
OpenCode File Watcher
The PMC file watcher (pmc watch .) watches source files and triggers pmc refresh-context --enrich automatically when files go quiet. It supersedes the old opencode-refresh-hook (tool.execute.after) approach — it sees agent edits, human edits, and git operations alike.
Debounce semantics
Each file has its own independent 5-minute quiet timer. A file that is being continuously edited never blocks the refresh of other files that have gone quiet. Once a file's quiet window expires, a single pmc refresh-context --enrich run is launched (pending state is merged across files).
Lifecycle
- 30-second tick + heartbeat: the watcher writes a heartbeat every 30s to
state/watch.pid - PID file identity: the PID file stores
{ pid, projectRoot, heartbeatAt }. A running watcher is considered stale ifheartbeatAtis more than 90s old (guards against PID reuse, zombie processes, and hung watchers) - Pending state persistence:
state/watch-pending.jsonsurvives restarts — if the watcher is killed mid-debounce, the next startup picks up where it left off
CLI flags
pmc watch . --detach # start in background (confirms startup within 5s)
pmc watch . --status # JSON: alive, pid, lastHeartbeat, pendingFiles
pmc watch . --stop # stop the tracked watcherThe plugin startup (runSessionStartRuntime) calls the --detach path automatically. Manual use is only needed when the plugin is not installed or after a manual --stop.
Enrichment single-instance guard
enrich-queue has a built-in single-instance guard (PID + heartbeat) so concurrent launchers — session-start, refresh-context, and the file watcher — cannot double-process the same queue. If an instance is already running, subsequent launch attempts exit immediately without starting a second worker.
Recommended Optional Plugin: opencode-pty
opencode-pty is a community OpenCode plugin that adds interactive pseudo-terminal (PTY) management. It lets agents spawn long-running background processes (pmc enrich, dev servers, file watchers, etc.), stream their output on demand, send interactive input (Ctrl+C, prompts, keystrokes), and clean them up on exit.
Why PMC recommends it: the recommended PMC workflow keeps pmc enrich . running in the background while the agent works on other tasks. Without PTY support that process is invisible to the agent — it cannot read progress, recover a stalled run, or react to prompts. The autostart block in AGENTS.md (watchdog poll + subagent drain) assumes PTY tools are available, and falls back to blind background bash otherwise. Install opencode-pty to get the full intended workflow.
Installation
Add opencode-pty to the plugin array in your OpenCode configuration (project-level .opencode/opencode.json or global ~/.config/opencode/opencode.json):
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-pty"]
}OpenCode installs the plugin automatically on the next run. After saving the config, restart OpenCode so the plugin code is loaded.
If you keep your OpenCode config under version control, commit this change so it stays in sync across machines.
Verifying
Inside an OpenCode session, the following tools should be available:
pty_spawn— start a new background process with a commandpty_list— list active PTY sessionspty_read— read buffered output from a sessionpty_write— send input (e.g.\\x03for Ctrl+C)pty_kill— terminate a session and free its buffer
If they are missing, confirm the entry is in the plugin array, then restart OpenCode. Run pmc doctor to check that the rest of the environment (Ollama, graphifyy, memory DB) is healthy.
Updating
OpenCode does not auto-update plugins. To upgrade opencode-pty:
rm -rf ~/.cache/opencode/node_modules/opencode-pty
opencodeOpenCode reinstalls the latest version on the next start.
Project Structure
A project with PMC installed will have:
your-repo/
├── .planning/
│ └── project-memory-context/
│ ├── install.json # PMC install state
│ ├── enrichment/
│ │ ├── worklist.json # All symbols + enrichment status
│ │ ├── sync-manifest.json # Pending agent-memory syncs
│ │ ├── semantic-jobs.json # Prepared LLM enrichment jobs
│ │ ├── failures.json # Failed enrichment attempts
│ │ └── *.memory.json # Per-symbol memory payloads
│ ├── graph/
│ │ ├── graph.json # Knowledge graph (graphifyy output)
│ │ ├── graph.html # Visual knowledge graph
│ │ ├── graph.metadata.json # Graph metadata
│ │ └── GRAPH_REPORT.md # Human-readable graph report
│ ├── intake/ # Project description + goals
│ ├── runs/ # Run-specific artifacts
│ └── project-context/
│ ├── detected/ # Auto-detected context
│ ├── declared/ # User-declared context
│ ├── materialized/ # 9 base memories (JSON)
│ ├── markdown/ # Human-readable context
│ └── state/ # Refresh state tracking
├── .opencode/opencode.json # OpenCode MCP config (if opencode)
├── .claude/project-memory-context.json # Claude Code enrichment config
├── .mcp.json # Universal MCP server config
├── AGENTS.md # PMC autostart block
├── project-memory-context.md # Command template
└── project-memory-context workflow.md # Workflow template9 Base Project-Context Memories
When you run pmc project-context, PMC generates and stores 9 memories in agent-memory:
| # | Memory Key | Description |
|---|---|---|
| 1 | stack-runtime | Language, framework, runtime version (from package.json, tsconfig.json, etc.) |
| 2 | dependencies-summary | Key dependencies and libraries |
| 3 | integrations-summary | External services and APIs |
| 4 | architecture-current | Current architecture patterns and entry points |
| 5 | architecture-target | Desired or declared target architecture |
| 6 | structure-summary | Root directories, key subtrees, and entry points |
| 7 | technical-rules | Coding standards, conventions, and rules |
| 8 | project-requirements | Declared business and functional requirements |
| 9 | known-issues-and-fixes | Known issues and recorded workarounds |
These are refreshed automatically when their source files change (--refresh mode).
Credits
Agent Memory MCP
The @aabadin/agent-memory-mcp package is a fork of adamrdrew/agent-memory-mcp, published under the @aabadin scope on npm.
Original: Adam Drew's agent-memory-mcp is an MCP server for persistent agent memory backed by LanceDB with hybrid BM25 + vector search using local ONNX embeddings.
Modifications for this project:
- Published under
@aabadinscope (original author did not publish to npm under@brainscope) - Version bumped to 2.0.0
- All references updated from
@brain/to@aabadin/scope - Fully compatible with the original API and tool set
The agent-memory-mcp package provides the persistence layer — every enriched symbol, every project-context memory, and every user observation is stored via this MCP server. It runs npx -y @aabadin/agent-memory-mcp automatically when installed by pmc setup.
Graphifyy
graphifyy by safishamsi is a Python package for AST-level structural analysis of codebases. It produces knowledge graphs showing file dependencies, imports, module clustering, and code organization — all without LLM calls.
Role in PMC: Graphify generates the base knowledge graph (graph.json) that PMC uses to understand symbol locations, file dependencies, and module relationships. The graph is stored under .planning/project-memory-context/graph/ and is consumed by the query engine for context-aware symbol lookups.
Fork: PMC currently uses adrianabadin/graphify @ feat/cshtml-mvc-razor-extraction, which extends extract_razor() with MVC-specific CSHTML patterns (Layout inheritance, Html.Partial, asp-controller/action, form submissions, TagHelpers). A PR has been submitted upstream: safishamsi/graphify#1085. Once merged, PMC will switch back to the official PyPI package.
License
GPL-3.0-or-later — see LICENSE.
