@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 +21 -0
- package/README.md +241 -0
- package/dist/cli/index.js +587 -0
- package/dist/cli/invocation.js +23 -0
- package/dist/core/format.js +46 -0
- package/dist/core/glob.js +62 -0
- package/dist/core/ids.js +39 -0
- package/dist/core/io.js +44 -0
- package/dist/core/migrate.js +59 -0
- package/dist/core/paths.js +41 -0
- package/dist/core/types.js +142 -0
- package/dist/extractors/diff.js +198 -0
- package/dist/extractors/git.js +136 -0
- package/dist/extractors/indexer.js +271 -0
- package/dist/extractors/parse.js +176 -0
- package/dist/integrations/claudemd.js +77 -0
- package/dist/integrations/hooks.js +80 -0
- package/dist/integrations/mergeDriver.js +41 -0
- package/dist/integrations/scaffold.js +74 -0
- package/dist/mcp/server.js +233 -0
- package/dist/store/compact.js +100 -0
- package/dist/store/db.js +19 -0
- package/dist/store/embedder.js +133 -0
- package/dist/store/hunchStore.js +469 -0
- package/dist/store/jsonStore.js +268 -0
- package/dist/store/merge.js +179 -0
- package/dist/store/schema.js +100 -0
- package/dist/synthesis/provider.js +488 -0
- package/dist/synthesis/synthesize.js +312 -0
- package/package.json +68 -0
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.
|