@aabadin/project-memory-context 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,123 +1,568 @@
1
- # @aabadin/project-memory-context
1
+ # @aabadin/project-memory-context (PMC)
2
2
 
3
- Portable project memory context CLI — bootstraps semantic enrichment workflows for any AI coding agent.
3
+ Portable project memory context — bootstraps **semantic enrichment workflows** for any AI coding agent.
4
4
 
5
- This package installs and wires together:
5
+ `pmc` installs, configures, and runs a complete pipeline that:
6
+ 1. **Maps** your codebase into a knowledge graph (via graphifyy)
7
+ 2. **Extracts** every top-level symbol (functions, classes, interfaces, etc.)
8
+ 3. **Enriches** each symbol with LLM-generated semantics (responsibility, inputs, outputs, dependencies)
9
+ 4. **Persists** everything as searchable memories that survive across sessions
6
10
 
7
- - a project bootstrapper (`pmc bootstrap` / `pmc setup`)
8
- - a local semantic MCP backed by Ollama (`pmc-local-model`)
9
- - an `agent-memory` MCP registration using `npx -y @aabadin/agent-memory-mcp`
10
- - command/workflow templates for `project-memory-context`
11
- - helper CLIs and artifact management for the semantic enrichment loop
11
+ This gives your AI agent persistent, recallable knowledge of your entire codebase without re-reading files.
12
12
 
13
- ## What it installs for you
13
+ ---
14
14
 
15
- The setup flow is designed to resolve everything automatically except:
15
+ ## Table of Contents
16
16
 
17
- - installing Ollama itself
18
- - pulling/downloading your local model
17
+ - [Concept & Objective](#concept--objective)
18
+ - [Architecture](#architecture)
19
+ - [Models](#models)
20
+ - [Installation](#installation)
21
+ - [Setup](#setup)
22
+ - [Single-agent setup](#single-agent-setup)
23
+ - [Multi-agent setup](#multi-agent-setup--flags)
24
+ - [Automated detection](#automated-detection)
25
+ - [CLI Reference](#cli-reference)
26
+ - [`pmc setup`](#pmc-setup)
27
+ - [`pmc bootstrap`](#pmc-bootstrap)
28
+ - [`pmc enrich` / `pmc enrich-queue`](#pmc-enrich--pmc-enrich-queue)
29
+ - [`pmc context`](#pmc-context)
30
+ - [`pmc status`](#pmc-status)
31
+ - [`pmc doctor`](#pmc-doctor)
32
+ - [`pmc init`](#pmc-init)
33
+ - [`pmc new-project`](#pmc-new-project)
34
+ - [`pmc sanitize`](#pmc-sanitize)
35
+ - [`pmc project-context`](#pmc-project-context)
36
+ - [Environment Variables](#environment-variables)
37
+ - [Project Structure](#project-structure)
38
+ - [9 Base Project-Context Memories](#9-base-project-context-memories)
39
+ - [Credits](#credits)
19
40
 
20
- The setup flow handles:
41
+ ---
21
42
 
22
- - asking for `OLLAMA_BASE_URL`
23
- - asking for `OLLAMA_MODEL`
24
- - installing `graphifyy` with Python/pip
25
- - creating `.planning/project-memory-context/`
26
- - writing project install state
27
- - registering MCP servers in `.mcp.json`
28
- - registering the plugin in `.opencode/opencode.json` when using OpenCode
29
- - copying `project-memory-context.md` and `project-memory-context workflow.md` into the target project
43
+ ## Concept & Objective
30
44
 
31
- ## Install
45
+ 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.
32
46
 
33
- Install the package globally, or run it with `npx`, then run setup inside the target repository.
47
+ **Project-Memory-Context (PMC)** solves this by creating a **persistent semantic layer** between your codebase and your agent:
48
+
49
+ | Component | What it does |
50
+ |---|---|
51
+ | **Visit (graphifyy)** | AST-level static analysis — builds a dependency graph of your entire codebase |
52
+ | **Symbol extraction** | Regex+parser extraction of all top-level symbols (classes, functions, interfaces, etc.) |
53
+ | **Semantic enrichment** | Calls a local LLM (Ollama) to describe each symbol's responsibility, inputs, outputs, and role |
54
+ | **Agent Memory** | Stores each enriched symbol as a searchable vector memory (hybrid BM25 + semantic) |
55
+ | **Project Context** | 9 auto-generated "base memories" about your project's stack, structure, architecture, etc. |
56
+
57
+ 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.
58
+
59
+ ---
60
+
61
+ ## Architecture
62
+
63
+ ```
64
+ ┌─────────────────────────────────────────────────────────────────────┐
65
+ │ PMC Package (@aabadin/...) │
66
+ │ │
67
+ │ cli/setup.mjs cli/bootstrap.mjs cli/enrich-queue.mjs│
68
+ │ cli/context.mjs cli/project-context.mjs cli/doctor.mjs │
69
+ │ cli/build-worklist.mjs cli/enrich.mjs cli/status.mjs │
70
+ │ cli/sanitize.mjs cli/finalize.mjs ... │
71
+ │ │
72
+ │ ┌───────────────────────────────────────────────────────────────┐ │
73
+ │ │ src/ │ templates/ │ │
74
+ │ │ ├── providers/ │ ├── opencode/ (commands, │ │
75
+ │ │ │ ├── local-model-provider │ │ agents, autostart) │ │
76
+ │ │ │ └── cloud-api-provider │ ├── claude-code/ │ │
77
+ │ │ ├── extractors/ (stack, │ ├── cursor/ │ │
78
+ │ │ │ structure, symbols) │ └── generic/ │ │
79
+ │ │ ├── retrieval/ (query-engine) └───────────────────────────────┘ │
80
+ │ │ ├── setup-bootstrap.mjs │
81
+ │ │ ├── template-installer.mjs │
82
+ │ │ ├── enrichment-driver.mjs │
83
+ │ │ ├── enrichment-config.mjs │
84
+ │ │ ├── sync-manifest.mjs │
85
+ │ │ ├── platform.mjs │
86
+ │ │ └── ... │
87
+ │ └──────────────────────────────────────────────────────────────── │
88
+ │ │
89
+ │ ┌──────────────────────────────────────────────────────────────┐ │
90
+ │ │ MCP Servers (installed by pmc setup) │ │
91
+ │ │ ├── agent-memory → npx -y @aabadin/agent-memory-mcp │ │
92
+ │ │ │ (LanceDB + hybrid search) │ │
93
+ │ │ └── pmc-local-model → Ollama REST API │ │
94
+ │ │ (semantic enrichment via local LLM) │ │
95
+ │ └──────────────────────────────────────────────────────────────┘ │
96
+ │ │
97
+ │ ┌──────────────────────────────────────────────────────────────┐ │
98
+ │ │ External Dependencies │ │
99
+ │ │ ├── Ollama (local LLM for enrichment) │ │
100
+ │ │ ├── graphifyy (Python pkg, AST-level knowledge graph) │ │
101
+ │ │ └── agent-memory-mcp (MCP server, hybrid BM25+vector DB) │ │
102
+ │ └──────────────────────────────────────────────────────────────┘ │
103
+ └─────────────────────────────────────────────────────────────────────┘
104
+ ```
105
+
106
+ ### Layer details
107
+
108
+ **PMC CLI layer** (`cli/*.mjs`): Each file is a single command dispatchable via `pmc <command>`. They import from `src/` for shared logic.
109
+
110
+ **PMC source layer** (`src/*.mjs`): Shared utilities, providers, extractors, and state management.
111
+
112
+ **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](#credits) for the original repo.
113
+
114
+ **Graphify** (`graphifyy`): A Python package by [obra](https://github.com/obra/graphify) 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](#credits) for the original repo.
115
+
116
+ ---
117
+
118
+ ## Models
119
+
120
+ ### Embedding Model: `Xenova/bge-m3`
121
+
122
+ | Property | Value |
123
+ |---|---|
124
+ | Model | [Xenova/bge-m3](https://huggingface.co/Xenova/bge-m3) |
125
+ | Dimensions | 1024 |
126
+ | Pooling | CLS (first token) |
127
+ | Runtime | ONNX via `@huggingface/transformers` v4.2.0 |
128
+ | Cache | Local ONNX model cache (~1 GB on first download) |
129
+ | Provider | Runs entirely locally inside the `agent-memory-mcp` process |
130
+
131
+ 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.
132
+
133
+ ### LLM: `deepseek-coder-v2:16b-ctx32k` (Ollama)
134
+
135
+ | Property | Value |
136
+ |---|---|
137
+ | Model | [deepseek-coder-v2](https://ollama.com/library/deepseek-coder-v2) |
138
+ | Provider | [Ollama](http://localhost:11434) |
139
+ | Context | 32K tokens |
140
+ | Size | 16B parameters |
141
+ | Hardware | Local GPU/CPU via Ollama |
142
+
143
+ Used for: semantic enrichment — reading source code fragments and producing structured descriptions of each symbol's responsibility, inputs, outputs, dependencies, and role.
144
+
145
+ **Alternative models** (configure via `OLLAMA_MODEL` env var):
146
+ - `qwen3-coder:30b` — larger, better reasoning
147
+ - `codellama:13b` — good for code tasks
148
+ - `deepseek-coder-v2:16b-ctx32k` — default, best balance of speed and quality
149
+
150
+ ---
151
+
152
+ ## Installation
34
153
 
35
154
  ```bash
36
155
  npm install -g @aabadin/project-memory-context
37
- pmc setup
38
156
  ```
39
157
 
40
- Without a global install:
158
+ Or run without installing:
41
159
 
42
160
  ```bash
43
161
  npx @aabadin/project-memory-context setup
44
162
  ```
45
163
 
46
- ## Setup prompts
164
+ **System requirements:**
165
+ - Node.js ≥ 18
166
+ - Ollama installed and running
167
+ - Python 3 (for graphifyy)
168
+ - ~2 GB free disk space (for embedding model cache + LanceDB)
169
+
170
+ ---
47
171
 
48
- `pmc setup` asks for:
172
+ ## Setup
49
173
 
50
- - Ollama base URL, default `http://localhost:11434`
51
- - Ollama model name, default `deepseek-coder-v2:16b-ctx32k`
174
+ Run `pmc setup` in your project root:
52
175
 
53
- It then attempts to install:
176
+ ```bash
177
+ cd /path/to/your/project
178
+ pmc setup
179
+ ```
180
+
181
+ The interactive prompt asks for:
182
+ 1. **Ollama base URL** (default: `http://localhost:11434`)
183
+ 2. **Ollama model name** (default: `deepseek-coder-v2:16b-ctx32k`)
184
+
185
+ It then:
186
+ 1. Installs `graphifyy` via pip
187
+ 2. Creates `.planning/project-memory-context/` with full directory structure
188
+ 3. Writes MCP config for the target agent(s)
189
+ 4. Installs agent-specific templates (commands, agents config, autostart snippets)
190
+ 5. Runs the environment doctor to verify everything works
191
+
192
+ ### Single-agent setup
54
193
 
55
194
  ```bash
56
- python -m pip install graphifyy
195
+ pmc setup # Auto-detects your agent
196
+ pmc setup --opencode # Force OpenCode
197
+ pmc setup --claude # Force Claude Code
198
+ pmc setup --cursor # Force Cursor
199
+ pmc setup --generic # Generic (writes README-SETUP.md)
57
200
  ```
58
201
 
59
- or an equivalent Python launcher depending on platform.
202
+ ### Multi-agent setup (combinable flags)
60
203
 
61
- ## Resulting project files
204
+ ```bash
205
+ pmc setup --opencode --claude # OpenCode + Claude Code
206
+ pmc setup --opencode --claude --cursor # All three
207
+ pmc setup --opencode --cursor # OpenCode + Cursor only
208
+ ```
62
209
 
63
- After setup, the target project contains:
210
+ Each agent gets its own configuration:
211
+ - **OpenCode**: `.opencode/opencode.json` with `mcp.agent-memory` entry + `AGENTS.md` autostart + global commands/agents
212
+ - **Claude Code**: `.claude/project-memory-context.json` enrichment config + `.mcp.json`
213
+ - **Cursor**: `.cursor/project-memory-context.json` enrichment config + `.mcp.json`
214
+ - **All agents**: `.mcp.json` at project root (universal fallback)
64
215
 
65
- ```text
66
- .mcp.json
67
- .planning/project-memory-context/install.json
216
+ ### Automated detection
217
+
218
+ When run without flags, `pmc setup` detects your agent by checking (in order):
219
+
220
+ 1. `.opencode/` directory → OpenCode
221
+ 2. `CLAUDE.md` file → Claude Code
222
+ 3. `.claude/` directory → Claude Code
223
+ 4. `.cursorrules` file → Cursor
224
+ 5. `.cursor/` directory → Cursor
225
+ 6. `~/.config/opencode/` exists → OpenCode (global)
226
+ 7. Otherwise → Generic
227
+
228
+ ---
229
+
230
+ ## CLI Reference
231
+
232
+ ### `pmc setup`
233
+
234
+ Interactively bootstraps PMC in the current project.
235
+
236
+ ```bash
237
+ pmc setup [--opencode] [--claude] [--cursor] [--generic]
238
+ ```
239
+
240
+ | Flag | Description |
241
+ |---|---|
242
+ | `--opencode` | Install configs for OpenCode |
243
+ | `--claude` | Install configs for Claude Code |
244
+ | `--cursor` | Install configs for Cursor |
245
+ | `--generic` | Generic setup (README only) |
246
+ | *(no flags)* | Auto-detect agent(s) |
247
+
248
+ **What it creates:**
249
+ ```
250
+ .planning/
251
+ project-memory-context/
252
+ install.json
253
+ enrichment/
254
+ graph/
255
+ intake/
256
+ runs/
257
+ project-context/
258
+ detected/ (auto-detected metadata)
259
+ declared/ (user-declared metadata)
260
+ materialized/ (9 base memories)
261
+ markdown/ (human-readable context)
262
+ state/ (refresh state)
263
+ .opencode/opencode.json (if opencode)
264
+ .claude/project-memory-context.json (if claude-code)
265
+ .cursor/project-memory-context.json (if cursor)
266
+ .mcp.json (universal MCP)
267
+ AGENTS.md (autostart snippet, if opencode)
68
268
  project-memory-context.md
69
269
  project-memory-context workflow.md
70
270
  ```
71
271
 
72
- ## Runtime layout
272
+ ---
273
+
274
+ ### `pmc bootstrap`
275
+
276
+ Portable, non-interactive bootstrap for any repo. Runs all stages.
277
+
278
+ ```bash
279
+ pmc bootstrap [target-repo] [--all] [--stage-a] [--stage-b] [--enrich]
280
+ ```
281
+
282
+ | Argument / Flag | Description |
283
+ |---|---|
284
+ | `target-repo` | Path to the target repo (default: current dir) |
285
+ | `--stage-a` | Intake + graphify structural mapping |
286
+ | `--stage-b` | Symbol extraction + build enrichment worklist |
287
+ | `--all` | Both stages |
288
+ | `--enrich` | Start enrichment queue in background (requires at least one stage) |
289
+
290
+ **Examples:**
291
+
292
+ ```bash
293
+ # Full pipeline (setup + graphify + symbols + enrichment)
294
+ pmc bootstrap . --all
295
+
296
+ # Graphify only
297
+ pmc bootstrap . --stage-a
298
+
299
+ # Symbols + enrichment only (after graphify)
300
+ pmc bootstrap . --stage-b --enrich
301
+
302
+ # Custom model
303
+ OLLAMA_MODEL=qwen3-coder:30b pmc bootstrap . --all --enrich
304
+ ```
305
+
306
+ **Environment variables for bootstrap:**
307
+
308
+ | Variable | Default | Description |
309
+ |---|---|---|
310
+ | `OLLAMA_URL` | `http://localhost:11434` | Ollama REST endpoint |
311
+ | `OLLAMA_MODEL` | `deepseek-coder-v2:16b-ctx32k` | Ollama model |
312
+ | `PMC_CONCURRENCY` | `8` | Parallel slots for worklist |
313
+ | `PMC_GRAPHIFY_PATH` | *(auto-detect)* | Custom path to graphify executable |
314
+
315
+ ---
316
+
317
+ ### `pmc enrich` / `pmc enrich-queue`
318
+
319
+ Run or start the semantic enrichment queue.
320
+
321
+ ```bash
322
+ pmc enrich # One-shot enrichment
323
+ pmc enrich-queue # Continuous queue (long-running)
324
+ ```
325
+
326
+ The enrichment queue:
327
+ 1. Reads `worklist.json` for pending symbols
328
+ 2. For each symbol, extracts the source code fragment
329
+ 3. Calls the local Ollama LLM with a structured prompt
330
+ 4. Stores the result as a memory via `agent-memory-mcp`
331
+ 5. Updates `graph.json`, `symbol-index.json`, and `worklist.json`
332
+
333
+ **Internal pipeline per symbol:**
334
+ ```
335
+ Symbol → semantic-unit (code fragment + imports)
336
+ → local-model-provider (Ollama) → structured report
337
+ → normalize-semantic-report → memory payload
338
+ → agent-memory: store → memoryId
339
+ → finalize-enrichment (graph + index + worklist)
340
+ ```
73
341
 
74
- During workflow execution, artifacts accumulate under:
342
+ ---
75
343
 
76
- ```text
77
- .planning/project-memory-context/
78
- intake/
79
- graph/
80
- enrichment/
81
- runs/
344
+ ### `pmc context`
345
+
346
+ Render project context for the current directory or a specific target.
347
+
348
+ ```bash
349
+ pmc context [target] [--refresh] [--depth compact|extended|deep|disk]
82
350
  ```
83
351
 
84
- ## MCP servers
352
+ | Option | Description |
353
+ |---|---|
354
+ | `target` | Symbol key or file path to focus on (default: project overview) |
355
+ | `--refresh` | Re-detect files and refresh stale memories |
356
+ | `--depth` | Output verbosity (default: `compact`) |
357
+
358
+ Depth levels:
359
+ - **compact** — symbol name + one-line summary
360
+ - **extended** — full LLM-generated description
361
+ - **deep** — includes all neighbors (depends on / depended by)
362
+ - **disk** — includes raw source code
85
363
 
86
- The bootstrap flow writes `.mcp.json` with an `agent-memory` server that runs:
364
+ ---
365
+
366
+ ### `pmc status`
367
+
368
+ Show enrichment progress and system health.
87
369
 
88
370
  ```bash
89
- npx -y @aabadin/agent-memory-mcp
371
+ pmc status
90
372
  ```
91
373
 
92
- OpenCode plugin integration may also inject local MCP entries at runtime using values from `.planning/project-memory-context/install.json`:
374
+ Output:
375
+ ```
376
+ Enrichment config:
377
+ Preferred modes: local-model, cloud-api, agent-subagent
378
+ Local model: deepseek-coder-v2:16b-ctx32k @ http://localhost:11434
379
+
380
+ Worklist:
381
+ Total symbols: 314
382
+ Pending: 201
383
+ Enriched: 87
384
+ Stale: 21
385
+ Failed: 5
386
+ ```
93
387
 
94
- - `pmc-local-model`
95
- - `pmc-agent-memory`
388
+ ---
96
389
 
97
- `pmc-local-model` exposes a semantic report tool backed by Ollama.
390
+ ### `pmc doctor`
98
391
 
99
- `pmc-agent-memory` points at the public `agent-memory-mcp` binary when plugin injection is used.
392
+ Run environment diagnostics to check that all dependencies are available.
100
393
 
101
- ## Workflow order
394
+ ```bash
395
+ pmc doctor
396
+ ```
102
397
 
103
- 1. `stage-a`
104
- - intake
105
- - brainstorming clarification
106
- - graphify structural mapping
398
+ Checks:
399
+ - **node-version** — Node.js ≥ 18?
400
+ - **python** — Python 3 available?
401
+ - **graphifyy** graphifyy package installed?
402
+ - **ollama** — Ollama reachable?
403
+ - **memory-db-path** — MEMORY_DB_PATH set and writable?
404
+ - **embedding-cache** — EMBEDDING_CACHE_PATH configured?
107
405
 
108
- 2. `stage-b`
109
- - build worklist
110
- - prepare semantic jobs
111
- - call `pmc-local-model`
112
- - materialize `*.memory.json`
113
- - store/update in `pmc-agent-memory`
114
- - materialize `*.result.json`
115
- - finalize or fail each symbol
406
+ ---
116
407
 
117
- ## Development verification
408
+ ### `pmc init`
118
409
 
119
- Run the local test suite:
410
+ Initialize a fresh PMC project structure.
120
411
 
121
412
  ```bash
122
- node --test "tools/project-memory-context/tests/*.test.mjs"
413
+ pmc init <project-root>
123
414
  ```
415
+
416
+ Creates the `.planning/project-memory-context/` directory tree and default configuration files.
417
+
418
+ ---
419
+
420
+ ### `pmc new-project`
421
+
422
+ Delegates to `bootstrap.mjs`. Same as `pmc bootstrap`.
423
+
424
+ ```bash
425
+ pmc new-project <target-repo> [--all] [--stage-a] [--stage-b] [--enrich]
426
+ ```
427
+
428
+ ---
429
+
430
+ ### `pmc sanitize`
431
+
432
+ Clean up stale enrichment artifacts and rebuild worklist state.
433
+
434
+ ```bash
435
+ pmc sanitize
436
+ ```
437
+
438
+ ---
439
+
440
+ ### `pmc project-context`
441
+
442
+ Materialize or refresh the 9 base project-context memories.
443
+
444
+ ```bash
445
+ pmc project-context [--refresh]
446
+ ```
447
+
448
+ | Flag | Description |
449
+ |---|---|
450
+ | *(none)* | Generate all 9 memories from scratch |
451
+ | `--refresh` | Only refresh memories whose source files have changed |
452
+
453
+ ---
454
+
455
+ ## Environment Variables
456
+
457
+ ### PMC variables
458
+
459
+ | Variable | Default | Description |
460
+ |---|---|---|
461
+ | `PMC_CLOUD_API_KEY` | *(none)* | API key for cloud enrichment fallback |
462
+ | `PMC_CONCURRENCY` | `8` | Parallel enrichment slots |
463
+ | `PMC_GRAPHIFY_PATH` | *(auto-detect)* | Custom path to graphify executable |
464
+ | `PMC_GRAPHIFY_BIN` | *(auto-detect)* | Alternative to `PMC_GRAPHIFY_PATH` |
465
+ | `PMC_GLOBAL_CONFIG` | `~/.config/pmc` | Override global config directory |
466
+ | `PMC_LOCAL_MODEL_BASE_URL` | `http://localhost:11434` | Ollama URL for enrichment |
467
+ | `PMC_LOCAL_MODEL` | *(from setup)* | Ollama model for enrichment |
468
+
469
+ ### Agent Memory MCP variables
470
+
471
+ | Variable | Required | Description |
472
+ |---|---|---|
473
+ | `MEMORY_DB_PATH` | Yes | Path to LanceDB database directory |
474
+ | `EMBEDDING_MODEL` | No | `Xenova/bge-m3` (default) |
475
+ | `EMBEDDING_DIMENSIONS` | No | `1024` (inferred from model) |
476
+ | `EMBEDDING_POOLING` | No | `cls` (inferred from model) |
477
+ | `EMBEDDING_CACHE_PATH` | No | Content-addressed binary embedding cache |
478
+ | `MEMORY_DECAY_HALF_LIFE` | No | `30` days (set `0` to disable) |
479
+ | `ENABLE_HARDCOPY` | No | `true` to enable JSON file backup |
480
+ | `HARDCOPY_PATH` | If hardcopy | Directory for JSON mirror files |
481
+
482
+ ---
483
+
484
+ ## Project Structure
485
+
486
+ A project with PMC installed will have:
487
+
488
+ ```
489
+ your-repo/
490
+ ├── .planning/
491
+ │ └── project-memory-context/
492
+ │ ├── install.json # PMC install state
493
+ │ ├── enrichment/
494
+ │ │ ├── worklist.json # All symbols + enrichment status
495
+ │ │ ├── sync-manifest.json # Pending agent-memory syncs
496
+ │ │ ├── semantic-jobs.json # Prepared LLM enrichment jobs
497
+ │ │ ├── failures.json # Failed enrichment attempts
498
+ │ │ └── *.memory.json # Per-symbol memory payloads
499
+ │ ├── graph/
500
+ │ │ ├── graph.json # Knowledge graph (graphifyy output)
501
+ │ │ ├── graph.html # Visual knowledge graph
502
+ │ │ ├── graph.metadata.json # Graph metadata
503
+ │ │ └── GRAPH_REPORT.md # Human-readable graph report
504
+ │ ├── intake/ # Project description + goals
505
+ │ ├── runs/ # Run-specific artifacts
506
+ │ └── project-context/
507
+ │ ├── detected/ # Auto-detected context
508
+ │ ├── declared/ # User-declared context
509
+ │ ├── materialized/ # 9 base memories (JSON)
510
+ │ ├── markdown/ # Human-readable context
511
+ │ └── state/ # Refresh state tracking
512
+ ├── .opencode/opencode.json # OpenCode MCP config (if opencode)
513
+ ├── .claude/project-memory-context.json # Claude Code enrichment config
514
+ ├── .mcp.json # Universal MCP server config
515
+ ├── AGENTS.md # PMC autostart block
516
+ ├── project-memory-context.md # Command template
517
+ └── project-memory-context workflow.md # Workflow template
518
+ ```
519
+
520
+ ---
521
+
522
+ ## 9 Base Project-Context Memories
523
+
524
+ When you run `pmc project-context`, PMC generates and stores 9 memories in `agent-memory`:
525
+
526
+ | # | Memory Key | Description |
527
+ |---|---|---|
528
+ | 1 | `stack-runtime` | Language, framework, runtime version (from `package.json`, `tsconfig.json`, etc.) |
529
+ | 2 | `stack-dependencies` | Key dependencies and their purposes |
530
+ | 3 | `structure-topology` | Directory layout, module organization |
531
+ | 4 | `structure-entrypoints` | Main entry points and build targets |
532
+ | 5 | `architecture-overview` | High-level architectural patterns |
533
+ | 6 | `architecture-data-flow` | Data flow and state management |
534
+ | 7 | `technical-rules` | Code conventions, linting rules, config |
535
+ | 8 | `intake-goals` | User-declared project goals and focus areas |
536
+ | 9 | `intake-description` | Human-written project summary |
537
+
538
+ These are refreshed automatically when their source files change (`--refresh` mode).
539
+
540
+ ---
541
+
542
+ ## Credits
543
+
544
+ ### Agent Memory MCP
545
+
546
+ The `@aabadin/agent-memory-mcp` package is a **fork** of [adamrdrew/agent-memory-mcp](https://github.com/adamrdrew/agent-memory-mcp), published under the `@aabadin` scope on npm.
547
+
548
+ **Original**: Adam Drew's [agent-memory-mcp](https://github.com/adamrdrew/agent-memory-mcp) is an MCP server for persistent agent memory backed by LanceDB with hybrid BM25 + vector search using local ONNX embeddings.
549
+
550
+ **Modifications for this project:**
551
+ - Published under `@aabadin` scope (original author did not publish to npm under `@brain` scope)
552
+ - Version bumped to 2.0.0
553
+ - All references updated from `@brain/` to `@aabadin/` scope
554
+ - Fully compatible with the original API and tool set
555
+
556
+ 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`.
557
+
558
+ ### Graphifyy
559
+
560
+ [graphifyy](https://github.com/obra/graphify) by obra 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.
561
+
562
+ **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.
563
+
564
+ ---
565
+
566
+ ## License
567
+
568
+ GPL-3.0-or-later — see [LICENSE](LICENSE).
package/cli/setup.mjs CHANGED
@@ -12,15 +12,21 @@ import { installAgentTemplates } from '../src/template-installer.mjs';
12
12
 
13
13
  const packageRoot = dirname(dirname(fileURLToPath(import.meta.url)));
14
14
 
15
+ const AGENT_FLAGS = {
16
+ '--opencode': 'opencode',
17
+ '--claude': 'claude-code',
18
+ '--cursor': 'cursor',
19
+ '--generic': 'generic',
20
+ };
21
+
15
22
  function installGraphify() {
16
23
  const candidates = process.platform === 'win32' ? ['python', 'py'] : ['python3', 'python'];
17
24
  for (const command of candidates) {
18
25
  const result = spawnSync(command, ['-m', 'pip', 'install', 'graphifyy'], { stdio: 'inherit' });
19
26
  if (result.status === 0) return command;
20
27
  }
21
- const pythonUrl = 'https://www.python.org/downloads/';
22
28
  console.warn(`\n⚠ Could not install graphifyy automatically.`);
23
- console.warn(` Python not found? Download it from: ${pythonUrl}`);
29
+ console.warn(` Python not found? Download it from: https://www.python.org/downloads/`);
24
30
  console.warn(` Then run: pip install graphifyy\n`);
25
31
  return null;
26
32
  }
@@ -31,13 +37,13 @@ function spawnCheck(bin, args) {
31
37
  }
32
38
 
33
39
  function parseArgs(args) {
34
- const parsed = { agent: null };
35
- for (let i = 0; i < args.length; i++) {
36
- if (args[i] === '--agent' && args[i + 1]) {
37
- parsed.agent = args[++i];
40
+ const agents = [];
41
+ for (const arg of args) {
42
+ if (AGENT_FLAGS[arg]) {
43
+ agents.push(AGENT_FLAGS[arg]);
38
44
  }
39
45
  }
40
- return parsed;
46
+ return { agents };
41
47
  }
42
48
 
43
49
  const rl = createInterface({ input, output });
@@ -45,7 +51,17 @@ const cwd = resolve(process.cwd());
45
51
 
46
52
  try {
47
53
  console.log('\n─── pmc setup ───────────────────────────────────────\n');
48
- const { agent: requestedAgent } = parseArgs(process.argv.slice(2));
54
+ const { agents: requestedAgents } = parseArgs(process.argv.slice(2));
55
+
56
+ let agents;
57
+ if (requestedAgents.length > 0) {
58
+ agents = [...new Set(requestedAgents)];
59
+ console.log(` Target agents: ${agents.join(', ')}`);
60
+ } else {
61
+ const detected = detectSetupAgentType(cwd);
62
+ agents = [detected];
63
+ console.log(` Auto-detected agent: ${detected}`);
64
+ }
49
65
 
50
66
  const ollamaBaseUrl =
51
67
  (await rl.question('Ollama base URL [http://localhost:11434]: ')).trim() ||
@@ -57,33 +73,33 @@ try {
57
73
 
58
74
  installGraphify();
59
75
 
60
- const agent = detectSetupAgentType(cwd, { requestedAgent });
61
76
  const { globalConfig } = resolveConfigDirs(cwd);
62
- console.log(`\n Detected agent: ${agent}`);
63
77
 
64
78
  const result = await bootstrapProjectInstall({
65
79
  projectRoot: cwd,
66
80
  packageRoot,
67
81
  ollamaBaseUrl,
68
82
  ollamaModel,
69
- agent,
83
+ agents,
70
84
  });
71
85
 
72
- await installAgentTemplates({
73
- projectRoot: cwd,
74
- agent,
75
- packageRoot,
76
- globalConfigDir: agent === 'opencode' ? globalConfig : undefined,
77
- });
78
- console.log(` Installed ${agent} templates.`);
86
+ for (const agent of agents) {
87
+ await installAgentTemplates({
88
+ projectRoot: cwd,
89
+ agent,
90
+ packageRoot,
91
+ globalConfigDir: agent === 'opencode' ? globalConfig : undefined,
92
+ });
93
+ console.log(` ✓ Installed ${agent} templates.`);
94
+ }
79
95
 
80
96
  console.log('\n─── Installation complete ───────────────────────────\n');
81
97
  console.log(` Memory DB path: ${result.installState.memoryDbPath}`);
82
98
  console.log(` Embedding cache: ${result.installState.embeddingCachePath}`);
83
99
  console.log(` MCP config: ${result.configPath}`);
84
100
  console.log(` Command template: ${result.commandPath}`);
101
+ console.log(` Agents configured: ${agents.join(', ')}`);
85
102
 
86
- // Run doctor to surface any remaining issues
87
103
  console.log('\n─── Environment check ───────────────────────────────\n');
88
104
  const env = {
89
105
  ...process.env,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aabadin/project-memory-context",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Portable project memory context CLI — bootstraps semantic enrichment workflows for any AI coding agent.",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "type": "module",
@@ -1,9 +1,8 @@
1
1
  import { mkdir, readFile, writeFile } from 'node:fs/promises';
2
- import { basename, dirname, join } from 'node:path';
2
+ import { dirname, join } from 'node:path';
3
3
 
4
4
  import { ensureProjectMemoryContextDirs, writeJsonArtifact } from './artifacts.mjs';
5
5
  import { PMC_ENRICHMENT_CONFIG_FILE } from './enrichment-config.mjs';
6
- import { resolveConfigDirs } from './platform.mjs';
7
6
 
8
7
  async function readJson(filePath, fallback) {
9
8
  try {
@@ -63,50 +62,65 @@ async function writeMcpJson(projectRoot, installState) {
63
62
  return mcpPath;
64
63
  }
65
64
 
66
- async function ensureAgentConfigRegistration(projectRoot, installState, agentType) {
67
- if (agentType === 'opencode') {
68
- const opencodeDir = join(projectRoot, '.opencode');
69
- await mkdir(opencodeDir, { recursive: true });
70
- const configPath = join(opencodeDir, 'opencode.json');
71
- const config = await readJson(configPath, { $schema: 'https://opencode.ai/config.json' });
72
- const existing = Array.isArray(config.plugin) ? config.plugin : [];
73
- if (!existing.includes('@aabadin/project-memory-context')) {
74
- config.plugin = [...existing, '@aabadin/project-memory-context'];
75
- }
76
- config.mcp = {
77
- ...(config.mcp ?? {}),
78
- ...buildOpencodeMcpConfig(installState).mcp,
79
- };
80
- await mkdir(dirname(configPath), { recursive: true });
81
- await writeFile(configPath, `${JSON.stringify(config, null, 2)}\n`, 'utf8');
82
- await writeMcpJson(projectRoot, installState);
83
- return configPath;
65
+ async function ensureOpencodeConfig(projectRoot, installState) {
66
+ const opencodeDir = join(projectRoot, '.opencode');
67
+ await mkdir(opencodeDir, { recursive: true });
68
+ const configPath = join(opencodeDir, 'opencode.json');
69
+ const config = await readJson(configPath, { $schema: 'https://opencode.ai/config.json' });
70
+ const existing = Array.isArray(config.plugin) ? config.plugin : [];
71
+ if (!existing.includes('@aabadin/project-memory-context')) {
72
+ config.plugin = [...existing, '@aabadin/project-memory-context'];
84
73
  }
74
+ config.mcp = {
75
+ ...(config.mcp ?? {}),
76
+ ...buildOpencodeMcpConfig(installState).mcp,
77
+ };
78
+ await mkdir(dirname(configPath), { recursive: true });
79
+ await writeFile(configPath, `${JSON.stringify(config, null, 2)}\n`, 'utf8');
80
+ return configPath;
81
+ }
85
82
 
86
- const { projectConfig } = resolveConfigDirs(projectRoot);
87
- const agentDir = basename(projectConfig);
88
-
89
- if (agentDir === '.claude' || agentDir === '.cursor' || agentDir === '.pmc') {
90
- const mcpPath = await writeMcpJson(projectRoot, installState);
91
- const enrichPath = join(projectConfig, PMC_ENRICHMENT_CONFIG_FILE);
92
- const existingConfig = await readJson(enrichPath, {});
93
- const config = {
94
- ...existingConfig,
95
- enrichment: {
96
- ...existingConfig.enrichment,
97
- localModel: {
98
- ...existingConfig.enrichment?.localModel,
99
- baseUrl: installState.ollamaBaseUrl,
100
- model: installState.ollamaModel,
101
- },
83
+ async function ensureEnrichmentConfig(projectRoot, configDir, installState) {
84
+ const enrichPath = join(configDir, PMC_ENRICHMENT_CONFIG_FILE);
85
+ const existingConfig = await readJson(enrichPath, {});
86
+ const config = {
87
+ ...existingConfig,
88
+ enrichment: {
89
+ ...existingConfig.enrichment,
90
+ localModel: {
91
+ ...existingConfig.enrichment?.localModel,
92
+ baseUrl: installState.ollamaBaseUrl,
93
+ model: installState.ollamaModel,
102
94
  },
103
- };
104
- await mkdir(dirname(enrichPath), { recursive: true });
105
- await writeFile(enrichPath, `${JSON.stringify(config, null, 2)}\n`, 'utf8');
106
- return mcpPath;
95
+ },
96
+ };
97
+ await mkdir(dirname(enrichPath), { recursive: true });
98
+ await writeFile(enrichPath, `${JSON.stringify(config, null, 2)}\n`, 'utf8');
99
+ }
100
+
101
+ async function ensureAgentConfigs(projectRoot, installState, agents) {
102
+ let primaryConfigPath = null;
103
+
104
+ for (const agent of agents) {
105
+ if (agent === 'opencode') {
106
+ primaryConfigPath = primaryConfigPath ?? await ensureOpencodeConfig(projectRoot, installState);
107
+ }
108
+ if (agent === 'claude-code') {
109
+ const claudeDir = join(projectRoot, '.claude');
110
+ await mkdir(claudeDir, { recursive: true });
111
+ await ensureEnrichmentConfig(projectRoot, claudeDir, installState);
112
+ primaryConfigPath = primaryConfigPath ?? join(projectRoot, '.mcp.json');
113
+ }
114
+ if (agent === 'cursor') {
115
+ const cursorDir = join(projectRoot, '.cursor');
116
+ await mkdir(cursorDir, { recursive: true });
117
+ await ensureEnrichmentConfig(projectRoot, cursorDir, installState);
118
+ primaryConfigPath = primaryConfigPath ?? join(projectRoot, '.mcp.json');
119
+ }
107
120
  }
108
121
 
109
- return writeMcpJson(projectRoot, installState);
122
+ await writeMcpJson(projectRoot, installState);
123
+ return primaryConfigPath ?? join(projectRoot, '.mcp.json');
110
124
  }
111
125
 
112
126
  async function copyTemplate(packageRoot, templateName, projectRoot) {
@@ -124,8 +138,10 @@ export async function bootstrapProjectInstall({
124
138
  ollamaBaseUrl,
125
139
  ollamaModel,
126
140
  embeddingCachePath,
141
+ agents = [],
127
142
  agent,
128
143
  }) {
144
+ const resolvedAgents = agents.length > 0 ? agents : (agent ? [agent] : ['generic']);
129
145
  const dirs = await ensureProjectMemoryContextDirs(projectRoot);
130
146
  const memoryDbPath = join(dirs.base, 'memory-db');
131
147
  const installState = {
@@ -139,7 +155,7 @@ export async function bootstrapProjectInstall({
139
155
 
140
156
  await mkdir(memoryDbPath, { recursive: true });
141
157
  await writeJsonArtifact(join(dirs.base, 'install.json'), installState);
142
- const configPath = await ensureAgentConfigRegistration(projectRoot, installState, agent);
158
+ const configPath = await ensureAgentConfigs(projectRoot, installState, resolvedAgents);
143
159
  const commandPath = await copyTemplate(packageRoot, 'project-memory-context.md', projectRoot);
144
160
  const workflowPath = await copyTemplate(packageRoot, 'project-memory-context workflow.md', projectRoot);
145
161
 
@@ -148,5 +164,6 @@ export async function bootstrapProjectInstall({
148
164
  configPath,
149
165
  commandPath,
150
166
  workflowPath,
167
+ agents: resolvedAgents,
151
168
  };
152
169
  }
@@ -91,10 +91,13 @@ async function installOpencode({ projectRoot, packageRoot, placeholders, globalC
91
91
  const globalDir = globalConfigDir;
92
92
 
93
93
  const commandTemplates = [
94
- 'opencode/commands/new-project.md',
94
+ 'opencode/commands/map-project.md',
95
95
  'opencode/commands/get-context.md',
96
96
  'opencode/commands/sync-context.md',
97
97
  'opencode/commands/sanitize.md',
98
+ 'opencode/commands/enrich-status.md',
99
+ 'opencode/commands/doctor.md',
100
+ 'opencode/commands/init-project.md',
98
101
  ];
99
102
 
100
103
  for (const tpl of commandTemplates) {
@@ -2,7 +2,7 @@
2
2
 
3
3
  <!-- pmc:init -->
4
4
 
5
- When the user types `/new-project`, run:
5
+ When the user types `/map-project`, run:
6
6
 
7
7
  ```bash
8
8
  {{PMC_BIN}} bootstrap . --all --enrich
@@ -14,6 +14,24 @@ When the user types `/get-context`, run:
14
14
  {{PMC_BIN}} context . --refresh
15
15
  ```
16
16
 
17
+ When the user types `/enrich-status`, run:
18
+
19
+ ```bash
20
+ {{PMC_BIN}} status .
21
+ ```
22
+
23
+ When the user types `/doctor`, run:
24
+
25
+ ```bash
26
+ {{PMC_BIN}} doctor
27
+ ```
28
+
29
+ When the user types `/init-project`, run:
30
+
31
+ ```bash
32
+ {{PMC_BIN}} init .
33
+ ```
34
+
17
35
  When the user types `/sync-context`, process `.planning/project-memory-context/enrichment/sync-manifest.json` and upsert pending entries into `agent-memory`.
18
36
 
19
37
  When the user types `/sanitize`, run:
@@ -2,7 +2,7 @@
2
2
 
3
3
  <!-- pmc:init -->
4
4
 
5
- When the user types "/new-project", run:
5
+ When the user types "/map-project", run:
6
6
 
7
7
  ```bash
8
8
  {{PMC_BIN}} bootstrap . --all --enrich
@@ -14,6 +14,24 @@ When the user types "/get-context", run:
14
14
  {{PMC_BIN}} context . --refresh
15
15
  ```
16
16
 
17
+ When the user types "/enrich-status", run:
18
+
19
+ ```bash
20
+ {{PMC_BIN}} status .
21
+ ```
22
+
23
+ When the user types "/doctor", run:
24
+
25
+ ```bash
26
+ {{PMC_BIN}} doctor
27
+ ```
28
+
29
+ When the user types "/init-project", run:
30
+
31
+ ```bash
32
+ {{PMC_BIN}} init .
33
+ ```
34
+
17
35
  When the user types "/sync-context", process `.planning/project-memory-context/enrichment/sync-manifest.json` and upsert pending entries into `agent-memory`.
18
36
 
19
37
  When the user types "/sanitize", run:
@@ -0,0 +1,21 @@
1
+ ---
2
+ name: doctor
3
+ description: Run environment diagnostics — check Python, Ollama, Node, agent-memory, and graphify.
4
+ argument-hint: ""
5
+ allowed-tools:
6
+ - Bash
7
+ ---
8
+
9
+ <objective>
10
+ Run the PMC environment doctor to verify all dependencies are correctly installed and configured.
11
+ </objective>
12
+
13
+ <execution>
14
+ Run:
15
+
16
+ ```bash
17
+ {{PMC_BIN}} doctor
18
+ ```
19
+
20
+ This checks: Node version, Python availability, graphifyy installation, Ollama connectivity, MEMORY_DB_PATH, and embedding cache path.
21
+ </execution>
@@ -0,0 +1,21 @@
1
+ ---
2
+ name: enrich-status
3
+ description: Show enrichment progress — pending, enriched, stale, and failed symbols in the worklist.
4
+ argument-hint: ""
5
+ allowed-tools:
6
+ - Bash
7
+ ---
8
+
9
+ <objective>
10
+ Display the current enrichment queue status: how many symbols have been enriched, how many are pending, stale, or failed.
11
+ </objective>
12
+
13
+ <execution>
14
+ Run:
15
+
16
+ ```bash
17
+ {{PMC_BIN}} status .
18
+ ```
19
+
20
+ This shows the worklist summary with counts for pending, enriched, stale, and failed symbols.
21
+ </execution>
@@ -0,0 +1,21 @@
1
+ ---
2
+ name: init-project
3
+ description: Initialize PMC project structure — creates .planning/project-memory-context/ directory tree.
4
+ argument-hint: ""
5
+ allowed-tools:
6
+ - Bash
7
+ ---
8
+
9
+ <objective>
10
+ Initialize the PMC directory structure in the current project. Creates the .planning/project-memory-context/ hierarchy and default configuration.
11
+ </objective>
12
+
13
+ <execution>
14
+ Run:
15
+
16
+ ```bash
17
+ {{PMC_BIN}} init .
18
+ ```
19
+
20
+ This creates the full directory tree under `.planning/project-memory-context/` with intake, graph, enrichment, project-context, and runs subdirectories.
21
+ </execution>
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: new-project
2
+ name: map-project
3
3
  description: Bootstrap PMC in the current project with graphify, worklist, and base memories.
4
4
  argument-hint: "[--all] [--enrich]"
5
5
  allowed-tools: