Hunch documentation
A shared record for AI agents: what was decided, what happened, and what still needs doing.
Hunch keeps decisions, rules, action records and commitments with their sources. A new agent can check that record instead of rebuilding the story from scratch. Engineering memory explains the reasons behind code; the served state layer extends the same approach to repository, user, team and organization records. Both ship today.
The vision is for agents working across different tools to share one current record. Wider organizational impact is still being tested in a pilot. Hunch checks defined rules about records and evidence; it does not make every submitted statement true or guarantee that an agent uses what it receives.
npm i -g @davesheffer/hunch → cd your-repo && hunch init → reload your assistant and ask “why is X built this way?”. Use hunch backfill --since 90d when you want to seed an existing repo from history.Install#
Hunch needs Node ≥ 22.13. Install the CLI globally — that puts a hunch binary on your PATH:
npm install -g @davesheffer/hunchIf the shell reports that hunch is not found, no global binary is required. From the repository directory, run npx -y @davesheffer/hunch@latest init.
Or run from source (for hacking on Hunch itself):
git clone https://github.com/davesheffer/hunch && cd hunch npm install npm run build # compile to dist/ npm link # optional: global `hunch` from source
The optional Hunch editor companion is available from Open VSX. It reads the same memory home as the CLI and MCP server; its version is separate from the CLI version.
Initialize a repo#
Run hunch init in the repo you want a memory for. One command scaffolds everything:
hunch init # scaffold .hunch/, index, install hooks, wire up assistants hunch backfill --since 90d # cold start: seed decisions from recent git history
hunch init does the following, idempotently (re-running is safe and merges into existing files):
- Scaffolds
.hunch/and indexes the repo into a symbol/dependency graph. - Installs a post-commit hook (the learning loop) and a pre-commit Constraint Guard.
- Writes
.mcp.json+ slash commands + an auto-maintainedCLAUDE.md, and registers a git merge driver for the graph. - Wires up every detected assistant — Claude Code, Cursor, VS Code (Copilot), Windsurf, Codex, Antigravity — to the same
.hunch/graph.
init for local hooks and setup. In Matrix mode it also validates .hunch/team.json, clones the dedicated memory repo into ignored local storage, and writes this machine’s ignored pointer. Source-checkout installs may use local executable paths.Update Hunch#
Ask an agent to “update Hunch”, or run hunch update from the repository root. If the shell reports that hunch is not found, run npx -y @davesheffer/hunch@latest update instead. It installs the latest release and aligns all configured harness pins while preserving existing settings.
For standalone npm projects, the command keeps Hunch in its current dependency section and saves an exact version. Without a repository dependency it updates the global CLI. Add --global to update both, or --dry-run to preview the commands. Other package managers and workspaces should update their dependency explicitly, then run hunch integrations repair-pins.
The update also repairs known legacy hook commands while preserving unrelated settings and intentionally disabled hooks. Restart or reconnect active assistant sessions afterward. In Codex, open /hooks to review and trust changed commands, then start a new session. Changing the pinned version changes the command and requires renewed trust; Hunch does not approve it for you. Each invocation updates the current repository; repeat it in other repositories as needed.
Installed interactive CLI commands may show a cached update notice. At most once every 24 hours, a detached worker asks npm for the package's public latest version. Hooks, MCP, CI, servers, the updater, non-interactive commands, and source checkouts skip that request. Set HUNCH_NO_UPDATE_CHECK=1 or NO_UPDATE_NOTIFIER=1 to disable it.
hunch integrations check --harness codex --probe --require mcp hunch integrations check --harness codex --require context
The first command checks a fresh MCP process. Run the second after trusted hooks have run in a new Codex session: it checks recorded host delivery on the expected Hunch version. Configuration, delivery, and the agent's use of memory are different evidence. Requiring edit-blocking additionally needs strict firmness and a delivered pre-edit event.
Your first query#
Ask the codebase why — from the CLI, or in your assistant once the MCP server is registered:
hunch why src/auth/session.ts # decisions / bugs / invariants behind a file hunch doctor # git, schema version, synthesis mode
…and in your assistant: “why is the session module built this way?” — the assistant consults Hunch and answers with citations (record ids + provenance).
Synthesis & billing#
Optional synthesis drafts memory from commits and failures. Agent-initiated work stays with that agent's provider and its CLI authentication; an unavailable or unknown origin uses the deterministic local fallback. Human terminal invocations can use an explicitly selected provider. Installing a CLI alone does not select it. See agent origin and provider routing.
| CLI | Subscription | Detected by |
|---|---|---|
claude (Claude Code) | CLI's configured authentication | claude --version |
codex (OpenAI Codex) | CLI's configured authentication | codex --version |
cursor-agent (Cursor) | Cursor | cursor-agent --version |
A terminal provider preference lives in gitignored local config. It does not override a known initiating agent with another provider. hunch provider shows availability and why a provider was selected:
hunch provider codex-cli # local: Claude / Codex / Cursor / openai-compat / deterministic hunch provider # see availability + why this provider is selected export HUNCH_SYNTH_PROVIDER=claude-cli # one-shell override; `auto` disables the local choice
Local & self-hosted models. No subscription CLI is required: point Hunch at an OpenAI-compatible endpoint — Ollama, vLLM, LM Studio, llama.cpp server, and anything else that speaks the chat-completions format. Select it like any other provider (hunch provider openai-compat, or the one-shell override):
export HUNCH_SYNTH_PROVIDER=openai-compat # alias: ollama export HUNCH_SYNTH_BASE_URL=http://localhost:11434/v1 export HUNCH_SYNTH_MODEL=llama3.1 export HUNCH_SYNTH_API_KEY=... # optional — omit for keyless local servers export HUNCH_SYNTH_TIMEOUT_MS=300000 # optional, default 5 min — local models can be slow export HUNCH_SYNTH_MAX_TOKENS=2048 # optional output cap export HUNCH_SYNTH_ALLOW_METERED=1 # public remotes only; deliberate billing/trust opt-in
Opt-in only: leave these unset and Hunch behaves exactly as above. Localhost, private/link-local IPs, and conventional LAN names work directly. Every public remote requires HUNCH_SYNTH_ALLOW_METERED=1 so a newly launched paid provider can never bypass a stale hostname list; set it only when the endpoint is deliberately trusted and any billing is understood.
Deep Synthesis. --deep takes repeated samples through the bound provider and reconciles them. --verify checks the draft against the commit. These are model-assisted drafting steps, not independent proof; the result stays advisory. They do not fan out to another installed provider.
hunch backfill --deep # higher-quality notes across history hunch sync <sha> --deep # a single commit (fact-check on) hunch sync <sha> --verify # fact-check a single note
MCP & assistants#
The Hunch MCP server lets supported clients query the same memory. hunch init writes MCP configuration and guidance for supported assistants. Automatic context delivery and edit blocking depend on the host's lifecycle hooks, settings and trust; an MCP connection alone proves neither.
| Assistant | MCP config | Grounding file |
|---|---|---|
| Claude Code | .mcp.json | CLAUDE.md + /hunch-* commands |
| Cursor | .cursor/mcp.json | .cursor/rules/hunch.mdc |
| VS Code (Copilot) | .vscode/mcp.json | .github/copilot-instructions.md |
| Windsurf | .windsurf/mcp_config.json | .windsurf/rules/hunch.md |
| Codex | .codex/config.toml | AGENTS.md + .codex/hooks.json (review with /hooks) |
| Antigravity | .agents/mcp_config.json | AGENTS.md + .agents/hooks.json |
The server runs over stdio and exposes memory tools under hunch_*. State tools under nuryel_* are exposed when enabled for the configuration or state root, not by default in every plain repository. Use hunch mcp --root <partition-dir> for a served partition. Other MCP clients can register a launcher manually; starting it is not a connectivity test:
hunch mcp # serves Hunch over stdio (this is what .mcp.json launches)
hunch init over a global claude mcp add. .mcp.json is registered by file path, so it’s robust and travels with the repo.Reload your assistant#
After hunch init or an update, a running assistant may still hold the old MCP process. Reload or reconnect your assistant in the repo so it loads the current tools. Codex hooks also require command trust: review changed commands with /hooks, then start a new session.
.hunch/ and the tools are hunch_*. If the tools don’t appear after a reload, run hunch doctor.Private memory v0.17#
Keep sensitive decisions, bugs and constraints in a separate private overlay. Authorized local queries and checks can include that overlay; public-only outputs use the public store. Choose the destination when capturing private information and control access to the overlay through your local and Git permissions.
One command sets it up (no env var, no shell-profile edit):
hunch private # default ./.hunch-private (gitignored) hunch private ~/work/secret-memory # or a path you choose hunch private --repo git@github.com:you/mem-private.git # or clone a private repo
It writes a gitignored .hunch/local.json pointing at the store, installs the --private post-commit hook, and that’s it — Hunch, the MCP server, and the local VS Code extension auto-detect it; hunch doctor shows private: on → …. It’s opt-in and default-off: no local.json (and no HUNCH_PRIVATE_DIR) means the overlay is completely inert.
Record sensitive items with private: true on hunch_record_decision / hunch_record_correction; they’re written to the overlay, never the committed repo. Post-commit synthesis routes its auto-captured decisions there too, so a private-memory repo’s auto-decisions never land in the public tree. HUNCH_PRIVATE_DIR overrides local.json per-shell (e.g. for portability); the git hook lives in .git/hooks/ and is never committed.
Auto-commit is on by default. Captures attempt to commit to their actual memory home. A private/shared Git store can also be pushed; public memory in an application repository rides your next code-branch push. Managed grounding documents can be refreshed alongside memory. Failed or disabled synchronization can leave a record local, so inspect the saved durability result. Opt out with --no-auto-commit on hunch init, private or shared.
HUNCH_PRIVATE_DIR unset in public CI; the scaffolded guard also uses --public-only. Private rules still need the same human authority and enforcement conditions as public ones.Windows note#
On Windows, a global claude mcp add writes to ~/.claude.json keyed by the raw working-directory string. Drive letters are case-insensitive (c:\ and C:\ are the same folder) but Claude Code compares the key case-sensitively — so it can create two project blocks for one directory, and a session that resolves to the other casing sees no hunch_* tools.
If you hit this, run hunch doctor — on Windows it detects the split and heals it (merging the MCP servers across both casings, after backing up ~/.claude.json). hunch init runs the same heal automatically.
Memory and Project DNA#
Memory records what matters: a decision and its reason, a rejected approach, a rule, a fixed bug or an open finding. Project DNA describes observed conventions: the repository's terminology, contribution habits and review expectations. It helps an agent fit the project without turning common habits into mandatory rules.
hunch why src/auth/session.ts hunch dna inspect hunch dna context
The code graph connects symbols and dependencies. Engineering Landscape records connect systems, services, owners and operational resources. hunch prove origin/main --public-only can bind an exact committed change to these records and its checks. A proof describes the evidence and gaps; it does not authorize a merge or deployment.
Read the Project DNA contract and change-proof guide.
See Hunch's contribution#
A task completion card and local report show what memory reached the agent, what the agent says it used, and which checks actually ran. A remembered lesson, an agent's attribution and a passing test are separate evidence; none alone proves that Hunch caused a better outcome.
hunch report hunch report <task-id> --html
The agent reuses a task ID supplied by a trusted prompt hook, or starts one through hunch_task. It carries that ID through context and captures, runs relevant checks through the returned verification launcher, then finishes the task. Missing instrumentation stays unverified.
The HTML report is a saved local file and may contain private memory. Read task reports for evidence grades, privacy controls and the agent workflow.
The reasoning graph#
These core engineering records explain a project; the code graph connects them to files and symbols. Action records, commitments and other state extend the same store:
| Record | What it captures |
|---|---|
| Decision | Why a change was made — an ADR auto-drafted from each commit (context, decision, alternatives, consequences). |
| Bug | A root cause + its history (introduced → fixed → recurred), captured from a failing test. |
| Constraint | A do-not-break rule. Recurring or severe bugs become one; corrections create one directly. |
| Finding | An observed gap, incident or measurement with dated evidence, which may remain open. |
| Code map | How your code connects — functions, files, and components — so Hunch can see the ripple effect of a change. |
Durable memory is kept in readable files. Code and search indexes are derived data that Hunch can rebuild from the repository and its records.
Provenance & confidence#
Records carry provenance and confidence so you can distinguish an agent's observation from human-confirmed intent. A source label does not independently prove the statement. Captured memory starts as advisory context; blocking needs human authority and a supported enforcement path. hunch escalations surfaces conflicts and decisions that still need human review.
Time-travel#
Decisions and constraints carry a git-anchored valid-time window. Supersession closes a window instead of deleting the record, so history stays auditable. Ask the graph what was believed at any past commit or tag:
hunch why src/auth/session.ts --as-of v0.7.0 hunch timeline src/auth/session.ts # the full decision history, newest first
The hunch_why and hunch_context MCP tools take the same optional as_of ref.
Decision-grounding#
Architectural Conformance keeps the code honest to the graph; decision-grounding keeps your docs honest to it. A decision can be anchored to a topic (e.g. auth.session), and a topic always has one live answer — the current decision, its history, and what was rejected along the way.
Capture with /capture. It interviews the decision to a resolved state — topic, rationale, rejected alternatives — before anything is written, and the graph refuses to hold two live decisions on one topic. A git merge is the one thing that can create two; hunch reconcile-topics catches it for human resolution.
Markdown topic anchors — AGENTS.md as a drift surface
Anchor a section of AGENTS.md, CLAUDE.md, or any repo markdown to a topic with an HTML comment:
<!-- hunch:topic auth.session --> # grounds only <!-- hunch:topic auth.session dec_a1b2c3d4e5 --> # pinned: prose written against that decision
- Grounding: whenever an assistant edits the file, the pre-edit hook injects each declared topic's current decision and what it rejected — follow the graph, not the stale prose being edited.
- Drift: a pinned marker whose decision has been superseded fires
doc-anchor-stale; a pin to a missing decision firesdoc-anchor-dangling. Only an explicit pin can fire — never a semantic guess. Unpinned markers ground but never drift. - Heal:
hunch heallists each drifted section with the decision to reconcile toward, then you update the pin. Read-only — it never rewrites your prose.
hunch drift # ⛔ exits non-zero on any anchor-stale drift or topic collision — wire into CI hunch heal # what to reconcile, and toward which decision hunch reconcile-topics # >1 live decision on a topic (post-merge) — exits non-zero
The component wiki & specs ledger#
hunch wiki renders a component wiki from the graph — one page per component (why it's shaped this way, invariants, structure, bug history, relations) plus a specs ledger that grades every markdown doc in your repo deterministically: ✅ grounded (anchored to current decisions — safe to trust), ⚠ stale (pinned to a superseded decision, says "proposed" about shipped code, or references only deleted files), ◻ unverified (no anchors — Hunch can't vouch either way). No LLM in any grade.
Stale docs get adopted. The wiki copies a stale doc into wiki/docs/ as a wiki-managed page healed against the graph — every stale pin re-pinned to the current decision with a 🧭 correction inline quoting what changed and what was rejected. Your original file is never touched; heal it (or delete it) and the copy retires automatically. The ledger routes readers to the trustworthy version either way.
Freshness is drift, not a cron job. Each page's graph inputs are content-hashed into a manifest; when the graph moves, hunch drift names exactly which pages went stale and hunch wiki --heal regenerates only those. Hand-editing a generated page trips the same wire (the graph is the source of truth — edit records, not pages).
hunch wiki # generate/refresh wiki/ + the specs ledger hunch wiki --check # CI gate: non-zero if any page is stale (green no-op if never adopted) hunch wiki --heal # regenerate ONLY the stale pages; retire orphans hunch wiki --private # render the FULL graph (private overlay included) into the OVERLAY repo
With a private overlay, the public wiki is built from the committed store only — a private record can never reach a committed page, by construction. --private writes the full-graph wiki into the overlay repo instead; nothing lands here.
MCP tools#
The tools your assistant calls under the hood. Read tools answer “why / what-must-not-break / blast radius”; write tools persist new memory.
| Tool | What it does |
|---|---|
hunch_query | Full-text + graph search across all records, ranked with provenance. |
hunch_why | Decisions, bugs & constraints behind a file/symbol (accepts as_of). |
hunch_check_constraints | Invariants whose scope matches a path/glob — call before editing. |
hunch_get_dependents | Transitive dependents of a symbol — the blast radius. |
hunch_blast_radius | Dependent files + near-violations a change could break indirectly. |
hunch_structure | The indexed shape of the repo / a dir / a file / a symbol — orient from the graph instead of grep rounds; tells the agent exactly which file to read. |
hunch_pr_impact | The impact surface of a change (working tree / staged / branch / commit): dependent files reached, invariants direct & near, decisions concerned. Advisory — the gate stays hunch_merge_verdict. |
hunch_path | Shortest dependency chain between two symbols/files/components, either direction — "how does A reach B?". |
hunch_bug_lineage | Bugs matching a symptom/symbol with their introduced→fixed→recurred lineage. |
hunch_context | The minimal relevant slice for a task — invariants, why, bug history, blast radius. |
hunch_timeline | A target’s decision history over time, with valid-time windows. |
hunch_merge_verdict | A cited BLOCK / WARN / PASS over a working-tree, staged, branch, or commit diff (see below). |
hunch_record_decision | Write-back: persist a new Decision (ADR) with provenance. Gated by topic — refuses a second live decision for a topic that already has one (never silently two); accepts an optional capture_token. |
hunch_capture_decision | Start a capture session — returns a one-question-at-a-time grilling protocol plus a capture_token to hand back to hunch_record_decision. |
hunch_current_decision | The single in-force decision for a topic — the drift-detection anchor (with what it rejected). |
hunch_record_correction | Save a scoped correction. Unconfirmed agent captures remain advisory; blocking needs human confirmation and strict enforcement (see Never Twice). |
hunch_record_finding | Write-back: persist an observation with no code change (an audit that found a gap, a measurement, an incident) — anchored to a date + evidence, it grounds future edits to the affected files. |
hunch_findings | The open-observations ledger: live findings (open / accepted-risk / scheduled) for a file, glob, or symbol — inherit past audits instead of re-discovering them. |
hunch_runbook | The proven steps for a recurring task (e.g. “add an MCP tool”) — kind-scoped retrieval over runbooks. |
hunch_compare | Rank N candidate branches/commits by architectural fit (fewest invariant hits) — the “evaluate 5 solutions” check. |
hunch_conformance | Does the code still satisfy recorded intent? (e.g. pay still reaches verifySession) — deterministic, over the graph. |
Slash commands#
For Claude Code, hunch init also writes ergonomic slash commands:
| Command | What it does |
|---|---|
/hunch-why <file|symbol> | The decisions, invariants, and bug history behind it — with citations. |
/hunch-fix <bug> | Fix a bug grounded in past root causes, blast radius, and constraints. |
/hunch-fragile | A fragility report — the riskiest code, with evidence. |
/capture | Grill you through a decision one question at a time, then persist it against its topic (via hunch_capture_decision). |
/heal | Read-only doc↔graph reconciliation — surface where a doc disagrees with the graph; never rewrites prose silently. |
Firmness levels#
hunch init installs supported lifecycle hooks and guidance for the assistant. Where the host loads and trusts those hooks, they can deliver relevant memory before work. Firmness controls how Hunch responds; use integration checks to see which capabilities were actually observed in your host.
hunch firmness # print the current level hunch firmness strict # change it (takes effect on the next edit; no restart)
| Level | Before an edit |
|---|---|
off | nothing (the hook is a no-op) |
advisory default | inject the relevant Hunch slice as context |
firm | advisory + explicitly flag invariants in the file’s scope |
strict | firm + deny a supported direct violation of a human-confirmed blocking constraint; indirect blast-radius warnings stay advisory |
The memory loop — it runs itself#
Captured memory becomes available as advisory context without routine manual triage. Genuine conflicts and authority decisions can still need review. Blocking power requires human confirmation. Configured hooks and synchronization handle much of the loop; task reports show what was observed:
hunch log # the memory timeline: capture · adopt · supersede · prune · repair hunch log --diff <sha> # what one move changed hunch revert-move <sha> # undo one move (local git revert, never pushed) hunch escalations # the decisions only YOU can make — normally empty hunch repair --apply # heal bindings after a rename (sync does this automatically) hunch push # the one deliberate outward step
| Piece | What it does on its own |
|---|---|
| Auto-trust | a capture is live advisory memory instantly; migrate an old draft backlog once with hunch adopt-drafts |
| Self-repair | renames heal every exact file binding — decision files, tripwire & constraint scopes, policy selectors — from git’s own rename detection; each repair is a revertable timeline move |
| Inline escalations | only what the graph can’t settle itself asks you: a topic conflict, a candidate rule, a proposed rule with its proof, a repaired rule needing a fresh proof — each a question with its resolution verb |
| Local-first | memory auto-commits locally and rides your next push; hunch push (or the panel’s Approve-to-push) is the explicit outward step |
In VS Code, the Hunch Memory panel is the same spine as a source-control view: the timeline with click-to-diff and one-click local revert, a ⚖ Needs your decision group that exists only while something real needs you, and a 🏛 Constitution group where activate / demote / withdraw / retire are each one audited click.
Never Twice v0.13#
The most expensive failure in AI coding is being corrected and then re-corrected: you say “no, never call X here”, the agent complies once, and next session it does it again — because the feedback was stored as advisory text, not enforced. Hunch closes that loop.
The agent can save your correction as a scoped Constraint through hunch_record_correction. A capture without a verified human interview token remains agent-reported testimony, capped at warning severity. Human confirmation can give a supported rule blocking authority; strict firmness and a working host hook or CI guard are also required.
You: "no — never import lodash, we ship our own utils"
Agent: hunch_record_correction({ rule: "never import lodash; use src/utils",
scope_hint_file: "src/cart.ts", severity: "blocking" })
→ con_… recorded as advisory testimony without a capture token.
Confirm the rule through the supported human review flow before relying on a deny.The UserPromptSubmit hook nudges the agent to persist a rule whenever your prompt reads like a correction. Scoping is conservative by default (the file you were in); a repo-wide rule is only blocking when you pass applies_to_all, so one correction can’t silently gate the whole tree.
Causal Merge Verdict v0.14#
A diff-only reviewer sees what changed. It can’t see that the line you’re deleting is the fix for an incident, that the symbol you’re re-adding was deliberately retired, or that the helper you’re adding already exists three modules over. Hunch can — because it holds the why and the whole graph.
hunch_merge_verdict (and hunch check / the CI guard) replays a diff against the graph and returns one cited verdict — BLOCK / WARN / PASS — that shows the reasoning, not just the rule:
VERDICT: ⛔ BLOCK — this change breaks a recorded invariant or re-opens a known bug.
⛔ pay() must verify the session before charging — con_pay
🧠 why: "Charge must verify the session first" (dec_pay)
🐞 guards against: Double-charge on unverified session — pay() charged without verifying (bug_…)No model in the loop, so it’s safe as a merge gate: it blocks only on a high-confidence rule you’ve confirmed, and warns on everything softer. Call it with {} to check staged changes, or pass base: "origin/main" for a PR range.
Decision Guard (Veto) v0.15#
Decisions record not just what you chose but the alternatives you rejected. The Decision Guard flags a change that reverses a decision — re-introducing an approach an in-force decision rejected — so the agent can’t quietly walk back a deliberate call.
hunch veto # flag changes that reverse a rejected alternative
Like the other gates: it warns by default and blocks under strict only on a rejected approach you’ve explicitly vouched for — the one-click activation in the VS Code Hunch Memory panel, or hunch review --accept <id> in the terminal. Blocking power is never granted automatically.
Regression Guard#
Re-adding a symbol or dependency that an in-force decision deliberately retired gets flagged — warns always, fails a strict commit only when the retirement is tied to a blocking invariant. The agent stops undoing intentional design. The pre-edit hook also surfaces what a decision retired from a file (“don’t re-add login here — dec_017 removed it”), and the commit-time hunch check does the actual gating.
Redundancy Guard v0.16#
Coding agents work from a local context window, so they re-implement a helper that already lives three modules over, or re-add a dependency the codebase already has — sprawl a diff-only reviewer can’t see. Hunch holds the whole symbol graph, so a diff that adds a function or class already defined elsewhere is flagged with its existing location.
Possibly re-implements 1 symbol(s) that already exist (advisory — review, never blocks): ⟲ adds function `formatDate` — already defined in src/util/date.ts
It’s advisory — it never blocks a commit; it surfaces in hunch check, the CI guard, and the merge verdict. It’s tuned to stay quiet, so a refactor that just moves code around isn’t mistaken for a duplicate.
CI Constraint Guard#
Memory that can hold a merge — when you've asked it to. hunch ci scaffolds a GitHub Action that runs hunch check on every PR and comments the affected invariants and decisions (with con_/dec_ ids and the causal why). The check fails only on a direct, high-confidence, non-stale blocking invariant — a rule you confirmed yourself.
hunch ci # scaffold .github/workflows/ + the PR comment action
hunch check --staged --strict # gate staged changes hunch check --base origin/main # gate a PR range (used in CI)
CLI reference#
Run hunch <command> --help for full flags. The everyday commands:
| Command | What it does |
|---|---|
init | Scaffold .hunch/, index, install hooks, wire up assistants. |
update [--global] [--dry-run] | Install the latest Hunch release and repair every configured harness pin in the current repository. |
index | Parse the repo into a symbol/dependency graph (deterministic, no LLM). |
backfill | Replay git history to seed decisions (cold-start fix). --since 90d |
sync | Capture a decision from a commit (run by the post-commit hook). |
query | Full-text + graph search. Add --semantic for embeddings recall. |
why | Explain why a file/symbol is the way it is. --as-of <ref> |
timeline | The decision history for a file/symbol over time. |
context | Assemble the minimal relevant Hunch slice for a task. |
fragile | Ranked fragility report with evidence. |
check | Flag changes that touch a do-not-break invariant (local + CI guard); also flags (advisory) symbols you add that already exist elsewhere. |
status | Enforcement readiness at a glance — what's enforcing, what's waiting for confirmation, what went stale. |
veto | Decision Guard — flag changes that reverse a rejected alternative. |
structure | Repo map / dir contents / file outline / symbol definition — from the graph, no grep. hunch structure src/auth |
impact | The impact surface of a change — dependents reached, invariants, decisions concerned. hunch impact origin/main, --commit <sha>, or staged by default. Advisory. |
path | Shortest dependency chain between two points: hunch path chargeUser verifySession. |
drift | Flag doc≠graph drift — a file anchored to a superseded decision (anchor-stale), a markdown pin to a superseded/missing decision (topic anchors), a live finding whose anchor evaporated (finding-stale), plus topic collisions. Deterministic; exits non-zero for CI. |
findings | The open-observations ledger — audited gaps/debt with no fix landed yet, anchored to a date + evidence instead of a commit. hunch findings src/procs/**, --all for history. |
reconcile-topics | Scan for >1 live decision per topic (an invariant a git merge can violate) and exit non-zero. Wire into a post-merge hook / CI. |
heal | Read-only doc↔graph reconciliation — report where prose and the graph disagree; never rewrites docs silently. |
wiki | Generate the component wiki + specs ledger from the graph. --check CI gate, --heal regenerates only stale pages, --private renders the full graph into the overlay repo. |
ci | Scaffold the CI Constraint Guard (GitHub Action). |
record-constraint | Record an invariant the codebase must not break. |
record-bug | Capture a Bug from a failing test (symptom + suspects). |
test | Run tests; capture failures as Bugs, promote recurrences to Constraints. |
supersede | Mark one decision as replaced by another (invalidate, don’t delete). |
stale | List decisions/constraints whose files changed after last verified (drift). |
review | Triage low-confidence drafts: list, accept, or reject. |
firmness | Get or set how firmly the agent hook enforces Hunch. |
embed | Generate local embeddings for semantic search (opt-in). |
compact | Prune low-value auto-captured records. |
migrate | Upgrade .hunch/ records to the current schema version. |
mcp | Start the MCP server over stdio. |
doctor | Diagnose the environment (git, synthesis provider, index freshness) + flag memory drift (dead refs, dangling supersedes, stale “proposed” docs). |
conform | Intent-conformance — prove the code still satisfies each decision’s recorded intent over the graph. --strict to fail. |
compare | Rank candidate branches/commits by architectural fit. hunch compare feat-a feat-b --base main |
runbook | Distill a reusable runbook from a commit range, or --find <query> to look one up. |
eval | Score retrieval quality (Recall@k, MRR) over a golden set; A/B the graph stream. --kind runbooks |
capture-comments | Lift inline hunch-why: / hunch-rule: comments into the graph (decisions + constraints). |
hook | The agent pre-edit hook handler (installed by init; reads the event JSON on stdin) — injects relevant memory before an edit, and at strict firmness denies edits that hit a blocking invariant. Never blocks on its own failure. |
merge-driver | (internal) git merge driver for .hunch/ JSON — resolves concurrent edits by record id, no conflict markers. Wired by init. |
Common workflows#
Copy-paste sequences for the everyday tasks. Run hunch <command> --help for every flag.
Set up a new repo
hunch init # scaffold, index, install hooks, wire up assistants hunch backfill --since 90d # seed decisions from recent history (no empty day-1) # …reload your assistant, then ask: "why is X built this way?"
Join a repo that already uses Hunch
git pull # the .hunch/ graph travels with the code hunch init # wire YOUR assistants to the shared graph (idempotent) # …reload your assistant — the team's memory is now in context
Ask why a file is the way it is
hunch why src/auth/session.ts # decisions, bugs & rules behind it hunch timeline src/auth/session.ts # how the thinking changed over time hunch why src/auth/session.ts --as-of v1.2.0 # what was believed at a past release
Turn a correction into an enforced rule
Tell your assistant the rule (it records it for you), or do it from the CLI — then confirm it so it actually blocks. Name the actual violation with --forbid-dep (or --forbid-symbol): the rule then blocks the real change across the file's whole life and stays quiet on edits that don't break it, where a scope-only rule relaxes to advisory once the file is edited again.
hunch record-constraint "never import lodash; use src/utils" \ --scope "src/**" --severity blocking --forbid-dep "lodash" hunch review --accept <id> # confirm → now held against every assistant
--forbid-dep matches the parsed import (a comment or string naming the module can't trip it; a submodule like lodash/groupBy is caught). A correction your assistant records is given the same matcher automatically. --match <regex> remains as a lint-grade textual fallback. None of these are bypass-proof — deliberate indirection can still route around any rule.
Curate the draft queue
hunch review # segmented: ready-to-confirm vs needs-scrutiny hunch review --accept-verified # batch-accept the well-grounded ones hunch compact # prune rejected / superseded / stale low-value drafts
Check a change before you merge
hunch check --staged --strict # does this break a do-not-break rule? hunch veto --staged # does it reverse a rejected decision? hunch conform --strict # does the code still honor recorded intent? # …or check a whole PR range instead of staged files: hunch check --base origin/main
Add the CI merge gate
hunch ci # scaffold the GitHub Action (runs on every PR) git add .github && git commit -m "ci: add Hunch constraint guard"
Capture a higher-quality note for an important commit
hunch sync <sha> --deep # reconcile several drafts + fact-check the note hunch review # then confirm it
Make an existing public repo's memory private
hunch private --repo git@github.com:you/mem-private.git --migrate # moves existing memory into the private store, makes this repo code-only, # and prints the one git command to commit the now-clean public repo
Work across branches & worktrees
hunch worktree ../feature-x -b feature-x # new worktree, already sharing memory hunch doctor # confirms "worktree: linked — sharing the repo's memory"
It's not working
hunch doctor # git, synthesis provider, index freshness, drift hunch index # rebuild the code map from current source hunch migrate # after an upgrade, bring records to the latest schema
Where it’s stored#
The source of truth is plain, readable JSON in a Git repository you control: under .hunch/ in the code repo by default, or in a dedicated private memory repo in Matrix mode. The code repo then carries only the credential-free .hunch/team.json; local paths and the derived SQLite search index stay ignored and can be rebuilt at any time.
Doctor & troubleshooting#
hunch doctor is the first stop for anything that looks off — it reports git status, the resolved synthesis provider, schema version, index freshness, and record counts (and on Windows, heals the ~/.claude.json casing split).
hunch doctor| Symptom | Fix |
|---|---|
Assistant shows no hunch_* tools | Reload the assistant in the repo; if still missing, hunch doctor. |
Synthesis is deterministic | Log into Claude Code, Codex, or Cursor. If more than one is available, choose with hunch provider <name>. |
| Graph looks stale | hunch index to rebuild the symbol graph from current source. |
| Schema mismatch after upgrade | hunch migrate to upgrade .hunch/ records. |
| Advertised team memory is unavailable | Check Git access and .hunch/team.json, then run hunch shared --repo <the-same-url>. Hunch refuses to fall back to another graph. |
Working as a team — the Matrix v1.9#
Matrix mode gives a project one living engineering-memory spine across teammates, branches, worktrees, agents, and operating systems. The source of truth is a separate private Git repository you control; You provide the Git hosting; the committed pointer contains no credentials.
Create that repository first, grant the team normal Git access, and have one maintainer connect it:
npm i -g @davesheffer/hunch hunch shared --repo git@github.com:acme/project-hunch-memory.git git add .gitignore .hunch/team.json git commit -m "chore: connect shared Hunch memory" git push
Use a credential-free HTTPS or SSH URL and leave authentication in SSH or the Git credential helper. Add --migrate only when moving existing public .hunch/ records into the dedicated store.
After the pointer commit lands, each teammate installs the same Hunch version, pulls, and runs hunch init. Hunch validates .hunch/team.json, creates an ignored .hunch-private/ clone, and merges the local path and preferences into ignored .hunch/local.json. An unparseable local config is never overwritten.
Always pumping. CLI operations attempt a bounded pull at startup; long-lived MCP servers refresh at tool-request boundaries. Captures commit and synchronize the memory-only repository by default, concurrent JSON records merge by identity, and a failed push stays local for hunch shared --sync to retry.
Authority stays fail-closed. Captures become advisory memory immediately. Blocking policy authority still requires an explicit audited human action, and public receipts should use --public-only so the shared graph never appears on a public surface.
Pause or roll back without deleting memory
hunch firmness off hunch shared --repo git@github.com:acme/project-hunch-memory.git --no-auto-commit # Keep the installed version; inspect the problem before choosing a rollback.
This preserves every shared and local memory record while disabling enforcement and automatic publication. Revert the .hunch/team.json setup commit only if new clones must stop discovering the Matrix; do not delete the memory repo or local overlay. Keep every client on the same supported Hunch version before resuming shared policy workflows, then run hunch shared --sync.
Maintenance#
Two housekeeping commands keep the graph healthy over time:
hunch compact # prune rejected/superseded/stale low-value drafts hunch stale # list records whose files changed after they were last verified
Routine captures are available as advisory memory, and hunch escalations asks you inline about the few things the graph can't settle itself. Migrating an older repo? One hunch adopt-drafts clears a legacy queue, and hunch log shows every memory move — each one revertable.
Release integrity#
Hunch tests release artifacts before publication credentials are available. The immutable npm tarball and VSIX are then passed to isolated publishers, which verify the public registries converged on the expected version. npm publishes with GitHub Actions provenance; one tested VSIX goes unchanged to Open VSX and is downloaded again for byte verification.
npm view @davesheffer/hunch version dist.integrity dist.attestations --json git tag --list 'v*' 'vscode-v*'
Inspect GitHub Actions, npm, and Open VSX for the public receipts.
Develop & contribute#
Hunch is open source under Apache-2.0. Contributions are welcome — see CONTRIBUTING.md and the repo to get started.