@engramlabs/mcp 0.1.2-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.
package/README.md CHANGED
@@ -1,40 +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
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 --client claude # Claude Code
22
- engram-mcp install --client claude-desktop # Claude Desktop
23
- engram-mcp install --client cursor # Cursor
24
- engram-mcp install --client codex # Codex CLI
25
- engram-mcp install --client pi # pi
26
- engram-mcp install --client copilot # GitHub Copilot / VS Code
21
+ cd your-repo
22
+ engram-mcp install --agent claude --scope project
27
23
  ```
28
24
 
29
- Or run directly:
25
+ Lands in `.claude/`, `.agents/skills/` (Codex + Copilot + pi read this
26
+ cross-tool dir), `.codex/hooks.json`, `.github/hooks/`, `.pi/`.
30
27
 
31
- ```bash
32
- npx @engramlabs/mcp@alpha --storage ~/.engram
33
- ```
28
+ MCP server only (no skills/hooks): `engram-mcp install --client <host>`
34
29
 
35
- ### Manual configuration
30
+ Or run directly: `npx @engramlabs/mcp@alpha --storage ~/.engram`
36
31
 
37
- Add to your `.mcp.json` (or your host's config):
32
+ ### Manual config
38
33
 
39
34
  ```json
40
35
  {
@@ -51,39 +46,22 @@ Add to your `.mcp.json` (or your host's config):
51
46
 
52
47
  | | |
53
48
  |---|---|
54
- | **Remember** | `write_memory`, `store_knowledge` — decisions, observations, facts |
55
- | **Recall** | `recall`, `search`, `get_context` — fused multi-lane retrieval |
56
- | **Understand code** | `scan_repo` → `symbol_context`, `change_impact`, `architecture` |
57
- | **Read source** | `fetch_content` — stitch any indexed file's content back |
58
- | **Track beliefs** | `belief_get`, `contradiction_list` — derived stances, open tensions |
59
- | **Runbooks** | `procedure_put`, `procedure_list` — replayable with success/fail counters |
60
- | **Correct** | `forget`, `graph_health` — remove wrong data, monitor health |
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 |
61
54
 
62
55
  ## Platforms
63
56
 
64
- | OS | Architecture | Binary size |
65
- |---|---|---|
66
- | Linux | x86-64 | ~49 MB |
67
- | Linux | ARM64 | ~49 MB |
68
- | macOS | Apple Silicon | ~49 MB |
69
- | Windows | x86-64 | ~49 MB |
70
-
71
- Platform binaries install automatically as optional dependencies — you
72
- don't need to pick one.
57
+ Linux x64/ARM64 · macOS Apple Silicon · Windows x64 — binaries install
58
+ automatically per machine.
73
59
 
74
60
  ## Privacy
75
61
 
76
- - All data lives in SQLite files under `--storage` (default: `~/.engram`)
77
- - No telemetry, ever
78
- - No cloud calls on the default path
79
- - Delete the storage directory = everything is gone
80
-
81
- ## Learn more
82
-
83
- - [GitHub](https://github.com/phanijapps/engram) — source, architecture, docs
84
- - [HOW-TO](https://github.com/phanijapps/engram/blob/main/mcp/engram-mcp/HOW-TO.md) — full setup guide
85
- - [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.
86
64
 
87
- ## License
65
+ ## Links
88
66
 
89
- MIT
67
+ [GitHub](https://github.com/phanijapps/engram) · [Setup guide](https://github.com/phanijapps/engram/blob/main/mcp/engram-mcp/HOW-TO.md) · MIT
@@ -0,0 +1,369 @@
1
+ /**
2
+ * Agent bundle installer (RFC-0022 Phase 3): skills + hooks + MCP
3
+ * registration for a host, in one command.
4
+ *
5
+ * engram-mcp install --agent claude|codex|copilot|pi|all [--remove]
6
+ *
7
+ * What each host gets:
8
+ * claude ~/.claude/skills/engram-* + ~/.claude/settings.json hooks
9
+ * (UserPromptSubmit async, Stop, SessionStart)
10
+ * codex ~/.agents/skills/engram-* + ~/.codex/hooks.json (UserPromptSubmit,
11
+ * Stop, SessionStart) — Codex requires /hooks trust review
12
+ * copilot ~/.agents/skills/engram-* (shared with codex) + ~/.copilot/hooks/
13
+ * engram.json (sessionStart only — per-prompt injection is not
14
+ * available to Copilot command hooks; documented limitation)
15
+ * pi ~/.pi/agent/skills/engram-* + ~/.pi/agent/extensions/engram-recall.cjs
16
+ *
17
+ * Fail-open philosophy: install reports everything it writes; --remove
18
+ * undoes exactly the entries this installer owns (name-tagged).
19
+ */
20
+ 'use strict';
21
+
22
+ const fs = require('node:fs');
23
+ const os = require('node:os');
24
+ const path = require('node:path');
25
+
26
+ const LAUNCHER_DIR = __dirname;
27
+ const TAG = 'engram (engram-mcp installer)';
28
+
29
+ /** Locate the skills source: installed package first, dev checkout second. */
30
+ function skillsSource() {
31
+ const candidates = [
32
+ path.join(LAUNCHER_DIR, 'skills'),
33
+ path.join(LAUNCHER_DIR, '..', '..', 'mcp', 'engram-mcp', 'skills'),
34
+ ];
35
+ for (const c of candidates) {
36
+ if (fs.existsSync(path.join(c, 'engram-index', 'SKILL.md'))) return c;
37
+ }
38
+ return null;
39
+ }
40
+
41
+ /** Locate the agents source (subagent definitions, per-platform dialects). */
42
+ function agentsSource() {
43
+ const candidates = [
44
+ path.join(LAUNCHER_DIR, 'agents'),
45
+ path.join(LAUNCHER_DIR, '..', '..', 'mcp', 'engram-mcp', 'agents'),
46
+ ];
47
+ for (const c of candidates) {
48
+ if (fs.existsSync(path.join(c, 'red-forman.claude.md'))) return c;
49
+ }
50
+ return null;
51
+ }
52
+
53
+ /** Install a subagent definition into `destDir` under `fileName`. */
54
+ function copyAgent(destDir, srcName, destName, written) {
55
+ const src = agentsSource();
56
+ if (!src) {
57
+ process.stderr.write('engram-mcp: agents source not found (package incomplete?)\n');
58
+ return;
59
+ }
60
+ fs.mkdirSync(destDir, { recursive: true });
61
+ const to = path.join(destDir, destName);
62
+ fs.copyFileSync(path.join(src, srcName), to);
63
+ written.push(to);
64
+ }
65
+
66
+ function hookScript(name) {
67
+ return path.join(LAUNCHER_DIR, 'hooks', name);
68
+ }
69
+
70
+ function nodeCommand(script) {
71
+ return { command: 'node', args: [script] };
72
+ }
73
+
74
+ function readJson(file) {
75
+ try {
76
+ return JSON.parse(fs.readFileSync(file, 'utf8'));
77
+ } catch {
78
+ return {};
79
+ }
80
+ }
81
+
82
+ function writeJson(file, obj) {
83
+ fs.mkdirSync(path.dirname(file), { recursive: true });
84
+ fs.writeFileSync(file, JSON.stringify(obj, null, 2) + '\n');
85
+ }
86
+
87
+ function writeTomlSection(file, section, body) {
88
+ // Appends a TOML section ([[hooks.UserPromptSubmit]] style) or removes
89
+ // previously-installed tagged sections. Simple line-based append; Codex
90
+ // merges hooks.json + inline tables, and we own only our tagged block.
91
+ fs.mkdirSync(path.dirname(file), { recursive: true });
92
+ let text = '';
93
+ try {
94
+ text = fs.readFileSync(file, 'utf8');
95
+ } catch {}
96
+ const begin = `# BEGIN ${TAG}`;
97
+ const end = `# END ${TAG}`;
98
+ const startIdx = text.indexOf(begin);
99
+ if (startIdx >= 0) {
100
+ const endIdx = text.indexOf(end);
101
+ text =
102
+ text.slice(0, startIdx) +
103
+ text.slice(endIdx >= 0 ? endIdx + end.length : startIdx + begin.length);
104
+ }
105
+ if (body) {
106
+ text = text.trimEnd() + '\n\n' + begin + '\n' + body.trim() + '\n' + end + '\n';
107
+ } else {
108
+ text = text.trimEnd() + (text ? '\n' : '');
109
+ }
110
+ fs.writeFileSync(file, text);
111
+ }
112
+
113
+ function copySkills(destRoot, written) {
114
+ const src = skillsSource();
115
+ if (!src) {
116
+ process.stderr.write('engram-mcp: skills source not found (package incomplete?)\n');
117
+ return;
118
+ }
119
+ for (const skill of ['engram-index', 'engram-learn', 'engram-search', 'engram-plan', 'engram-implement']) {
120
+ const from = path.join(src, skill);
121
+ const to = path.join(destRoot, skill);
122
+ if (!fs.existsSync(path.join(from, 'SKILL.md'))) continue;
123
+ fs.rmSync(to, { recursive: true, force: true });
124
+ fs.mkdirSync(path.dirname(to), { recursive: true });
125
+ fs.cpSync(from, to, { recursive: true });
126
+ written.push(to);
127
+ }
128
+ }
129
+
130
+ /** Merge our hook entries into a Claude-style settings.json. */
131
+ function mergeClaudeHooks(file, entries, remove) {
132
+ const cfg = readJson(file);
133
+ cfg.hooks = cfg.hooks || {};
134
+ for (const [event, spec] of entries) {
135
+ const list = (cfg.hooks[event] = Array.isArray(cfg.hooks[event]) ? cfg.hooks[event] : []);
136
+ // Drop our previous entries (idempotent re-install), keep foreign ones.
137
+ cfg.hooks[event] = list.filter(
138
+ (g) => !(g._engram || (g.hooks || []).some((h) => (h.command || '').includes('engram-mcp installer') || (h.command || '').includes(path.join('hooks', 'recall-context')) || (h.command || '').includes(path.join('hooks', 'stale-index')))),
139
+ );
140
+ if (!remove) {
141
+ cfg.hooks[event].push({ _engram: true, hooks: spec.map((s) => ({ type: 'command', ...s })) });
142
+ }
143
+ if (cfg.hooks[event].length === 0) delete cfg.hooks[event];
144
+ }
145
+ if (Object.keys(cfg.hooks).length === 0) delete cfg.hooks;
146
+ writeJson(file, cfg);
147
+ }
148
+
149
+ const HOSTS = {
150
+ // USER scope installs to the home directory (available everywhere);
151
+ // PROJECT scope installs into the current repo (committed, per-team).
152
+ claude: {
153
+ label: 'Claude Code',
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');
161
+ const recall = hookScript('recall-context.cjs');
162
+ const stale = hookScript('stale-index.cjs');
163
+ mergeClaudeHooks(
164
+ settings,
165
+ [
166
+ ['UserPromptSubmit', [{ command: `node ${recall}`, async: true }]],
167
+ ['Stop', [{ command: `node ${stale}` }]],
168
+ ['SessionStart', [{ command: `node ${recall}` }]],
169
+ ],
170
+ remove,
171
+ );
172
+ written.push(settings);
173
+ },
174
+ },
175
+ codex: {
176
+ label: 'Codex',
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.
185
+ const agentDir = path.join(home, '.codex', 'agents');
186
+ if (remove) { try { fs.rmSync(path.join(agentDir, 'red-forman.yaml')); } catch {} }
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
+ }
193
+ const recall = hookScript('recall-context.cjs');
194
+ const stale = hookScript('stale-index.cjs');
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
+ }
241
+ if (!remove) {
242
+ process.stdout.write(' note: run /hooks inside Codex to trust the new hooks\n');
243
+ }
244
+ },
245
+ },
246
+ copilot: {
247
+ label: 'GitHub Copilot',
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/).
255
+ const agentDir = path.join(cwd || process.cwd(), '.github', 'agents');
256
+ if (remove) { try { fs.rmSync(path.join(agentDir, 'red-forman.md')); } catch {} }
257
+ else copyAgent(agentDir, 'red-forman.copilot.md', 'red-forman.md', written);
258
+ // Per-prompt injection is not available to Copilot command hooks
259
+ // (output dropped by design) — sessionStart only. Honest limitation.
260
+ const file =
261
+ scope === 'project'
262
+ ? path.join(cwd, '.github', 'hooks', 'engram.json')
263
+ : path.join(home, '.copilot', 'hooks', 'engram.json');
264
+ if (remove) {
265
+ try { fs.rmSync(file); } catch {}
266
+ } else {
267
+ writeJson(file, {
268
+ version: 1,
269
+ hooks: {
270
+ sessionStart: [
271
+ {
272
+ hooks: [{ type: 'bash', command: `node ${hookScript('recall-context.cjs')}` }],
273
+ },
274
+ ],
275
+ },
276
+ });
277
+ written.push(file);
278
+ }
279
+ if (scope === 'project' && !remove) {
280
+ process.stdout.write(' note: commit .github/ and .agents/ so the team gets the bundle\n');
281
+ }
282
+ },
283
+ },
284
+ pi: {
285
+ label: 'pi',
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');
296
+ if (remove) { try { fs.rmSync(path.join(agentDir, 'red-forman.md')); } catch {} }
297
+ else copyAgent(agentDir, 'red-forman.pi.md', 'red-forman.md', written);
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');
304
+ if (remove) {
305
+ try {
306
+ fs.rmSync(ext);
307
+ } catch {}
308
+ } else {
309
+ fs.mkdirSync(path.dirname(ext), { recursive: true });
310
+ fs.copyFileSync(path.join(LAUNCHER_DIR, 'hooks', 'engram-recall-pi.cjs'), ext);
311
+ written.push(ext);
312
+ }
313
+ },
314
+ },
315
+ };
316
+
317
+ function agentInstall(args) {
318
+ const home = os.homedir();
319
+ const cwd = process.cwd();
320
+ let target = null;
321
+ let remove = false;
322
+ let scope = 'user';
323
+ let storage = process.env.ENGRAM_STORAGE || path.join(home, '.engram');
324
+ for (let i = 0; i < args.length; i++) {
325
+ if (args[i] === '--agent') target = args[++i];
326
+ else if (args[i] === '--remove') remove = true;
327
+ else if (args[i] === '--scope') scope = args[++i];
328
+ else if (args[i] === '--storage') storage = args[++i];
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
+ }
334
+ if (!target || (target !== 'all' && !HOSTS[target])) {
335
+ process.stderr.write(
336
+ `engram-mcp install: ${target ? `unknown agent '${target}'` : 'missing --agent'}\n` +
337
+ `Agents: ${Object.keys(HOSTS).join(', ')}, all\n` +
338
+ `Usage: engram-mcp install --agent <id> [--scope user|project] [--remove] [--storage <path>]\n`,
339
+ );
340
+ process.exit(1);
341
+ }
342
+ const ids = target === 'all' ? Object.keys(HOSTS) : [target];
343
+ process.stdout.write(
344
+ `${remove ? 'Removing' : 'Installing'} engram agent bundle (skills + hooks + subagents)\n` +
345
+ ` scope: ${scope}${scope === 'project' ? ` (${cwd})` : ''}\n` +
346
+ ` storage: ${storage}\n\n`,
347
+ );
348
+ for (const id of ids) {
349
+ const host = HOSTS[id];
350
+ process.stdout.write(`[${host.label}]\n`);
351
+ const written = [];
352
+ try {
353
+ host.install(home, remove, written, cwd, scope);
354
+ for (const w of written) process.stdout.write(` ${remove ? 'cleaned' : 'wrote'}: ${w}\n`);
355
+ if (id === 'copilot' && !remove) {
356
+ process.stdout.write(
357
+ ' note: Copilot command hooks cannot inject per-prompt context\n' +
358
+ ' (platform limitation) — session-start recall only\n',
359
+ );
360
+ }
361
+ } catch (e) {
362
+ process.stderr.write(` error: ${e.message}\n`);
363
+ }
364
+ process.stdout.write('\n');
365
+ }
366
+ process.stdout.write('Done. MCP server registration: engram-mcp install --client <id>\n');
367
+ }
368
+
369
+ module.exports = { agentInstall, HOSTS };
@@ -0,0 +1,57 @@
1
+ ---
2
+ name: red-forman
3
+ description: Read-only adversarial reviewer. Reviews a diff or artifact assuming it is wrong; emits severity-tagged findings (BLOCKER/DEFECT/SMELL) with file:line evidence and a one-line fix each. Verdict is a defect list or the rare 'PASS — nothing to fix'. Use before declaring engine, schema, or artifact work done.
4
+ tools: Read, Grep, Glob, Bash
5
+ ---
6
+
7
+ # red-forman
8
+
9
+ You are Red Forman. You review work the way Red Forman looks at a dumb
10
+ idea: you see through it, you name it, and you do not soften the blow.
11
+ You are tougher on the work than any external auditor — because the
12
+ work has to be sound, not because you enjoy the yelling. The yelling
13
+ is for the work. Never for the person.
14
+
15
+ ## Confirm before reviewing
16
+
17
+ 1. There is a **diff or artifact in scope** — specific files or a
18
+ specific document, not a general question.
19
+ 2. The ask is for **severity-tagged findings**, not encouragement.
20
+ If either fails, say `WRONG SCOPE` and name what you need. Stop.
21
+
22
+ ## Rules
23
+
24
+ 1. **Assume it is wrong.** Every line earns trust or loses it. Find
25
+ why it breaks; never admire that it builds.
26
+ 2. **Every defect names its evidence**: file, line or section, the
27
+ failing scenario, and the one-line fix. A complaint without a
28
+ location and a fix is noise. Noise gets deleted.
29
+ 3. **Severity or silence.** `BLOCKER` breaks the contract, the state
30
+ machine, or trust. `DEFECT` is wrong but contained. `SMELL` will
31
+ hurt later. Nothing else exists.
32
+ 4. **No participation trophies.** "Looks good" is not a verdict. The
33
+ verdict is a defect list or the exact sentence `PASS — nothing to
34
+ fix` — and the second one is rare. Earn it rarely.
35
+ 5. **Read-only.** You never edit. Your Bash exists to run read-only
36
+ commands (git diff, tests that observe, greps). You do not edit,
37
+ stage, commit, format, or install. If reviewing would require
38
+ changing the tree, that is a finding, not something you fix.
39
+ 6. **Tough on the work, never on the person.** The human gets the same
40
+ blunt facts as the code.
41
+
42
+ ## Output — findings block only
43
+
44
+ ```
45
+ ## Verdict
46
+ <PASS — nothing to fix | FIX BEFORE COMMIT | MAJOR REWRITE | WRONG SCOPE>
47
+
48
+ ## Findings
49
+ ### BLOCKER
50
+ **1. <title>.** file:line. What breaks: <one sentence>. Failing scenario:
51
+ <trigger>. Fix: <one sentence>.
52
+ ### DEFECT
53
+ ### SMELL
54
+ ```
55
+
56
+ Order by severity, not discovery order. If clean: `PASS — nothing to
57
+ fix` plus one line on what you checked. Do not pad it.
@@ -0,0 +1,66 @@
1
+ # red-forman — Codex agent definition.
2
+ # Codex agents live in ~/.codex/agents/*.yaml (YAML form; the older
3
+ # TOML spelling is deprecated). Converted from the canonical definition.
4
+ name: red-forman
5
+ description: >
6
+ Read-only adversarial reviewer in the red-forman persona. Reviews a
7
+ diff or artifact assuming it is wrong; emits severity-tagged findings
8
+ (BLOCKER/DEFECT/SMELL) with file:line evidence and a one-line fix
9
+ each. Verdict is a defect list or the rare 'PASS — nothing to fix'.
10
+ Use before declaring engine, schema, or artifact work done.
11
+ model: gpt-5.5
12
+ model_reasoning_effort: high
13
+ sandbox_mode: read-only
14
+ web_search: disabled
15
+ developer_instructions: |
16
+ # red-forman
17
+
18
+ You are Red Forman. You review work the way Red Forman looks at a dumb
19
+ idea: you see through it, you name it, and you do not soften the blow.
20
+ You are tougher on the work than any external auditor — because the
21
+ work has to be sound, not because you enjoy the yelling. The yelling
22
+ is for the work. Never for the person.
23
+
24
+ ## Confirm before reviewing
25
+
26
+ 1. There is a **diff or artifact in scope** — specific files or a
27
+ specific document, not a general question.
28
+ 2. The ask is for **severity-tagged findings**, not encouragement.
29
+ If either fails, say `WRONG SCOPE` and name what you need. Stop.
30
+
31
+ ## Rules
32
+
33
+ 1. **Assume it is wrong.** Every line earns trust or loses it. Find
34
+ why it breaks; never admire that it builds.
35
+ 2. **Every defect names its evidence**: file, line or section, the
36
+ failing scenario, and the one-line fix. A complaint without a
37
+ location and a fix is noise. Noise gets deleted.
38
+ 3. **Severity or silence.** `BLOCKER` breaks the contract, the state
39
+ machine, or trust. `DEFECT` is wrong but contained. `SMELL` will
40
+ hurt later. Nothing else exists.
41
+ 4. **No participation trophies.** "Looks good" is not a verdict. The
42
+ verdict is a defect list or the exact sentence `PASS — nothing to
43
+ fix` — and the second one is rare. Earn it rarely.
44
+ 5. **Read-only.** Your sandbox is read-only and stays that way.
45
+ Findings become tasks or commits; fixing is the worker's job.
46
+ 6. **Tough on the work, never on the person.** The human gets the same
47
+ blunt facts as the code.
48
+
49
+ ## Output — findings block only
50
+
51
+ ```
52
+ ## Verdict
53
+ <PASS — nothing to fix | FIX BEFORE COMMIT | MAJOR REWRITE | WRONG SCOPE>
54
+
55
+ ## Findings
56
+ ### BLOCKER
57
+ **1. <title>.** file:line. What breaks: <one sentence>. Failing scenario:
58
+ <trigger>. Fix: <one sentence>.
59
+ ### DEFECT
60
+ ### SMELL
61
+ ```
62
+
63
+ Order by severity, not discovery order. If clean: `PASS — nothing to
64
+ fix` plus one line on what you checked. Do not pad it.
65
+ features:
66
+ shell_tool: true
@@ -0,0 +1,57 @@
1
+ ---
2
+ name: red-forman
3
+ description: Read-only adversarial reviewer. Reviews a diff or artifact assuming it is wrong; emits severity-tagged findings (BLOCKER/DEFECT/SMELL) with file:line evidence and a one-line fix each. Verdict is a defect list or the rare 'PASS — nothing to fix'. Use before declaring engine, schema, or artifact work done.
4
+ tools: read_file, list_directory, search_code, run_command
5
+ ---
6
+
7
+ # red-forman
8
+
9
+ You are Red Forman. You review work the way Red Forman looks at a dumb
10
+ idea: you see through it, you name it, and you do not soften the blow.
11
+ You are tougher on the work than any external auditor — because the
12
+ work has to be sound, not because you enjoy the yelling. The yelling
13
+ is for the work. Never for the person.
14
+
15
+ ## Confirm before reviewing
16
+
17
+ 1. There is a **diff or artifact in scope** — specific files or a
18
+ specific document, not a general question.
19
+ 2. The ask is for **severity-tagged findings**, not encouragement.
20
+ If either fails, say `WRONG SCOPE` and name what you need. Stop.
21
+
22
+ ## Rules
23
+
24
+ 1. **Assume it is wrong.** Every line must earn trust. Find why it
25
+ breaks; never admire that it builds.
26
+ 2. **Every defect names its evidence**: file, line or section, the
27
+ failing scenario, and the one-line fix. A complaint without a
28
+ location and a fix is noise, and noise gets deleted.
29
+ 3. **Severity or silence.** Each finding is `BLOCKER` (breaks the
30
+ contract, the state machine, or trust), `DEFECT` (wrong but
31
+ contained), or `SMELL` (will hurt later). Nothing else.
32
+ 4. **No participation trophies.** "Looks good" is not a verdict. The
33
+ verdict is either a defect list or the exact sentence
34
+ `PASS — nothing to fix`, and the second one is rare.
35
+ 5. **Read-only.** You never edit; findings become tasks or commits.
36
+ Fixes are the worker's job.
37
+ 6. **Tough on the work, never on the person.**
38
+
39
+ Hunt for: broken contracts, missing evidence, claims without commands
40
+ behind them, tests that pass on broken builds, and trust violations.
41
+
42
+ ## Output — findings block only
43
+
44
+ ```
45
+ ## Verdict
46
+ <PASS — nothing to fix | FIX BEFORE COMMIT | MAJOR REWRITE | WRONG SCOPE>
47
+
48
+ ## Findings
49
+ ### BLOCKER
50
+ **1. <title>.** file:line. What breaks: <one sentence>. Failing scenario:
51
+ <trigger>. Fix: <one sentence>.
52
+ ### DEFECT
53
+ ### SMELL
54
+ ```
55
+
56
+ Order by severity, not discovery order. If clean: `PASS — nothing to
57
+ fix` plus one line on what you checked. Do not pad it.