@engramlabs/mcp 0.1.3-alpha → 0.1.4-alpha

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.
Files changed (3) hide show
  1. package/README.md +26 -56
  2. package/agent-install.js +109 -53
  3. package/package.json +6 -6
package/README.md CHANGED
@@ -1,47 +1,35 @@
1
1
  # @engramlabs/mcp
2
2
 
3
- Local-first agentic **knowledge & memory layer** for AI agents — via MCP.
3
+ Local-first **knowledge & memory layer** for AI agents — via MCP.
4
4
 
5
- Engram gives your agent durable memory, source-grounded knowledge, a code
6
- graph, beliefs with contradiction detection, and governed retrieval — all in
7
- SQLite files on your machine. No cloud, no telemetry, no network calls on
8
- the default path.
5
+ Durable memory, a code graph, beliefs, and governed retrieval in SQLite
6
+ files on your machine. No cloud, no telemetry.
9
7
 
10
- ## Install
8
+ ## Quick start
11
9
 
12
10
  ```bash
13
11
  npm install -g @engramlabs/mcp@alpha
12
+ engram-mcp install --agent claude # skills + hooks + red-forman subagent
14
13
  ```
15
14
 
16
- ## Enable your MCP host + agent bundle
15
+ Hosts: `claude` · `claude-desktop` · `cursor` · `codex` · `pi` · `copilot` · `all`
17
16
 
18
- One command — no JSON editing:
17
+ **Project scope** — install skills, hooks, and agents into the repo
18
+ (committed, shared with the team) instead of your home directory:
19
19
 
20
20
  ```bash
21
- engram-mcp install --agent claude # skills + hooks + red-forman subagent
22
- # or: codex, copilot, pi, all
21
+ cd your-repo
22
+ engram-mcp install --agent claude --scope project
23
23
  ```
24
24
 
25
- MCP server registration only:
25
+ Lands in `.claude/`, `.agents/skills/` (Codex + Copilot + pi read this
26
+ cross-tool dir), `.codex/hooks.json`, `.github/hooks/`, `.pi/`.
26
27
 
27
- ```bash
28
- engram-mcp install --client claude # Claude Code
29
- engram-mcp install --client claude-desktop # Claude Desktop
30
- engram-mcp install --client cursor # Cursor
31
- engram-mcp install --client codex # Codex CLI
32
- engram-mcp install --client pi # pi
33
- engram-mcp install --client copilot # GitHub Copilot / VS Code
34
- ```
35
-
36
- Or run directly:
28
+ MCP server only (no skills/hooks): `engram-mcp install --client <host>`
37
29
 
38
- ```bash
39
- npx @engramlabs/mcp@alpha --storage ~/.engram
40
- ```
30
+ Or run directly: `npx @engramlabs/mcp@alpha --storage ~/.engram`
41
31
 
42
- ### Manual configuration
43
-
44
- Add to your `.mcp.json` (or your host's config):
32
+ ### Manual config
45
33
 
46
34
  ```json
47
35
  {
@@ -58,40 +46,22 @@ Add to your `.mcp.json` (or your host's config):
58
46
 
59
47
  | | |
60
48
  |---|---|
61
- | **Remember** | `write_memory`, `store_knowledge` — decisions, observations, facts |
62
- | **Recall** | `recall`, `search`, `get_context` — fused multi-lane retrieval |
63
- | **Understand code** | `scan_repo` → `symbol_context`, `change_impact`, `architecture` |
64
- | **Read source** | `fetch_content` — stitch any indexed file's content back |
65
- | **Track beliefs** | `belief_get`, `contradiction_list` — derived stances, open tensions |
66
- | **Runbooks** | `procedure_put`, `procedure_list` — replayable with success/fail counters |
67
- | **Correct** | `forget`, `graph_health` — remove wrong data, monitor health |
68
- | **Adversarial review** | `red-forman` subagent — severity-tagged findings on any diff before you declare done |
49
+ | **Memory** | remember decisions, gotchas, invariants — recall them automatically |
50
+ | **Code graph** | index a repo → symbols, blast radius, architecture |
51
+ | **Skills** | `engram-index/learn/search/plan/implement` — evidence-labeled workflows |
52
+ | **Auto-recall** | hooks inject relevant memory per prompt; irrelevant stays silent |
53
+ | **Adversarial review** | `red-forman` subagent — severity-tagged findings before you ship |
69
54
 
70
55
  ## Platforms
71
56
 
72
- | OS | Architecture | Binary size |
73
- |---|---|---|
74
- | Linux | x86-64 | ~49 MB |
75
- | Linux | ARM64 | ~49 MB |
76
- | macOS | Apple Silicon | ~49 MB |
77
- | Windows | x86-64 | ~49 MB |
78
-
79
- Platform binaries install automatically as optional dependencies — you
80
- don't need to pick one.
57
+ Linux x64/ARM64 · macOS Apple Silicon · Windows x64 — binaries install
58
+ automatically per machine.
81
59
 
82
60
  ## Privacy
83
61
 
84
- - All data lives in SQLite files under `--storage` (default: `~/.engram`)
85
- - No telemetry, ever
86
- - No cloud calls on the default path
87
- - Delete the storage directory = everything is gone
88
-
89
- ## Learn more
90
-
91
- - [GitHub](https://github.com/phanijapps/engram) — source, architecture, docs
92
- - [HOW-TO](https://github.com/phanijapps/engram/blob/main/mcp/engram-mcp/HOW-TO.md) — full setup guide
93
- - [RFC-0021](https://github.com/phanijapps/engram/blob/main/docs/rfcs/0021-npm-distribution-rollout.md) — distribution design
62
+ All data in SQLite under `~/.engram`. No telemetry, no cloud. Delete
63
+ the directory = everything is gone.
94
64
 
95
- ## License
65
+ ## Links
96
66
 
97
- MIT
67
+ [GitHub](https://github.com/phanijapps/engram) · [Setup guide](https://github.com/phanijapps/engram/blob/main/mcp/engram-mcp/HOW-TO.md) · MIT
package/agent-install.js CHANGED
@@ -147,16 +147,17 @@ function mergeClaudeHooks(file, entries, remove) {
147
147
  }
148
148
 
149
149
  const HOSTS = {
150
+ // USER scope installs to the home directory (available everywhere);
151
+ // PROJECT scope installs into the current repo (committed, per-team).
150
152
  claude: {
151
153
  label: 'Claude Code',
152
- skillsDir: (home) => path.join(home, '.claude', 'skills'),
153
- agentFile: (home) => [path.join(home, '.claude', 'agents'), 'red-forman.md'],
154
- install(home, remove, written) {
155
- copySkills(this.skillsDir(home), written);
156
- const [agentDir, agentName] = this.agentFile(home);
157
- if (remove) { try { fs.rmSync(path.join(agentDir, agentName)); } catch {} }
158
- else copyAgent(agentDir, 'red-forman.claude.md', agentName, written);
159
- const settings = path.join(home, '.claude', 'settings.json');
154
+ install(home, remove, written, cwd, scope) {
155
+ const root = scope === 'project' ? path.join(cwd, '.claude') : path.join(home, '.claude');
156
+ copySkills(path.join(root, 'skills'), written);
157
+ const agentDir = path.join(root, 'agents');
158
+ if (remove) { try { fs.rmSync(path.join(agentDir, 'red-forman.md')); } catch {} }
159
+ else copyAgent(agentDir, 'red-forman.claude.md', 'red-forman.md', written);
160
+ const settings = path.join(root, 'settings.json');
160
161
  const recall = hookScript('recall-context.cjs');
161
162
  const stale = hookScript('stale-index.cjs');
162
163
  mergeClaudeHooks(
@@ -173,40 +174,70 @@ const HOSTS = {
173
174
  },
174
175
  codex: {
175
176
  label: 'Codex',
176
- skillsDir: (home) => path.join(home, '.agents', 'skills'),
177
- install(home, remove, written) {
178
- copySkills(this.skillsDir(home), written);
179
- // Codex agents: ~/.codex/agents/*.yaml (YAML form — the TOML
180
- // spelling is deprecated).
177
+ install(home, remove, written, cwd, scope) {
178
+ // Skills: the cross-tool .agents/skills dir (project) or ~/.agents/skills (user).
179
+ copySkills(
180
+ scope === 'project' ? path.join(cwd, '.agents', 'skills') : path.join(home, '.agents', 'skills'),
181
+ written,
182
+ );
183
+ // Agents: Codex discovers agents at user level only (~/.codex/agents,
184
+ // YAML form) — no documented project-agent location.
181
185
  const agentDir = path.join(home, '.codex', 'agents');
182
186
  if (remove) { try { fs.rmSync(path.join(agentDir, 'red-forman.yaml')); } catch {} }
183
- else copyAgent(agentDir, 'red-forman.codex.yaml', 'red-forman.yaml', written);
187
+ else {
188
+ copyAgent(agentDir, 'red-forman.codex.yaml', 'red-forman.yaml', written);
189
+ if (scope === 'project') {
190
+ process.stdout.write(' note: Codex agents are user-scope (no project-agent discovery)\n');
191
+ }
192
+ }
184
193
  const recall = hookScript('recall-context.cjs');
185
194
  const stale = hookScript('stale-index.cjs');
186
- const body = remove
187
- ? null
188
- : [
189
- '[[hooks.UserPromptSubmit]]',
190
- ' [[hooks.UserPromptSubmit.hooks]]',
191
- ' type = "command"',
192
- ` command = 'node "${recall}"'`,
193
- ' async = true',
194
- ' statusMessage = "engram recall"',
195
- '',
196
- '[[hooks.Stop]]',
197
- ' [[hooks.Stop.hooks]]',
198
- ' type = "command"',
199
- ` command = 'node "${stale}"'`,
200
- '',
201
- '[[hooks.SessionStart]]',
202
- ' matcher = "startup|resume"',
203
- ' [[hooks.SessionStart.hooks]]',
204
- ' type = "command"',
205
- ` command = 'node "${recall}"'`,
206
- ' additionalContextLimit = 2000',
207
- ].join('\n');
208
- writeTomlSection(path.join(home, '.codex', 'config.toml'), 'hooks', body);
209
- written.push(path.join(home, '.codex', 'config.toml'));
195
+ if (scope === 'project') {
196
+ // Project hooks live in <repo>/.codex/hooks.json (JSON, not TOML).
197
+ const file = path.join(cwd, '.codex', 'hooks.json');
198
+ if (remove) {
199
+ try { fs.rmSync(file); } catch {}
200
+ } else {
201
+ writeJson(file, {
202
+ description: 'engram agent bundle (skills + hooks + subagent)',
203
+ hooks: {
204
+ UserPromptSubmit: [
205
+ { hooks: [{ type: 'command', command: `node "${recall}"`, async: true, statusMessage: 'engram recall' }] },
206
+ ],
207
+ Stop: [{ hooks: [{ type: 'command', command: `node "${stale}"` }] }],
208
+ SessionStart: [
209
+ { matcher: 'startup|resume', hooks: [{ type: 'command', command: `node "${recall}"`, additionalContextLimit: 2000 }] },
210
+ ],
211
+ },
212
+ });
213
+ written.push(file);
214
+ }
215
+ } else {
216
+ const body = remove
217
+ ? null
218
+ : [
219
+ '[[hooks.UserPromptSubmit]]',
220
+ ' [[hooks.UserPromptSubmit.hooks]]',
221
+ ' type = "command"',
222
+ ` command = 'node "${recall}"'`,
223
+ ' async = true',
224
+ ' statusMessage = "engram recall"',
225
+ '',
226
+ '[[hooks.Stop]]',
227
+ ' [[hooks.Stop.hooks]]',
228
+ ' type = "command"',
229
+ ` command = 'node "${stale}"'`,
230
+ '',
231
+ '[[hooks.SessionStart]]',
232
+ ' matcher = "startup|resume"',
233
+ ' [[hooks.SessionStart.hooks]]',
234
+ ' type = "command"',
235
+ ` command = 'node "${recall}"'`,
236
+ ' additionalContextLimit = 2000',
237
+ ].join('\n');
238
+ writeTomlSection(path.join(home, '.codex', 'config.toml'), 'hooks', body);
239
+ written.push(path.join(home, '.codex', 'config.toml'));
240
+ }
210
241
  if (!remove) {
211
242
  process.stdout.write(' note: run /hooks inside Codex to trust the new hooks\n');
212
243
  }
@@ -214,20 +245,24 @@ const HOSTS = {
214
245
  },
215
246
  copilot: {
216
247
  label: 'GitHub Copilot',
217
- skillsDir: (home) => path.join(home, '.agents', 'skills'),
218
- install(home, remove, written, cwd) {
219
- copySkills(this.skillsDir(home), written);
220
- // Copilot custom agents are repo-scoped: .github/agents/.
248
+ install(home, remove, written, cwd, scope) {
249
+ // Skills: .agents/skills (project, cross-tool) or ~/.agents/skills (user).
250
+ copySkills(
251
+ scope === 'project' ? path.join(cwd, '.agents', 'skills') : path.join(home, '.agents', 'skills'),
252
+ written,
253
+ );
254
+ // Agents: repo-scoped either way (.github/agents/).
221
255
  const agentDir = path.join(cwd || process.cwd(), '.github', 'agents');
222
256
  if (remove) { try { fs.rmSync(path.join(agentDir, 'red-forman.md')); } catch {} }
223
257
  else copyAgent(agentDir, 'red-forman.copilot.md', 'red-forman.md', written);
224
258
  // Per-prompt injection is not available to Copilot command hooks
225
259
  // (output dropped by design) — sessionStart only. Honest limitation.
226
- const file = path.join(home, '.copilot', 'hooks', 'engram.json');
260
+ const file =
261
+ scope === 'project'
262
+ ? path.join(cwd, '.github', 'hooks', 'engram.json')
263
+ : path.join(home, '.copilot', 'hooks', 'engram.json');
227
264
  if (remove) {
228
- try {
229
- fs.rmSync(file);
230
- } catch {}
265
+ try { fs.rmSync(file); } catch {}
231
266
  } else {
232
267
  writeJson(file, {
233
268
  version: 1,
@@ -241,17 +276,31 @@ const HOSTS = {
241
276
  });
242
277
  written.push(file);
243
278
  }
279
+ if (scope === 'project' && !remove) {
280
+ process.stdout.write(' note: commit .github/ and .agents/ so the team gets the bundle\n');
281
+ }
244
282
  },
245
283
  },
246
284
  pi: {
247
285
  label: 'pi',
248
- skillsDir: (home) => path.join(home, '.pi', 'agent', 'skills'),
249
- install(home, remove, written) {
250
- copySkills(this.skillsDir(home), written);
251
- const agentDir = path.join(home, '.pi', 'agent', 'agents');
286
+ install(home, remove, written, cwd, scope) {
287
+ // Skills: pi reads the cross-tool .agents/skills at project level
288
+ // (same dir codex/copilot read) or ~/.pi/agent/skills at user level.
289
+ copySkills(
290
+ scope === 'project' ? path.join(cwd, '.agents', 'skills') : path.join(home, '.pi', 'agent', 'skills'),
291
+ written,
292
+ );
293
+ // Agents: .pi/agents/ (project) or ~/.pi/agent/agents/ (user).
294
+ const agentDir =
295
+ scope === 'project' ? path.join(cwd, '.pi', 'agents') : path.join(home, '.pi', 'agent', 'agents');
252
296
  if (remove) { try { fs.rmSync(path.join(agentDir, 'red-forman.md')); } catch {} }
253
297
  else copyAgent(agentDir, 'red-forman.pi.md', 'red-forman.md', written);
254
- const ext = path.join(home, '.pi', 'agent', 'extensions', 'engram-recall.cjs');
298
+ // Extensions are pi's hook mechanism: .pi/extensions/ (project)
299
+ // or ~/.pi/agent/extensions/ (user).
300
+ const ext =
301
+ scope === 'project'
302
+ ? path.join(cwd, '.pi', 'extensions', 'engram-recall.cjs')
303
+ : path.join(home, '.pi', 'agent', 'extensions', 'engram-recall.cjs');
255
304
  if (remove) {
256
305
  try {
257
306
  fs.rmSync(ext);
@@ -270,23 +319,30 @@ function agentInstall(args) {
270
319
  const cwd = process.cwd();
271
320
  let target = null;
272
321
  let remove = false;
322
+ let scope = 'user';
273
323
  let storage = process.env.ENGRAM_STORAGE || path.join(home, '.engram');
274
324
  for (let i = 0; i < args.length; i++) {
275
325
  if (args[i] === '--agent') target = args[++i];
276
326
  else if (args[i] === '--remove') remove = true;
327
+ else if (args[i] === '--scope') scope = args[++i];
277
328
  else if (args[i] === '--storage') storage = args[++i];
278
329
  }
330
+ if (scope !== 'user' && scope !== 'project') {
331
+ process.stderr.write(`engram-mcp install: --scope must be 'user' or 'project'\n`);
332
+ process.exit(1);
333
+ }
279
334
  if (!target || (target !== 'all' && !HOSTS[target])) {
280
335
  process.stderr.write(
281
336
  `engram-mcp install: ${target ? `unknown agent '${target}'` : 'missing --agent'}\n` +
282
337
  `Agents: ${Object.keys(HOSTS).join(', ')}, all\n` +
283
- `Usage: engram-mcp install --agent <id> [--remove] [--storage <path>]\n`,
338
+ `Usage: engram-mcp install --agent <id> [--scope user|project] [--remove] [--storage <path>]\n`,
284
339
  );
285
340
  process.exit(1);
286
341
  }
287
342
  const ids = target === 'all' ? Object.keys(HOSTS) : [target];
288
343
  process.stdout.write(
289
344
  `${remove ? 'Removing' : 'Installing'} engram agent bundle (skills + hooks + subagents)\n` +
345
+ ` scope: ${scope}${scope === 'project' ? ` (${cwd})` : ''}\n` +
290
346
  ` storage: ${storage}\n\n`,
291
347
  );
292
348
  for (const id of ids) {
@@ -294,7 +350,7 @@ function agentInstall(args) {
294
350
  process.stdout.write(`[${host.label}]\n`);
295
351
  const written = [];
296
352
  try {
297
- host.install(home, remove, written, cwd);
353
+ host.install(home, remove, written, cwd, scope);
298
354
  for (const w of written) process.stdout.write(` ${remove ? 'cleaned' : 'wrote'}: ${w}\n`);
299
355
  if (id === 'copilot' && !remove) {
300
356
  process.stdout.write(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@engramlabs/mcp",
3
- "version": "0.1.3-alpha",
3
+ "version": "0.1.4-alpha",
4
4
  "description": "Local-first agentic memory: the engram MCP server launcher. Memory + knowledge graph + beliefs + code intelligence for any MCP client.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -32,11 +32,11 @@
32
32
  "local-first"
33
33
  ],
34
34
  "optionalDependencies": {
35
- "@engramlabs/mcp-linux-x64-gnu": "0.1.3-alpha",
36
- "@engramlabs/mcp-linux-arm64-gnu": "0.1.3-alpha",
37
- "@engramlabs/mcp-darwin-arm64": "0.1.3-alpha",
38
- "@engramlabs/mcp-darwin-x64": "0.1.3-alpha",
39
- "@engramlabs/mcp-win32-x64": "0.1.3-alpha"
35
+ "@engramlabs/mcp-linux-x64-gnu": "0.1.4-alpha",
36
+ "@engramlabs/mcp-linux-arm64-gnu": "0.1.4-alpha",
37
+ "@engramlabs/mcp-darwin-arm64": "0.1.4-alpha",
38
+ "@engramlabs/mcp-darwin-x64": "0.1.4-alpha",
39
+ "@engramlabs/mcp-win32-x64": "0.1.4-alpha"
40
40
  },
41
41
  "scripts": {
42
42
  "test": "node --test test/*.test.cjs"