← roadmap

intercache

improve priority P2 effort M wave 2

What it does: An MCP-only plugin (8 tools, 0 skills/commands/agents) implementing a content-addressed file cache for Claude Code: SHA256 blob store with 2-char prefix sharding and atomic writes (store.py), per-project SQLite manifests doing fast mtime+size validation with a SHA256 slow path (manifest.py), and per-project SQLite-WAL session tracking of file accesses (session.py). Tools: cache_lookup/store/invalidate/warm/stats, session_track/diff, cache_purge. Data lives at ~/.intercache/. Goal per PHILOSOPHY.md: eliminate redundant cross-session file re-reads. NOTE: despite the name/description, it is NOT semantic — all embedding/vector code was removed in v0.2.0 and moved to intersearch; what remains is exact path+SHA256 matching.

Rationale: The storage engine is genuinely well-built (atomic tmp+rename blob writes, WAL SQLite, busy_timeout, path-traversal guards in both server and manifest, a parent-death watchdog for orphaned MCP processes). But two structural problems make it inert and mislabeled. (1) NOTHING auto-invokes it: the plugin registers only an MCP server with no PreToolUse/PostToolUse hook intercepting the harness Read tool, so cache_lookup/cache_store/session_track only fire if an agent voluntarily calls them before/after every read — which contradicts the plugin’s own decision filter ‘Does this work transparently without agent cooperation?’ and effectively never happens. The sole hook, post-commit.sh, is a no-op echo stub that never actually calls cache_invalidate. (2) The name, plugin.json description, README title, and server.py module docstring (‘embedding search’) all still claim ‘semantic cache,’ but v0.2.0 (commit 30c7bd8) stripped all embeddings to intersearch; embeddings.py is dead code shipped on disk. The 2026 token-economics SOTA (Uber burning its AI budget; ~80% of agent tokens spent finding/re-reading code) makes a cross-session cache high-ROI in principle, but the winning implementations are harness-level (the Clavain harness already tracks file state and discourages in-session re-reads), so intercache’s only defensible niche — the cross-session tier — is exactly the part its missing auto-wiring fails to deliver. This is fixable, and the foundation is sound, so improve rather than deprecate.

SOTA gap: Auto-invocation via deterministic hooks. The ‘harness engineering as a discipline’ SOTA trend (hooks for anything that must happen every time, not things you hope the model remembers) and the token-economics trend (cache aggressively; map-then-read) both point at the same fix: a PostToolUse hook on Read that calls cache_store/session_track, and a SessionStart hook that calls cache_warm — turning a manually-invoked tool catalog into transparent infrastructure. Secondary gap: the ‘semantic’ label is now an active falsehood since embeddings left; semantic/hybrid retrieval (the RAG/embedding SOTA) lives entirely in intersearch.

Redundancy: Vector/semantic functionality fully overlaps intersearch (intercache deliberately handed embedding_index/embedding_query to it in v0.2.0; embeddings.py is leftover dead code). Code-reconnaissance/dedup of reads overlaps tldr-swinton (token-efficient code recon, map-then-read). intersearch already names intercache in its store/server/CLAUDE — the split is intentional, but intercache retaining the ‘semantic’ name while owning none of the semantics is the redundancy/confusion risk. No functional overlap with intermem/interknow (those are knowledge/memory, not file-content caching).

Actions:

  • Add a PostToolUse hook (Read/Edit -> cache_store + session_track) and a SessionStart hook (-> cache_warm) in a real hooks.json so the cache fires transparently without agent cooperation — the single change that makes the plugin actually do anything; fix post-commit.sh to genuinely call cache_invalidate instead of echoing.
  • Rename/relabel away from ‘semantic’: update plugin.json description, README title, PHILOSOPHY, and the server.py docstring (which still says ‘embedding search’) to ‘content-addressed cross-session file cache.’ Either re-add a thin semantic layer delegating to intersearch or stop claiming it.
  • Delete dead embeddings.py (confirmed unimported; kept ‘for reference’ in git history already) and fix the session.py docstring that still says ‘JSONL read logs’ when it is now SQLite-WAL.
  • Implement the size-based LRU eviction that CLAUDE.md specifies but admits is unbuilt (‘unbounded growth with manual cache_purge’), so ~/.intercache/blobs does not grow without bound.