@davesheffer/hunch 0.1.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Dave Sheffer
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,241 @@
1
+ # 🧠 Hunch β€” Engineering Memory OS
2
+
3
+ > Git stores *what* the code is. **Hunch** stores ***why*** it is that way β€” a persistent,
4
+ > git-native reasoning graph over your codebase, surfaced to Claude Code at reasoning time
5
+ > so the AI stops re-deriving understanding and stops undoing intentional design.
6
+
7
+ ## The problem
8
+
9
+ Every AI coding session starts from zero. The model re-reads your code, re-guesses the
10
+ intent, and happily "fixes" the thing you deliberately did last month β€” because the
11
+ *reasoning* behind the code lives in PRs, Slack, and people's heads, not in the repo.
12
+
13
+ **Hunch** captures that reasoning as a **byproduct of normal work** β€” commits and test
14
+ failures β€” stores it as a git-tracked graph next to your code, and feeds it back to
15
+ Claude Code so every session is grounded in the decisions, bugs, and invariants that
16
+ came before. Local-first, no documentation toil, no SaaS.
17
+
18
+ ## How it works
19
+
20
+ ```
21
+ commit / test failure .hunch/ (git-tracked JSON) Claude Code
22
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
23
+ β”‚ post-commit hook ───┼────────▢│ Decisions (why a change) │────────▢│ MCP tools β”‚
24
+ β”‚ record-bug ───┼────────▢│ Bugs (root causes) β”‚ read β”‚ /hunch-* cmds β”‚
25
+ β”‚ structured diff + β”‚ write β”‚ Constraints(invariants) │◀────────│ CLAUDE.md β”‚
26
+ β”‚ Claude (or heuristic) β”‚ β”‚ Components / Symbols/Edges β”‚ β”‚ CLI β”‚
27
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
28
+ ```
29
+
30
+ - **Index** (no LLM): tree-sitter parses your repo into a symbol/dependency graph β€”
31
+ functions, call edges, imports, components β€” plus churn and fan-in metrics.
32
+ - **Learn**: each commit becomes a structured **Decision** (an ADR); a failing test
33
+ becomes a **Bug** with a ranked suspect list; recurring or severe bugs are promoted
34
+ into **Constraints** (do-not-break invariants) and raise a component's *fragility*.
35
+ - **Ground**: Claude Code reads it through an **MCP server**, an auto-maintained
36
+ **`CLAUDE.md`**, and **slash commands** β€” every answer cites `provenance`
37
+ (source + confidence + evidence), so nothing is a blind assertion.
38
+
39
+ ## Getting started
40
+
41
+ ### 1. Install it
42
+
43
+ ```bash
44
+ npm install -g @davesheffer/hunch # puts `hunch` on your PATH
45
+ ```
46
+
47
+ Or run from source (for hacking on Hunch itself):
48
+
49
+ ```bash
50
+ npm install
51
+ npm run build # compiles to dist/
52
+ npm link # optional: puts a global `hunch` on your PATH
53
+ ```
54
+
55
+ Either way you then type `hunch …`. From a source checkout without `npm link`, use
56
+ `node dist/cli/index.js …` (or `npm run hunch -- …` to run via tsx). The rest of this
57
+ README uses `hunch` for brevity.
58
+
59
+ ### 2. (Recommended) make the `claude` CLI available
60
+
61
+ Hunch's LLM synthesis is billed to your **Claude Pro/Max subscription** through the
62
+ `claude` CLI β€” **never** the pay-per-token API. If `claude --version` works in your
63
+ terminal, you get full LLM-quality capture for free. If it doesn't, Hunch still works
64
+ using a deterministic structural heuristic (lower-confidence drafts). `hunch doctor`
65
+ tells you which mode you're in.
66
+
67
+ ### 3. Initialize the repo you want a memory for
68
+
69
+ ```bash
70
+ hunch init # scaffold .hunch/, index, install the post-commit hook,
71
+ # write .mcp.json + slash commands + CLAUDE.md, register the merge driver
72
+ hunch backfill --since 90d # cold start: seed decisions from recent git history
73
+ ```
74
+
75
+ `init` writes a `.mcp.json` pointing at *this machine's* node + Hunch β€” so **reload
76
+ Claude Code in the repo** afterward to pick up the `hunch_*` tools. (Each teammate runs
77
+ `hunch init` once to wire up their own clone; the captured `.hunch/` content is shared
78
+ via git.)
79
+
80
+ ### 4. Use it
81
+
82
+ ```bash
83
+ hunch why src/auth/session.ts # the decisions / bugs / invariants behind a file
84
+ hunch doctor # check git, schema version, and synthesis mode
85
+ ```
86
+
87
+ …and in Claude Code, just ask: *"why is the session module built this way?"*
88
+
89
+ ## Two ways to use it
90
+
91
+ **Through Claude Code (the point).** Once the MCP server is registered, ask questions
92
+ normally and Claude consults Hunch, or invoke the slash commands:
93
+
94
+ | Slash command | What it does |
95
+ |---|---|
96
+ | `/hunch-why <file\|symbol>` | the decisions, invariants, and bug history behind it β€” with citations |
97
+ | `/hunch-fix <bug>` | fix a bug grounded in past root causes, blast radius, and constraints |
98
+ | `/hunch-fragile` | a fragility report (the riskiest code, with evidence) |
99
+
100
+ The MCP tools Claude calls under the hood: `hunch_why`, `hunch_query`,
101
+ `hunch_check_constraints`, `hunch_get_dependents` (blast radius), `hunch_bug_lineage`,
102
+ `hunch_context` (surgical minimal slice for a task), `hunch_record_decision` (write-back).
103
+
104
+ **Through the CLI** β€” the same graph, from your terminal:
105
+
106
+ | Command | What |
107
+ |---|---|
108
+ | `hunch init [--enforce]` | scaffold `.hunch/`, index, install hook + merge driver, wire up Claude Code (`--enforce` adds a pre-commit invariant guard) |
109
+ | `hunch index` | parse repo β†’ symbols / edges / components (deterministic, no LLM) |
110
+ | `hunch backfill --since 90d` | replay git history β†’ seed decisions |
111
+ | `hunch sync [sha]` | turn a commit into a Decision (run automatically by the hook) |
112
+ | `hunch record-bug --test <id> --message <m>` | capture a Bug from a failing test |
113
+ | `hunch why <path\|symbol>` | decisions / bugs / constraints explaining a target (flags `⚠STALE`) |
114
+ | `hunch query "<q>" [--semantic]` | full-text + graph search (`--semantic` blends in local embeddings) |
115
+ | `hunch embed` | generate local embeddings for semantic recall (opt-in; needs `@huggingface/transformers`) |
116
+ | `hunch context <path\|symbol>` | minimal relevant slice for a task: invariants β†’ decisions β†’ bugs β†’ blast radius |
117
+ | `hunch fragile` | ranked fragility report with evidence |
118
+ | `hunch check [--staged\|--commit <sha>] [--strict]` | guardrail: flag changes touching a do-not-break invariant |
119
+ | `hunch stale` | drift: records whose files changed after they were last verified |
120
+ | `hunch review [--accept <id>\|--reject <id>]` | curate: triage / promote / drop low-confidence drafts |
121
+ | `hunch migrate` | upgrade `.hunch/` records to the current schema version |
122
+ | `hunch compact [--apply]` | prune low-value drafts to bound growth (dry-run by default) |
123
+ | `hunch doctor` | environment diagnostics (git, auth mode, schema version, counts) |
124
+ | `hunch mcp` | start the MCP server over stdio (Claude Code connects here) |
125
+
126
+ ## Semantic search (optional)
127
+
128
+ By default `hunch query` and the `hunch_query` MCP tool use fast keyword (FTS) search β€”
129
+ zero setup, instant, offline. For recall on *paraphrases* (a question that shares no words
130
+ with the record it should find), opt into **local embeddings**:
131
+
132
+ ```bash
133
+ npm i -g @huggingface/transformers # one-time; a local model runtime
134
+ hunch embed # embed your records (first run downloads ~90MB)
135
+ hunch query --semantic "auth token expiry" # hybrid keyword + semantic recall
136
+ ```
137
+
138
+ Embeddings are **local and free** (no API β€” consistent with the subscription-only synthesis
139
+ rule) and **opt-in** (the base install stays lean). The long-lived MCP server picks them up
140
+ automatically once present. Vectors live in the derived SQLite index and are reconciled by
141
+ content hash on every `hunch index`, so they never drift from the JSON source of truth. `hunch
142
+ doctor` reports coverage; tune the blend with `HUNCH_RRF_W_FTS` / `HUNCH_RRF_W_SEM` / `HUNCH_RRF_K`.
143
+
144
+ ## What makes the capture good (not just "changed N files")
145
+
146
+ Even with **no LLM**, the write path runs a structured **diff analysis** β€” added /
147
+ removed / changed symbols, new and dropped dependencies, and which invariants a change
148
+ touches β€” so an auto-captured decision reads like *"introduced `verifySession`,
149
+ `revokeSession`; removed `login`; new dep: redis; touches con_004"*, with breaking-change
150
+ consequences. With the `claude` CLI present it upgrades to full LLM synthesis; otherwise
151
+ it stays useful offline. Either way every record is **advisory and cheap to discard** β€”
152
+ `hunch review` lets you promote the good ones to human-confirmed.
153
+
154
+ ## Working as a team
155
+
156
+ The `.hunch/` JSON is the **source of truth**: diffable, reviewable in PRs, and synced
157
+ for free over `git push` / `pull`. `hunch init` also registers a **git merge driver** so
158
+ concurrent edits to the graph merge **by record id** instead of throwing conflict markers
159
+ (human-confirmed beats auto, then higher confidence, then recency). The routing lives in a
160
+ committed `.gitattributes`; the per-clone driver definition is set up by each teammate's
161
+ `hunch init`.
162
+
163
+ ## Maintenance
164
+
165
+ - **`hunch doctor`** β€” is git healthy? are you on the subscription path or the offline
166
+ heuristic? what schema version is on disk? how many records?
167
+ - **`hunch migrate`** β€” after upgrading Hunch, bring old `.hunch/` records up to the
168
+ current schema (old records are migrated in memory on every read, so reads never break;
169
+ `migrate` persists the upgrade and never drops a record it can't migrate).
170
+ - **`hunch compact --apply`** β€” auto-captured drafts accumulate; compaction prunes the
171
+ low-value ones (rejected / superseded / stale drafts, resolved low-confidence bugs).
172
+ It **never** removes an accepted/human-confirmed decision, an open bug, a constraint, or
173
+ any record another record still references. Run without `--apply` first to preview.
174
+
175
+ ## Where it's stored
176
+
177
+ ```
178
+ .hunch/
179
+ β”œβ”€ components/ one JSON file per architecture node (curated, PR-reviewable)
180
+ β”œβ”€ decisions/ one JSON file per Decision (ADR)
181
+ β”œβ”€ bugs/ one JSON file per Bug
182
+ β”œβ”€ constraints/ one JSON file per Constraint (invariant)
183
+ β”œβ”€ symbols/index.json the symbol graph (high-cardinality, single file)
184
+ β”œβ”€ edges/index.json the dependency graph
185
+ β”œβ”€ manifest.json on-disk schema version
186
+ └─ hunch.sqlite DERIVED FTS5 + graph index, rebuilt by `hunch index` (gitignored)
187
+ ```
188
+
189
+ Low-volume entities are one file per record so they read cleanly in a PR; the
190
+ high-cardinality symbol/edge graphs are single id-sorted arrays to keep git noise down.
191
+ SQLite is a throwaway index rebuilt from the JSON β€” only the JSON is committed.
192
+
193
+ > Note: the on-disk directory is still `.hunch/` (and the MCP tools are still `hunch_*`)
194
+ > for backward compatibility with existing graphs. A future release may migrate these to
195
+ > `.hunch/` / `hunch_*`.
196
+
197
+ ## Architecture
198
+
199
+ ```
200
+ src/
201
+ β”œβ”€ core/ types (Zod schema), ids, paths, glob, schema migration, atomic file I/O
202
+ β”œβ”€ store/ JSON source of truth ←→ SQLite/FTS5 derived index; merge driver; compaction
203
+ β”œβ”€ extractors/ tree-sitter parse, git introspection, the indexer
204
+ β”œβ”€ synthesis/ write path: Claude-CLI (subscription) or deterministic fallback
205
+ β”œβ”€ mcp/ MCP stdio server (the hunch_* tools)
206
+ β”œβ”€ integrations/ post-commit hook, CLAUDE.md writer, .mcp.json + slash commands, merge driver
207
+ └─ cli/ commander entrypoint
208
+ ```
209
+
210
+ ## VS Code
211
+
212
+ A companion **[VS Code extension](vscode-extension/)** visualizes Hunch (a tree of
213
+ decisions / invariants / bugs / fragility, a "why is this file the way it is?" action, and
214
+ a status-bar invariant counter) by reading the committed `.hunch/` JSON directly β€” no
215
+ server, no native deps.
216
+
217
+ ## Notable engineering decisions
218
+
219
+ - **Subscription-billed synthesis, never the API.** The write path drives your Claude
220
+ subscription via the `claude` CLI; `ANTHROPIC_API_KEY` / `ANTHROPIC_AUTH_TOKEN` are
221
+ stripped from the child env to force subscription auth (they outrank it in headless
222
+ mode). A deterministic, no-LLM fallback means the loop never hard-requires credentials.
223
+ - **Native `tree-sitter` (0.21.1) + `tree-sitter-typescript`, not web-tree-sitter.** The
224
+ prebuilt WASM grammars have an ABI incompatible with current `web-tree-sitter`; the
225
+ native bindings ship Node-20 prebuilds (no compiler) and a simpler synchronous API.
226
+ - **`better-sqlite3` pinned to `12.9.0`** β€” 12.10.x ships no Node-20 prebuild and would
227
+ force a source compile; 12.9.0 has the Node-20 (ABI 115) prebuild.
228
+ - **Atomic, durable writes.** All `.hunch/` writes go through a temp-file + rename, with a
229
+ Windows-safe fallback, so an interrupted write can't truncate the index; `put`/`delete`
230
+ refuse to rewrite a corrupt index rather than flatten it.
231
+
232
+ ## Develop
233
+
234
+ ```bash
235
+ npm run typecheck # tsc --noEmit
236
+ npm test # node:test suite (store, graph, parse, indexer, synthesis, migrate, merge, compact)
237
+ npm run hunch -- why src/store/hunchStore.ts # run the CLI from source via tsx, no build
238
+ ```
239
+
240
+ See [DESIGN.md](DESIGN.md) for the full spec. Deferred by design: embeddings / vector
241
+ search, PR/CI webhooks, a web dashboard, and multi-repo support.