@albinocrabs/feynman 0.2.0 → 0.2.1

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "feynman",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Auto-inject ASCII diagram rules into Codex and Claude Code prompts.",
5
5
  "author": {
6
6
  "name": "apolenkov",
package/CHANGELOG.md ADDED
@@ -0,0 +1,12 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+
5
+ ## 0.2.1 - 2026-05-07
6
+
7
+ Changes since v0.2.0.
8
+
9
+ ### Maintenance
10
+
11
+ - add open-source automation
12
+
@@ -0,0 +1,126 @@
1
+ # Contributing to feynman
2
+
3
+ Contributions welcome. This guide covers setup, what to work on, and
4
+ how to get a PR merged.
5
+
6
+ ---
7
+
8
+ ## Quick Start
9
+
10
+ ```bash
11
+ git clone https://github.com/apolenkov/feynman
12
+ cd feynman
13
+ npm install
14
+ npm test
15
+ ```
16
+
17
+ Tests use Node's built-in `node:test` runner — no external test framework
18
+ needed.
19
+
20
+ Lint the codebase: `node bin/feynman-lint.js README.md docs/*.md examples/*.md`
21
+
22
+ ---
23
+
24
+ ## What Makes a Good First PR
25
+
26
+ These are well-scoped and require no architectural decisions:
27
+
28
+ - **Add a lint-rule test case** — add a row to `tests/lint-cases.json` for
29
+ an edge case that's currently untested.
30
+ - **Improve an example** — add or improve a file in `examples/` following
31
+ the schema in `docs/architecture.md` and `06-CONTEXT.md`.
32
+ - **Expand `feynman doctor`** — add a new health check to `bin/feynman.js`
33
+ `cmdDoctor()`.
34
+ - **Fix a typo or improve prose** — in `README.md`, `docs/`, or `CONTRIBUTING.md`.
35
+ - **Add a rule to `rules/feynman-activate.md`** — follow the rules-authoring
36
+ guidelines below.
37
+
38
+ ---
39
+
40
+ ## PR Checklist
41
+
42
+ Before opening a pull request:
43
+
44
+ - [ ] `npm test` passes (all existing tests green)
45
+ - [ ] New behavior has a test in `tests/` covering the change
46
+ - [ ] No new lint warnings: `node bin/feynman-lint.js <changed files>`
47
+ - [ ] `README.md` updated if a user-facing feature changed
48
+ - [ ] Commit message follows the format: `type(scope): description`
49
+ (types: `feat`, `fix`, `test`, `docs`, `refactor`, `chore`)
50
+
51
+ ---
52
+
53
+ ## Rules Authoring Guidelines
54
+
55
+ The hook injects `rules/feynman-activate.md` into every Claude prompt.
56
+ The rules must be declarative facts, not commands.
57
+
58
+ **Good (declarative):**
59
+ > "A response describing a sequence of steps includes an ASCII flow diagram."
60
+
61
+ **Bad (imperative):**
62
+ > "Always draw a flow diagram when you see steps."
63
+
64
+ Imperative phrasing triggers Claude's prompt-injection defense
65
+ ([bug #17804](https://github.com/anthropics/claude-code/issues/17804)) and
66
+ may be filtered or reinterpreted.
67
+
68
+ Each intensity variant must stay under 8,000 characters. Measure with:
69
+
70
+ ```bash
71
+ node -e "
72
+ const f = require('fs').readFileSync('rules/feynman-activate.md', 'utf8');
73
+ ['lite','full','ultra'].forEach(v => {
74
+ const s = f.indexOf('<!-- ' + v + ' -->');
75
+ const e = f.indexOf('<!-- /' + v + ' -->', s);
76
+ console.log(v, f.slice(s, e + ('<!-- /' + v + ' -->').length).length, 'chars');
77
+ });
78
+ "
79
+ ```
80
+
81
+ ---
82
+
83
+ ## Issue Triage
84
+
85
+ **Labels:**
86
+
87
+ | label | when to use |
88
+ |------------------|--------------------------------------------------|
89
+ | `bug` | something works differently than documented |
90
+ | `feature` | new capability request |
91
+ | `docs` | documentation gap or error |
92
+ | `good-first-issue` | well-scoped, no architecture decisions needed |
93
+
94
+ **Expected response time:** best-effort, typically within a week for bugs.
95
+ Feature requests may be deferred to a milestone.
96
+
97
+ ---
98
+
99
+ ## Governance
100
+
101
+ - Single maintainer: [apolenkov](https://github.com/apolenkov)
102
+ - License: MIT — see `LICENSE`
103
+ - Public roadmap: `.planning/ROADMAP.md` (check before proposing big features)
104
+ - No DCO or CLA sign-off required — low barrier to contribution is intentional
105
+
106
+ ---
107
+
108
+ ## Testing
109
+
110
+ ```bash
111
+ npm test # run all tests
112
+ npm test -- --grep L01 # filter by test name pattern
113
+ ```
114
+
115
+ Coverage report: `npm run coverage` (writes to `coverage/`)
116
+
117
+ Tests are in `tests/` using `node:test` and `node:assert`. Lint golden
118
+ cases are in `tests/lint-cases.json`.
119
+
120
+ ---
121
+
122
+ ## Architecture
123
+
124
+ See [`docs/architecture.md`](docs/architecture.md) for the hook lifecycle,
125
+ lint pipeline, and state schema before making changes to `hooks/`,
126
+ `lib/lint/`, or `bin/`.
package/README.md CHANGED
@@ -24,6 +24,7 @@
24
24
  <a href="#intensity-levels">Levels</a> •
25
25
  <a href="#lint">Lint</a> •
26
26
  <a href="#examples">Examples</a> •
27
+ <a href="docs/launch.md">Launch</a> •
27
28
  <a href="CONTRIBUTING.md">Contributing</a>
28
29
  </p>
29
30
 
@@ -33,7 +34,10 @@ A [Claude Code](https://docs.anthropic.com/en/docs/claude-code) and Codex
33
34
  plugin that automatically injects ASCII diagram rules into every prompt via the
34
35
  `UserPromptSubmit` hook.
35
36
 
36
- <!-- TODO: GIF after v0.3.0 visual capture -->
37
+ ```bash
38
+ npx -y @albinocrabs/feynman@latest install --target both
39
+ npx -y @albinocrabs/feynman@latest doctor --target codex
40
+ ```
37
41
 
38
42
  ## Why feynman
39
43
 
@@ -262,10 +266,11 @@ Domain-specific examples showing feynman in practice:
262
266
 
263
267
  ## How it works
264
268
 
265
- The `UserPromptSubmit` hook fires on every Claude prompt. The hook reads
266
- `~/.claude/.feynman/state.json`, extracts the rules for the active intensity
269
+ The `UserPromptSubmit` hook fires on every Claude Code or Codex prompt. The
270
+ hook reads the target-local state file (`~/.claude/.feynman/state.json` or
271
+ `~/.codex/.feynman/state.json`), extracts the rules for the active intensity
267
272
  level, and injects them as `additionalContext` — invisible to you, visible to
268
- Claude on every message.
273
+ the model on every message.
269
274
 
270
275
  ```
271
276
  [your prompt]
@@ -279,6 +284,19 @@ Claude on every message.
279
284
  [structured response with ASCII diagrams]
280
285
  ```
281
286
 
287
+ ## Release process
288
+
289
+ Every push runs tests on Node 18 and 20 across Ubuntu and macOS. The release
290
+ lane also lints public docs, smoke-tests the packed npm tarball, builds a
291
+ `dist/*.tgz` artifact, and can publish to npm from a GitHub Release when
292
+ `NPM_TOKEN` is configured.
293
+
294
+ ```bash
295
+ npm run ci
296
+ npm run changelog
297
+ npm run build
298
+ ```
299
+
282
300
  State is stored at `~/.claude/.feynman/state.json`. First run bootstraps
283
301
  automatically. See [docs/architecture.md](docs/architecture.md) for internals.
284
302
 
package/SECURITY.md ADDED
@@ -0,0 +1,31 @@
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+
5
+ Security fixes are shipped for the latest published npm version.
6
+
7
+ ## Reporting a Vulnerability
8
+
9
+ Please report security issues privately by opening a GitHub security advisory:
10
+
11
+ https://github.com/apolenkov/feynman/security/advisories/new
12
+
13
+ Do not file public issues for vulnerabilities. Include:
14
+
15
+ - affected version
16
+ - reproduction steps
17
+ - expected impact
18
+ - suggested fix, if known
19
+
20
+ We aim to acknowledge reports within 72 hours.
21
+
22
+ ## Scope
23
+
24
+ feynman is a local hook package. The main security-sensitive surfaces are:
25
+
26
+ - hook command registration in `~/.claude/settings.json`
27
+ - hook command registration in `~/.codex/hooks.json`
28
+ - file reads from the installed package directory
29
+ - state files under `~/.claude/.feynman/` and `~/.codex/.feynman/`
30
+
31
+ The package has zero runtime npm dependencies.
package/bin/feynman.js CHANGED
@@ -98,10 +98,10 @@ ${c.bold('Options:')}
98
98
  --force (install) Re-register even if already installed
99
99
 
100
100
  ${c.bold('Examples:')}
101
- npx feynman install
102
- npx feynman install --target codex
103
- npx feynman install --target both
104
- npx feynman doctor
101
+ npx @albinocrabs/feynman install
102
+ npx @albinocrabs/feynman install --target codex
103
+ npx @albinocrabs/feynman install --target both
104
+ npx @albinocrabs/feynman doctor
105
105
  feynman lint response.md
106
106
  feynman uninstall
107
107
  `;
@@ -351,7 +351,7 @@ function cmdUninstall(opts) {
351
351
  if (results.every(r => r.missing || !r.hadHook)) {
352
352
  console.log(`feynman: no hook found for ${labels} — nothing to uninstall.`);
353
353
  } else {
354
- console.log(`feynman disabled for ${labels}. State preserved. Re-enable: npx feynman install --target ${opts.target}`);
354
+ console.log(`feynman disabled for ${labels}. State preserved. Re-enable: npx @albinocrabs/feynman install --target ${opts.target}`);
355
355
  }
356
356
  process.exit(0);
357
357
  }
@@ -0,0 +1,190 @@
1
+ # feynman Architecture
2
+
3
+ Three independent layers: hook lifecycle, lint pipeline, and state schema.
4
+
5
+ ---
6
+
7
+ ## Layer 1: Hook Lifecycle
8
+
9
+ The `UserPromptSubmit` hook fires before every Claude Code or Codex prompt.
10
+ feynman intercepts the event, reads the active rules, and injects them as
11
+ `additionalContext`.
12
+
13
+ ```
14
+ ~/.claude/settings.json ~/.codex/hooks.json
15
+
16
+ │ hooks.UserPromptSubmit fires on every prompt
17
+
18
+ hooks/feynman-activate.js
19
+
20
+ ├─ [0] FEYNMAN_HOME selects client state root
21
+ │ unset → ~/.claude (backward compatible)
22
+ │ ~/.claude → Claude Code install
23
+ │ ~/.codex → Codex install
24
+
25
+ ├─ [1] validate session_id (path-traversal guard)
26
+
27
+ ├─ [2] $FEYNMAN_HOME/.feynman-active ← flag file
28
+ │ absent + no state.json → bootstrap first run
29
+ │ absent + state.json → exit 0 (user disabled)
30
+ │ present → continue
31
+
32
+ ├─ [3] $FEYNMAN_HOME/.feynman/state.json
33
+ │ enabled: false → exit 0
34
+ │ corrupt JSON → exit 0 (fail safe)
35
+
36
+ ├─ [4] rules/feynman-activate.md
37
+ │ extract section for state.intensity
38
+ │ (lite | full | ultra)
39
+
40
+ ├─ [5] state.injections++ (write back)
41
+
42
+ └─ [6] stdout: JSON additionalContext → injected into prompt
43
+ {hookSpecificOutput: {hookEventName: 'UserPromptSubmit',
44
+ additionalContext: <rules text>}}
45
+ ```
46
+
47
+ **Key constraints:**
48
+
49
+ - Output must be JSON with no trailing newline — plain stdout triggers
50
+ Claude Code's red error banner (bug #13912).
51
+ - Paths use `os.homedir()`, never tilde literals (bug #8810).
52
+ - Production install writes user hook config directly:
53
+ `~/.claude/settings.json` for Claude Code and `~/.codex/hooks.json` for
54
+ Codex. Plugin manifests are shipped for discoverability, but direct hook
55
+ registration remains the reliable fallback.
56
+ - Flag file checked before state file to detect intentional disabling
57
+ vs. first run (bug #35713).
58
+
59
+ **File:** `hooks/feynman-activate.js`
60
+
61
+ ---
62
+
63
+ ## Layer 2: Lint Pipeline
64
+
65
+ The lint pipeline validates ASCII diagram correctness in markdown files.
66
+ It runs as a CLI tool and as an optional `Stop` hook.
67
+
68
+ ```
69
+ <file.md> or stdin
70
+
71
+
72
+ lib/lint/parser.js
73
+ │ parseMarkdown(text) → ASTNode[]
74
+ │ each node: {type, content, startLine, endLine}
75
+ │ types: fenced_code, ascii_art (freestanding)
76
+
77
+
78
+ lib/lint/rules.js
79
+ │ runs each rule against each AST node:
80
+
81
+ ├─ L01_box_closure(ast)
82
+ ├─ L02_tree_chars(ast)
83
+ ├─ L03_arrow_style(ast)
84
+ ├─ L04_column_widths(ast)
85
+ ├─ L05_flow_integrity(ast)
86
+ ├─ L06_priority_scale(ast)
87
+ ├─ L07_no_mermaid_mix(ast, fullText)
88
+ └─ L08_frame_width(ast)
89
+
90
+ │ each rule returns Issue[]:
91
+ │ {rule, severity, line, column, message, suggestion?}
92
+
93
+
94
+ reporter (inline in CLI + Stop hook)
95
+
96
+ ├─ bin/feynman-lint.js ← standalone CLI
97
+ │ feynman lint <file>
98
+ │ exit 0: no errors
99
+ │ exit 1: errors found
100
+ │ exit 2: usage error
101
+ │ --json: machine-readable output
102
+ │ --strict: warnings treated as errors
103
+
104
+ └─ hooks/feynman-lint.js ← Stop hook (optional)
105
+ fires after Claude's response
106
+ if issues found: injects correction context
107
+ into next UserPromptSubmit cycle
108
+ ```
109
+
110
+ **File:** `lib/lint/parser.js`, `lib/lint/rules.js`, `bin/feynman-lint.js`,
111
+ `hooks/feynman-lint.js`
112
+
113
+ ---
114
+
115
+ ## Layer 3: State Schema
116
+
117
+ All runtime state lives in two files under the selected client root:
118
+ `~/.claude/` for Claude Code, `~/.codex/` for Codex.
119
+
120
+ ```
121
+ ~/.claude/ or ~/.codex/
122
+ ├── .feynman-active ← presence flag
123
+ │ present = feynman active
124
+ │ absent = user disabled (state.json preserved)
125
+ │ content = current intensity string (informational)
126
+
127
+ └── .feynman/
128
+ └── state.json ← runtime state
129
+ {
130
+ "enabled": boolean, // true = inject rules on each prompt
131
+ "intensity": string, // "lite" | "full" | "ultra"
132
+ "injections": number // cumulative hook fire count
133
+ }
134
+ ```
135
+
136
+ **State transitions:**
137
+
138
+ ```
139
+ [first run]
140
+ both files absent → bootstrap
141
+ writes state.json {enabled:true, intensity:'full', injections:0}
142
+ writes .feynman-active with intensity string
143
+
144
+ [/feynman off]
145
+ state.enabled = false
146
+ .feynman-active deleted
147
+
148
+ [/feynman on]
149
+ state.enabled = true
150
+ .feynman-active created
151
+
152
+ [/feynman lite | full | ultra]
153
+ state.intensity = <value>
154
+ .feynman-active content updated
155
+
156
+ [npx @albinocrabs/feynman uninstall --target claude|codex|both]
157
+ hook removed from target hook config
158
+ .feynman-active deleted
159
+ state.json preserved (user data)
160
+ ```
161
+
162
+ **Schema is frozen** — field names are used by `hooks/feynman-activate.js`,
163
+ `bin/feynman.js`, and `skills/feynman/SKILL.md`. Any rename requires
164
+ coordinated update across all three files.
165
+
166
+ **File:** read/written by `hooks/feynman-activate.js` and `bin/feynman.js`;
167
+ managed by skill commands in `skills/feynman/SKILL.md`.
168
+
169
+ ---
170
+
171
+ ## CLI Subcommand Map
172
+
173
+ ```
174
+ bin/feynman.js
175
+ ├── install → writes target hook config + state.json + flag
176
+ ├── uninstall → removes target hook entries + flag (keeps state)
177
+ ├── doctor → checks target health criteria, prints frame
178
+ ├── lint → delegates to bin/feynman-lint.js
179
+ └── version → prints package.json version
180
+ ```
181
+
182
+ Targets:
183
+
184
+ ```
185
+ claude → ~/.claude/settings.json + ~/.claude/.feynman/
186
+ codex → ~/.codex/hooks.json + ~/.codex/.feynman/
187
+ both → runs claude and codex installers idempotently
188
+ ```
189
+
190
+ **File:** `bin/feynman.js`
package/docs/launch.md ADDED
@@ -0,0 +1,67 @@
1
+ # Launch Notes
2
+
3
+ ## Positioning
4
+
5
+ feynman is a Claude Code and Codex plugin that makes structured answers
6
+ visible by default. Flows become arrows, hierarchies become trees, comparisons
7
+ become columns, priorities become scales, and status summaries become frames.
8
+
9
+ ## One-liner
10
+
11
+ ```bash
12
+ npx -y @albinocrabs/feynman@latest install --target both
13
+ ```
14
+
15
+ ## Short Description
16
+
17
+ feynman automatically injects ASCII diagram rules into Claude Code and Codex
18
+ prompts, so structured answers render as readable terminal-native diagrams
19
+ without asking every time.
20
+
21
+ ## Benefits
22
+
23
+ - No runtime dependencies
24
+ - Works with Claude Code and Codex
25
+ - Installs with `npx`
26
+ - Keeps state local under `~/.claude` or `~/.codex`
27
+ - Ships a diagram linter for public docs and generated responses
28
+ - Uses plain ASCII/Unicode text, not external renderers
29
+
30
+ ## Demo Script
31
+
32
+ ```bash
33
+ npx -y @albinocrabs/feynman@latest install --target both
34
+ npx -y @albinocrabs/feynman@latest doctor --target claude
35
+ npx -y @albinocrabs/feynman@latest doctor --target codex
36
+ ```
37
+
38
+ Prompt:
39
+
40
+ ```text
41
+ Compare SQLite, Postgres, and Redis for a local-first prototype.
42
+ ```
43
+
44
+ Expected shape:
45
+
46
+ ```text
47
+ SQLite | Postgres | Redis
48
+ -----------------|------------------|----------------
49
+ single-file | server database | memory-first
50
+ easy local setup | richer SQL | fast cache
51
+ limited writes | production-ready | persistence opt
52
+ ```
53
+
54
+ ## Release Checklist
55
+
56
+ - `npm run ci`
57
+ - GitHub Actions CI green
58
+ - `npm run changelog`
59
+ - `npm run build`
60
+ - `npm publish --dry-run --access public`
61
+ - GitHub Release created from changelog notes
62
+ - npm package visible at `@albinocrabs/feynman@latest`
63
+ - Smoke test from clean directory:
64
+
65
+ ```bash
66
+ npx -y @albinocrabs/feynman@latest version
67
+ ```