Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Releases: fmflurry/code-memory

v0.7.0

12 Jun 13:55
@fmflurry fmflurry

Choose a tag to compare

Release theme: Worktree resilience, atomic graph rebuilds, and fresh indexes. The index now survives interrupted full ingests; linked git worktrees reuse the main repo's index instead of forcing a cold re-ingest; and queries trigger non-blocking background rebuilds when the index drifts from HEAD.

Added — Linked git worktree awareness

What: a new _git_toplevel() helper resolves linked git worktrees to the main repo's root by running git rev-parse --git-common-dir after the baseline --show-toplevel call. In a linked worktree, the two paths differ; in the main worktree, they're the same. The project slug is now derived from the main repo's directory name, so all worktrees of the same project reuse the same Qdrant / Falkor namespace without requiring a cold re-ingest.

Reason: developers working in linked worktrees (e.g. git worktree add ../feature-branch) saw no code-memory functionality because the ingest system minted a separate Qdrant collection and Falkor graph for each worktree. A single repo with 3–5 active worktrees accumulated 3–5 cold ingests. The main repo and each worktree now share the same index.

Added — Non-persistent autostart for linked worktrees

What: two new gates in the autostart system:

  • is_linked_git_worktree(path) — checks whether path is inside a linked worktree via git CLI.
  • is_non_persistent_watch_dir(path) — returns True for ephemeral session dirs OR linked worktrees; used by ensure_autostart() to skip registering a persistent OS agent for directories that are temporary or share the main repo's watcher.
  • LaunchdAdapter.prune_stale() (run on every MCP bootstrap) removes launchd agents whose WorkingDirectory is gone or is a linked worktree.

Reason: the prior release fixed the watcher's per-session accumulation; this release prevents the same bleed on linked worktrees. A developer with 2 linked worktrees no longer gets 3 persistent code-memory watch units.

Added — Shadow-graph atomic promotion (graph durability fix)

What: the full ingest pipeline now builds into a shadow FalkorDB graph named <project_graph>__shadow and atomically promotes it only after the rebuild succeeds:

  1. At ingest start, drop any leftover shadow from a prior interrupted rebuild.
  2. Redirect all graph writes to the shadow FalkorStore instance.
  3. On successful completion, execute GRAPH.DELETE <live>, then GRAPH.COPY <shadow> <live>, then GRAPH.DELETE <shadow>.
  4. If the copy fails, the live graph is cleared but the shadow stays intact — the caller can retry without losing data.

Reason: before this, an interrupted full ingest (network loss, Ollama timeout, Falkor down, user kills the process) left the live graph empty so subsequent callers / definitions / callees queries returned nothing until a manual full re-ingest. The graph now survives interruption — the shadow is cleaned up on the next rebuild attempt.

Added — Health-check guard for stale rebuilds

What: the ingest state now records file_count and symbol_count from each successful full rebuild. Before starting an incremental ingest, _health_check_ok() compares the current ingestable file count against the stored baseline; if it grew more than 20% and the graph symbol count is suspiciously low (below a ratio threshold), a full rebuild is forced with a diagnostic message to stderr.

Config:

  • CODE_MEMORY_INGEST_HEALTH_CHECK_ENABLED (default true)
  • CODE_MEMORY_INGEST_HEALTH_CHECK_MIN_RATIO (default 0.3 = expect ≥30% of file count as symbol count)

Reason: a transient FalkorDB outage or an incomplete prior ingest could leave the graph permanently empty while incremental ingests reported success. The health check detects this silently-failed state and forces a rebuild, with no user intervention needed.

Added — Single-flight ingest lock

What: new src/code_memory/sync/single_flight.py module provides in-process (asyncio.Lock) + cross-process (PID file) guards to prevent concurrent full ingests for the same (root, project) pair.

  • try_acquire(root, project) — returns True if no rebuild is running, False if the slot is taken.
  • release(root, project) — releases the slot unconditionally.
  • Stale PID files (dead process or age > 30 min) are silently removed.

The Claude Code and Cursor plugins' on-session-start.js fast-path-skip a spawn when a live ingest is detected, preventing thundering-herd code-memory ingest calls on boot.

Reason: on slow machines or large repos, overlapping code-memory ingest calls could queue up and queue up (especially if the embedder is I/O-bound), causing a session to take 5+ minutes to boot. The lock ensures at most one rebuild runs; fast-path skips spare the overhead.

Added — Ingest safety guards

What: new assert_safe_ingest_root() function in sync/safety.py refuses to ingest:

  1. System/HOME roots (same set as the watcher guard: HOME, /, /tmp, /var, /etc, /usr, /System, /Library, /opt, /Applications, C:/, etc.)
  2. Non-git directories (checked via is_inside_git_worktree()).

Bypass via CODE_MEMORY_UNSAFE_INGEST=1 env var (env-only, not a CLI flag, to prevent accidental use).

Reason: code-memory ingest ~ could walk every IDE cache, checkout, and node_modules on disk. ingest is more dangerous than watch because it stores results; a non-git directory ingest mints an arbitrary project slug. The guard is invoked by the CLI ingest entry point and by hooks.

Added — IPv4-default service URLs

What: the default OLLAMA_URL, QDRANT_URL, and FALKOR_URL now use 127.0.0.1 instead of localhost. This works around a Windows quirk where localhost may resolve to ::1 (IPv6) and hang on socket connect.

Config example (all in .code-memoryrc or env):

OLLAMA_URL=http://127.0.0.1:11434
QDRANT_URL=http://127.0.0.1:6333
FALKOR_URL=redis://127.0.0.1:6379

Reason: on some Windows setups, the TCP stack prefers IPv6 and binds localhost to ::1, while the service listens on 127.0.0.1. Callers then hang waiting for a timeout (seconds to minutes). Using the explicit IPv4 address is more reliable.

Added — Non-blocking _ensure_fresh for MCP queries

What: the pre-query guard _ensure_fresh() no longer blocks on a sync. Instead:

  1. Spawn a quick freshness check (_is_index_stale()) in a bounded daemon thread (_FRESHNESS_PROBE_TIMEOUT, default 2.0 s).
  2. If the index is stale AND the check finished in time, fire a background _background_rebuild() in a detached daemon thread protected by the single-flight lock.
  3. Return immediately so the query gets the current (possibly stale) index while the rebuild runs in the background.

Reason: MCP queries were blocking on a full ingest in the worst case, causing Claude Code / OpenCode / Cursor to hang for minutes. Now the agent gets an answer immediately while background sync keeps the index fresh.

Fixed — Ollama embed connect timeout

What: OllamaEmbedder now uses split connect/read timeouts:

  • _DEFAULT_CONNECT_TIMEOUT = 5.0 s — fail fast on wrong stack (IPv6 vs IPv4) or misconfigured host.
  • _DEFAULT_READ_TIMEOUT = 300.0 s — Ollama's cold-load model phase happens during read, not connect.

Configurable via OLLAMA_CONNECT_TIMEOUT and OLLAMA_READ_TIMEOUT env vars.

Reason: the old single timeout=300 param applied to connect, which could hang for 300 s waiting on a misconfigured IPv6 address. A 5 s connect timeout with 3 retries fails fast (~15 s worst case) instead.

Added — Vibe plugin

What: new plugins/vibe/ brings code-memory to Mistral Vibe. Vibe lacks lifecycle hooks (unlike Claude Code, Cursor, OpenCode), so the plugin delivers:

  • Skill (/code-memory) with orientation guidance and manual command runner.
  • MCP server registration in config.toml.
  • OS autostart watcher for file-edit → auto-reingest (since hooks aren't available).

Install: ./plugins/vibe/install.sh (default user scope, with flags for project scope, no-mcp, no-watch, uninstall).

Reason: Vibe is a code-aware LLM editor with a different extension model. Bundling the same code-memory integration surfaces our topology queries to Vibe users without reimplementation.

Added — Ingest state enhancements

What: the ingest state now stores:

  • file_count / symbol_count from each full rebuild (used by the health check).
  • file_count and symbol_count are populated by the pipeline during ingest and read by the health-check predicate before deciding to rebuild.

Reason: enables the health-check guard to detect silently-failed ingests.

Assets 2
Loading

v0.5.3 — git credential prompts no longer freeze the MCP server

04 Jun 13:01
@fmflurry fmflurry

Choose a tag to compare

Release theme: git operations never block on credentials.

Fixed — Interactive git credential prompts froze the MCP server

The snapshot store talked to origin with plain git fetch / git push and nothing to suppress interactive auth. On any HTTPS remote without cached credentials this:

  • froze the MCP server at boot — the synchronous sync_repo(trigger="mcp-boot", fetch=True) hung on a git fetch waiting for a password the stdio server could never supply, so OpenCode reported the server as not running;
  • re-prompted on every code-memory status and on every watcher quiet-period sync.

Fix: every best-effort / read git call in SnapshotStore now runs with GIT_TERMINAL_PROMPT=0, GIT_SSH_COMMAND=ssh -oBatchMode=yes, and an empty -c credential.helper=. GIT_TERMINAL_PROMPT=0 alone is insufficient — a configured credential helper (e.g. Git Credential Manager) is a separate program git still launches and pops its own dialog; resetting the helper list makes git return in ~0.1s instead of waiting on a human. Only the explicit publish path (push during snapshot publish / gc) opts back into credentials via allow_credentials=True, so opted-in remotes still authenticate.

Loading

v0.5.2 — watcher leak fix + semantic claim dedupe

30 May 00:11
@fmflurry fmflurry

Choose a tag to compare

Fixed

  • Unbounded launchd watcher accumulation. MCP boot no longer registers a permanent KeepAlive agent for ephemeral/per-session dirs (~/.claude/homunculus/*, .cursor/worktrees/*, plugins/cache/*). New prune_stale runs on every bootstrap and removes agents whose target dir is gone or ephemeral, self-healing existing cruft. (launchd-only for now; systemd/schtasks GC is a follow-up.)
  • Graceful watcher teardown. MCP server now stops the watcher via atexit + SIGTERM so the watchdog Observer flushes and joins instead of dying mid-debounce.

Added

  • Semantic dedupe of near-duplicate claims. Paraphrastic claims (cosine ≥ CLAIMS_SEMANTIC_DEDUP_THRESHOLD, default 0.90) collapse into the closest open claim instead of inserting duplicate rows. Set ≥ 1.0 to disable.

Also includes prior untagged work: Cursor harness integration + installer improvements.

Update: code-memory update

Loading

v0.5.1 — updater bugfixes

27 May 18:30
@fmflurry fmflurry

Choose a tag to compare

Bugfix release — code-memory update actually works now

The first real run of code-memory update --check against a machine carrying the pre-rename code-memory dist (uv-tool installs from before the PyPI rename) surfaced four bugs. All fixed:

  1. CLI version fell back to 0.0.0+local__init__.py only queried flurryx-code-memory. Legacy installs have dist name code-memory. Now tries both.
  2. uv tool upgrade flurryx-code-memory failed — uv-tool registers tools by entry-point name (code-memory), not package name. Now uses uv tool install --reinstall --force --from <src> code-memory — also migrates legacy dist cleanly.
  3. claude plugin install ... --force rejected--force no longer a valid flag. Switched to claude plugin update <name> with a graceful install-fallback.
  4. Docker stack reported "no compose / docker" on dev installs whose compose file lives in the repo, not ~/.code-memory/. Updater now probes cm-falkordb / cm-qdrant for the com.docker.compose.project.config_files label.

Upgrade

code-memory update

If you're on 0.5.0 and it errors out on the CLI step, run the one-liner installer once to migrate to 0.5.1 — from there onward update is self-sufficient:

curl -fsSL https://raw.githubusercontent.com/fmflurry/code-memory/main/install.sh | bash

PyPI: https://pypi.org/project/flurryx-code-memory/0.5.1/

Loading

v0.5.0 — smart `code-memory update` CLI

27 May 17:27
@fmflurry fmflurry

Choose a tag to compare

Highlights

code-memory update — smart, idempotent updater. No more re-running the one-liner just to bump the CLI.

code-memory update # smart refresh
code-memory update --check # dry-run; exit 1 if behind
code-memory update --full # re-run the one-liner installer
code-memory update --bleeding # CLI from git+main

How it differs from re-running the installer

  • Detects install method (uv tool / pipx / pip / editable) via sys.prefix + PEP 610 direct_url.json.
  • Refreshes only what's already installed locally:
    • CLI via the same channel
    • Docker stack only if ~/.code-memory/docker/docker-compose.yml exists or containers run
    • Ollama models only if already in ollama list (so no surprise gemma2:9b re-prompt)
    • Claude Code plugin + OpenCode npm pkg only when registered
  • Pieces you opted out of stay untouched — no re-prompting.

Other changes

  • New code-memory --version / -V flag (README claimed it; it was missing).
  • __version__ now resolved from importlib.metadata (no more stale 0.1.0).
  • README: attention banner under ## Installation + new ## Updating section + jump link.

Install / Update

# Existing users:
code-memory update
# Fresh install (unchanged):
curl -fsSL https://raw.githubusercontent.com/fmflurry/code-memory/main/install.sh | bash

PyPI: https://pypi.org/project/flurryx-code-memory/0.5.0/

Loading

v0.4.0 — Live ingest progress + PyPI + PHP

27 May 15:34
@fmflurry fmflurry

Choose a tag to compare

What's new in v0.4.0

Published to PyPI as flurryx-code-memory (the bare code-memory name was already taken on PyPI by another project). The Python import path is unchanged: from code_memory import ....

Highlights

  • Live ingest progress — new ingest-watch CLI plus rich TUI progressbar; MCP clients receive notifications/progress for in-chat feedback during long ingests.
  • Zero-clone installer — one-liner install for macOS / Linux / Windows; no git clone required.
  • PHP language support — extractor now covers PHP alongside the existing TS/JS/Python/Go/C#/etc.
  • MCP ingest steeringcodememory_ingest is now disabled by default and steers agents to the streaming Bash CLI, so progress is actually visible in the host UI.
  • Health endpoint fix/health now reports the real graph node count instead of always returning 1 (aggregate-row counting bug).
  • Metrics + resilience — tool-call tracking, efficiency measurement, retry/backoff hardening across backends, BGE-M3 standardised, harmful rerank removed.
  • Auto-watcher plugin — installs as a session-start hook for Claude Code and OpenCode, so the index stays fresh without manual ingest calls.

Fixes

  • Correct relative imports in health module (was triggering package-escape error).
  • sync now propagates uncommitted file deletions to both the graph and vector index.
  • metrics.db falls back to data/ when CODEMEMORY_METRICS_DB is unset.

Install

pip install flurryx-code-memory
# or zero-clone installer:
curl -fsSL https://raw.githubusercontent.com/fmflurry/code-memory/main/scripts/install.sh | bash

Full changelog: v0.2.0...v0.4.0

Loading

v0.2.0 — Snapshots: ingest once, sync everywhere

25 May 17:37
@fmflurry fmflurry

Choose a tag to compare

Release theme: enterprise-grade ingest, full features, no quality tradeoffs.

Headline

Snapshots: ingest once, sync everywhere. Build the index once on a fast machine (code-memory ingest --full && code-memory snapshot publish), distribute via a dedicated git branch, every other developer runs code-memory sync and pulls full state (vectors + graph + episodic) in seconds. Verified end-to-end: 0.5 s when the snapshot matches HEAD; 0.9 s when HEAD is one commit ahead (auto-applies snapshot + runs incremental delta). The cold-ingest cost moves from "every dev on every clone" to "once per merge in CI".

Key changes

Added

  • Snapshot publish/sync end-to-end workflow.
  • REFERENCES edge type for C# type-position usage — callers IFoo now returns implementations, parameter-type users, and generic-arg sites.
  • Canonical import aliasing for Python relative imports — importers <module> catches every form (relative and absolute).
  • Persistent content-hash embedding cache×ばつ warm re-ingest (55.7 s → 2.9 s on this repo), full features.
  • TEI backend (EMBED_BACKEND=tei) — ×ばつ cold ingest on Linux + NVIDIA, same bge-m3 weights, identical recall.
  • --no-vectors ingest flag for graph-only workloads.
  • Auto-resolved embed_dim from model name (no more silent dim mismatches).
  • Claim entity resolution + retrieve-pack surfacing + OpenCode plugin parity (Graphiti-style fact memory).

Fixed

  • Snapshot hybrid-vector round-trip. _dump_vectors used to silently discard embeddings when Qdrant returned the hybrid layout. The feature was non-functional in shipping code; now it actually round-trips. 8 new e2e tests prevent regression.

Performance

  • UNWIND-batched Falkor upserts: ~50 round-trips → ~3 per file. ×ばつ faster graph layer.
  • Cross-file embedding batches + pipelined Qdrant upserts (2-worker thread pool).

Docs

  • Honest README throughout. The "How code-memory scores vs rg" hero callout cites measured numbers from the shipped benchmark queries. The Performance & scale section documents three real unlock paths (snapshots, cache, TEI) and an "Honest limits today" subsection that names what isn't on the roadmap.

Removed

  • Private app-name references purged from current tree and full 53-commit git history (force-pushed). Anyone with an existing clone needs to delete and re-clone — SHAs are orphaned.

Compat note

git push --force was used to rewrite history. Existing clones will not git pull cleanly. Re-clone fresh:

git clone git@github.com:fmflurry/code-memory.git

Full changelog

See CHANGELOG.md.

Loading

AltStyle によって変換されたページ (->オリジナル) /