@albinocrabs/feynman 0.2.0

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.
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "feynman",
3
+ "version": "0.2.0",
4
+ "description": "Auto-inject ASCII diagram rules into Codex and Claude Code prompts.",
5
+ "author": {
6
+ "name": "apolenkov",
7
+ "url": "https://github.com/apolenkov/feynman"
8
+ },
9
+ "homepage": "https://github.com/apolenkov/feynman",
10
+ "repository": "https://github.com/apolenkov/feynman",
11
+ "license": "MIT",
12
+ "keywords": [
13
+ "codex",
14
+ "claude-code",
15
+ "ascii",
16
+ "diagrams",
17
+ "hooks",
18
+ "productivity"
19
+ ],
20
+ "hooks": "./hooks.json",
21
+ "skills": "./skills/",
22
+ "interface": {
23
+ "displayName": "feynman",
24
+ "shortDescription": "Draw ASCII diagrams when structure appears.",
25
+ "longDescription": "feynman injects concise diagram rules on every prompt so flows, hierarchies, comparisons, priorities, and status summaries render as readable ASCII diagrams.",
26
+ "developerName": "apolenkov",
27
+ "category": "Productivity",
28
+ "capabilities": [
29
+ "Interactive",
30
+ "Write"
31
+ ],
32
+ "websiteURL": "https://github.com/apolenkov/feynman",
33
+ "privacyPolicyURL": "https://github.com/apolenkov/feynman/blob/main/README.md",
34
+ "termsOfServiceURL": "https://github.com/apolenkov/feynman/blob/main/LICENSE",
35
+ "defaultPrompt": [
36
+ "Use feynman diagrams for structured answers.",
37
+ "Explain this architecture visually.",
38
+ "Compare these options with ASCII columns."
39
+ ],
40
+ "brandColor": "#10B981",
41
+ "screenshots": []
42
+ }
43
+ }
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 apolenkov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,292 @@
1
+ <p align="center">
2
+ <img src="https://em-content.zobj.net/source/apple/391/pencil_270f-fe0f.png" width="120" />
3
+ </p>
4
+
5
+ <h1 align="center">feynman</h1>
6
+
7
+ <p align="center">
8
+ <strong>why explain in words when diagram do trick</strong>
9
+ </p>
10
+
11
+ <p align="center">
12
+ <a href="https://www.npmjs.com/package/@albinocrabs/feynman"><img src="https://img.shields.io/npm/v/@albinocrabs/feynman?style=flat&color=blue" alt="npm version"></a>
13
+ <a href="https://github.com/apolenkov/feynman/actions/workflows/ci.yml"><img src="https://github.com/apolenkov/feynman/workflows/CI/badge.svg" alt="CI"></a>
14
+ <a href="https://github.com/apolenkov/feynman/blob/main/.github/coverage-badge.json"><img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/apolenkov/feynman/main/.github/coverage-badge.json" alt="Coverage"></a>
15
+ <a href="LICENSE"><img src="https://img.shields.io/github/license/apolenkov/feynman?style=flat" alt="License"></a>
16
+ <a href="https://github.com/apolenkov/feynman/stargazers"><img src="https://img.shields.io/github/stars/apolenkov/feynman?style=flat&color=yellow" alt="Stars"></a>
17
+ <a href="https://github.com/apolenkov/feynman/commits/main"><img src="https://img.shields.io/github/last-commit/apolenkov/feynman?style=flat" alt="Last Commit"></a>
18
+ </p>
19
+
20
+ <p align="center">
21
+ <a href="#why-feynman">Why</a> •
22
+ <a href="#before--after">Before/After</a> •
23
+ <a href="#install">Install</a> •
24
+ <a href="#intensity-levels">Levels</a> •
25
+ <a href="#lint">Lint</a> •
26
+ <a href="#examples">Examples</a> •
27
+ <a href="CONTRIBUTING.md">Contributing</a>
28
+ </p>
29
+
30
+ ---
31
+
32
+ A [Claude Code](https://docs.anthropic.com/en/docs/claude-code) and Codex
33
+ plugin that automatically injects ASCII diagram rules into every prompt via the
34
+ `UserPromptSubmit` hook.
35
+
36
+ <!-- TODO: GIF after v0.3.0 visual capture -->
37
+
38
+ ## Why feynman
39
+
40
+ Structured information explained in prose forces you to rebuild the structure
41
+ in your head before you can reason about it. feynman intercepts every Claude
42
+ Code or Codex prompt and injects rules that turn flows into arrows,
43
+ hierarchies into trees, comparisons into columns, and status into frames. The
44
+ structure is visible before you have to think about it.
45
+
46
+ ## Before / After
47
+
48
+ <table>
49
+ <tr>
50
+ <td width="50%">
51
+
52
+ ### Without feynman
53
+
54
+ > "The deployment pipeline has three stages: first the code is built, then tests run, then it deploys to prod."
55
+
56
+ </td>
57
+ <td width="50%">
58
+
59
+ ### With feynman
60
+
61
+ ```
62
+ [Build] --> [Test] --> [Deploy]
63
+ ```
64
+
65
+ </td>
66
+ </tr>
67
+ <tr>
68
+ <td>
69
+
70
+ ### Without feynman
71
+
72
+ > "Option A is fast but stateless. Option B is slower but persists data. Option C gives you both at higher cost."
73
+
74
+ </td>
75
+ <td>
76
+
77
+ ### With feynman
78
+
79
+ ```
80
+ Option A | Option B | Option C
81
+ ---------------|---------------|----------
82
+ fast startup | slow startup | medium
83
+ stateless | persistent | persistent
84
+ free | free | $$$
85
+ ```
86
+
87
+ </td>
88
+ </tr>
89
+ <tr>
90
+ <td>
91
+
92
+ ### Without feynman
93
+
94
+ > "Fix the auth bug first since it's a security issue, then the memory leak, then the slow query."
95
+
96
+ </td>
97
+ <td>
98
+
99
+ ### With feynman
100
+
101
+ ```
102
+ ▲ high
103
+ auth bug (security)
104
+ memory leak
105
+ ▼ low
106
+ slow query
107
+ ```
108
+
109
+ </td>
110
+ </tr>
111
+ <tr>
112
+ <td>
113
+
114
+ ### Without feynman
115
+
116
+ > "The auth service talks to Redis for rate limiting and Postgres for user data."
117
+
118
+ </td>
119
+ <td>
120
+
121
+ ### With feynman
122
+
123
+ ```
124
+ [Auth Service]
125
+ ├── [Redis] rate limiter
126
+ └── [Postgres] user data
127
+ ```
128
+
129
+ </td>
130
+ </tr>
131
+ </table>
132
+
133
+ ## Install
134
+
135
+ **Claude Code via npx:**
136
+
137
+ ```bash
138
+ npx @albinocrabs/feynman install --target claude
139
+ ```
140
+
141
+ **Codex via npx:**
142
+
143
+ ```bash
144
+ npx @albinocrabs/feynman install --target codex
145
+ ```
146
+
147
+ **Both clients:**
148
+
149
+ ```bash
150
+ npx @albinocrabs/feynman install --target both
151
+ ```
152
+
153
+ The install command is idempotent: running it again updates the existing
154
+ feynman hook instead of adding duplicates.
155
+
156
+ **Claude Code via bash one-liner:**
157
+
158
+ ```bash
159
+ git clone https://github.com/apolenkov/feynman && bash feynman/install.sh
160
+ ```
161
+
162
+ Restart Claude Code or Codex. Done.
163
+
164
+ **Verify:** `npx @albinocrabs/feynman doctor --target claude` or `npx @albinocrabs/feynman doctor --target codex`
165
+
166
+ **Uninstall:** `npx @albinocrabs/feynman uninstall --target claude|codex|both`
167
+
168
+ **Plugin manifests:** this repo also ships `.claude-plugin/plugin.json`,
169
+ `hooks/hooks.json`, `.codex-plugin/plugin.json`, and `hooks.json` so plugin
170
+ marketplaces can discover feynman. The npx installer remains the production
171
+ fallback because both clients still support direct user hook registration.
172
+
173
+ <details>
174
+ <summary>Manual install</summary>
175
+
176
+ Add to `~/.claude/settings.json` — use the absolute path, not `~/`
177
+ ([bug #8810](https://github.com/anthropics/claude-code/issues/8810)):
178
+
179
+ ```json
180
+ {
181
+ "hooks": {
182
+ "UserPromptSubmit": [
183
+ {
184
+ "hooks": [
185
+ {
186
+ "type": "command",
187
+ "command": "node \"/absolute/path/to/feynman/hooks/feynman-activate.js\"",
188
+ "timeout": 5,
189
+ "statusMessage": "Injecting diagram rules..."
190
+ }
191
+ ]
192
+ }
193
+ ]
194
+ }
195
+ }
196
+ ```
197
+
198
+ For Codex, add the same shape to `~/.codex/hooks.json` and set
199
+ `FEYNMAN_HOME` so state lives under `~/.codex`:
200
+
201
+ ```json
202
+ {
203
+ "hooks": {
204
+ "UserPromptSubmit": [
205
+ {
206
+ "hooks": [
207
+ {
208
+ "type": "command",
209
+ "command": "FEYNMAN_HOME=\"$HOME/.codex\" node \"/absolute/path/to/feynman/hooks/feynman-activate.js\"",
210
+ "timeout": 5,
211
+ "statusMessage": "Injecting diagram rules..."
212
+ }
213
+ ]
214
+ }
215
+ ]
216
+ }
217
+ }
218
+ ```
219
+ </details>
220
+
221
+ ## Intensity Levels
222
+
223
+ | Level | What draws | Use when |
224
+ |-------|-----------|----------|
225
+ | **lite** | Flows + trees only | Minimal, subtle |
226
+ | **full** | All 5 diagram types (default) | Normal use |
227
+ | **ultra** | Force diagram even for short answers | Maximum visual structure |
228
+
229
+ Toggle via `/feynman`:
230
+
231
+ ```
232
+ /feynman lite — flows and trees only
233
+ /feynman full — all diagram types
234
+ /feynman ultra — force diagrams always
235
+ /feynman off — disable
236
+ /feynman on — re-enable
237
+ /feynman status — show current state
238
+ ```
239
+
240
+ ## Lint
241
+
242
+ feynman includes a linter for ASCII diagrams. It catches structural errors
243
+ before they reach readers: unclosed boxes, wrong tree characters, mixed arrow
244
+ styles, inconsistent column counts, and more.
245
+
246
+ ```bash
247
+ npx @albinocrabs/feynman lint response.md
248
+ ```
249
+
250
+ See [docs/lint-rules.md](docs/lint-rules.md) for the full L01-L08 reference.
251
+
252
+ ## Examples
253
+
254
+ Domain-specific examples showing feynman in practice:
255
+
256
+ - [Architecture review](examples/architecture-review.md) — auth service topology
257
+ - [API flow](examples/api-flow.md) — POST /api/login request lifecycle
258
+ - [Database schema](examples/db-schema.md) — e-commerce entity model
259
+ - [Algorithm walkthrough](examples/algorithm-explain.md) — token-bucket rate limiter
260
+ - [Deploy pipeline](examples/deploy-pipeline.md) — monorepo CI/CD
261
+ - [Code review](examples/code-review.md) — priority + comparison diagrams
262
+
263
+ ## How it works
264
+
265
+ The `UserPromptSubmit` hook fires on every Claude prompt. The hook reads
266
+ `~/.claude/.feynman/state.json`, extracts the rules for the active intensity
267
+ level, and injects them as `additionalContext` — invisible to you, visible to
268
+ Claude on every message.
269
+
270
+ ```
271
+ [your prompt]
272
+ +
273
+ [feynman rules] ← injected by hook, ~2KB
274
+
275
+
276
+ [Claude]
277
+
278
+
279
+ [structured response with ASCII diagrams]
280
+ ```
281
+
282
+ State is stored at `~/.claude/.feynman/state.json`. First run bootstraps
283
+ automatically. See [docs/architecture.md](docs/architecture.md) for internals.
284
+
285
+ ## Contributing
286
+
287
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for setup, PR checklist, and
288
+ rules-authoring guidelines.
289
+
290
+ ## License
291
+
292
+ MIT
@@ -0,0 +1,123 @@
1
+ #!/usr/bin/env node
2
+ // bin/feynman-lint.js — feynman diagram linter CLI
3
+ // Usage: feynman-lint <file.md>
4
+ // feynman-lint - (stdin)
5
+ // feynman-lint --json <file>
6
+ // feynman-lint --strict <file>
7
+ // feynman-lint --help
8
+ // Exit codes: 0 = pass, 1 = lint failure, 2 = usage error
9
+ // Zero deps. CJS only.
10
+ 'use strict';
11
+
12
+ const fs = require('fs');
13
+ const path = require('path');
14
+ const { lint, format } = require('../lib/lint');
15
+
16
+ const USAGE = `Usage: feynman-lint <file.md>
17
+ feynman-lint - (read from stdin)
18
+ feynman-lint --json <file>
19
+ feynman-lint --strict <file>
20
+ feynman-lint --help
21
+
22
+ Options:
23
+ --json Output issues as JSON object
24
+ --strict Treat warnings as errors (exit 1 on any issue)
25
+ --help Show this help message
26
+
27
+ Exit codes:
28
+ 0 No errors (or no issues in default mode)
29
+ 1 Lint failure (errors found, or warnings in --strict mode)
30
+ 2 Usage error (bad arguments, file not found)
31
+ `;
32
+
33
+ // Parse arguments
34
+ const argv = process.argv.slice(2);
35
+ let useJson = false;
36
+ let useStrict = false;
37
+ let filePath = null;
38
+ let useStdin = false;
39
+
40
+ for (const arg of argv) {
41
+ if (arg === '--json') { useJson = true; continue; }
42
+ if (arg === '--strict') { useStrict = true; continue; }
43
+ if (arg === '--help') { process.stdout.write(USAGE); process.exit(0); }
44
+ if (arg === '-') { useStdin = true; continue; }
45
+ if (arg.startsWith('-') && arg !== '-') {
46
+ process.stderr.write(`feynman-lint: unknown flag '${arg}'\n${USAGE}`);
47
+ process.exit(2);
48
+ }
49
+ if (filePath) {
50
+ process.stderr.write(`feynman-lint: too many file arguments\n${USAGE}`);
51
+ process.exit(2);
52
+ }
53
+ filePath = arg;
54
+ }
55
+
56
+ if (!filePath && !useStdin) {
57
+ process.stderr.write(USAGE);
58
+ process.exit(2);
59
+ }
60
+
61
+ function run(markdown, displayName) {
62
+ const result = lint(markdown);
63
+ const { issues } = result;
64
+
65
+ if (useJson) {
66
+ const out = {
67
+ file: displayName,
68
+ passed: useStrict ? issues.length === 0 : result.passed,
69
+ issues,
70
+ };
71
+ process.stdout.write(JSON.stringify(out, null, 2) + '\n');
72
+ const failed = useStrict ? issues.length > 0 : !result.passed;
73
+ process.exit(failed ? 1 : 0);
74
+ }
75
+
76
+ // gcc mode
77
+ const isTTY = process.stdout.isTTY;
78
+ const output = format(issues, 'gcc', displayName, isTTY);
79
+
80
+ if (output) {
81
+ process.stdout.write(output + '\n');
82
+ }
83
+
84
+ // Determine pass/fail
85
+ const failed = useStrict
86
+ ? issues.length > 0
87
+ : !result.passed;
88
+
89
+ if (failed) {
90
+ const errCount = issues.filter(i => i.severity === 'error').length;
91
+ const warnCount = issues.filter(i => i.severity === 'warn').length;
92
+ const parts = [];
93
+ if (errCount) parts.push(`${errCount} error${errCount !== 1 ? 's' : ''}`);
94
+ if (warnCount) parts.push(`${warnCount} warning${warnCount !== 1 ? 's' : ''}`);
95
+ process.stderr.write(`${displayName}: ${parts.join(', ')}\n`);
96
+ process.exit(1);
97
+ } else {
98
+ process.exit(0);
99
+ }
100
+ }
101
+
102
+ // Read input
103
+ if (useStdin) {
104
+ let buf = '';
105
+ process.stdin.setEncoding('utf8');
106
+ process.stdin.on('data', chunk => { buf += chunk; });
107
+ process.stdin.on('end', () => run(buf, '<stdin>'));
108
+ } else {
109
+ // File mode
110
+ const absPath = path.resolve(filePath);
111
+ if (!fs.existsSync(absPath)) {
112
+ process.stderr.write(`feynman-lint: file not found: ${filePath}\n`);
113
+ process.exit(2);
114
+ }
115
+ let markdown;
116
+ try {
117
+ markdown = fs.readFileSync(absPath, 'utf8');
118
+ } catch (e) {
119
+ process.stderr.write(`feynman-lint: cannot read file: ${filePath}: ${e.message}\n`);
120
+ process.exit(2);
121
+ }
122
+ run(markdown, filePath);
123
+ }