{"id":"8d48dd20-041e-47bd-8ae4-188a6fe13a2f","slug":"codevira","kind":"mcp","name":"codevira","summary":"Stop re-explaining your project to AI agents every session. One memory layer for Claude Code, Cursor, Windsurf, Antigravity — local, MIT, no signup.","owner":"sachinshelke","repoUrl":"https://github.com/sachinshelke/codevira","license":"MIT","licenseTier":"permissive","trust":"community","stars":12,"match":null,"fewStars":false,"format":"mcp","createdAt":"2026-03-06T01:09:49.000Z","addedAt":"2026-10-14T05:20:55.392Z","logoUrl":"https://avatars.githubusercontent.com/u/869601?u=cfca4ee4c7dedb8af66191a98fc6635aea9ac525&v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["memory-knowledge","developer-tools","search"],"tags":["ai-agents","antigravity","claude-code","coding-assistant","cursor","developer-tools","knowledge-graph","memory"],"runtime":"python","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-20T18:52:59.255Z","sample":false,"url":"https://conduits.dev/tools/codevira","language":"Python","transports":["stdio"],"install":{"pypi":"codevira"},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"<p align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/sachinshelke/codevira/main/website/assets/logo.png\" alt=\"Codevira logo — persistent memory for AI coding agents\" width=\"140\" height=\"140\">\n</p>\n\n<h1 align=\"center\">Codevira — persistent memory and decision enforcement for AI coding agents</h1>\n\n<p align=\"center\"><strong>Stop re-explaining your codebase to every AI tool — and stop the next agent from undoing the fix that took you three hours.</strong></p>\n\n<p align=\"center\">\n<a href=\"https://pypi.org/project/codevira/\"><img src=\"https://img.shields.io/pypi/v/codevira?color=orange\" alt=\"PyPI version\"></a>\n<a href=\"https://pypi.org/project/codevira/\"><img src=\"https://img.shields.io/pypi/pyversions/codevira?color=blue\" alt=\"Python versions\"></a>\n<a href=\"https://github.com/sachinshelke/codevira/actions/workflows/ci.yml\"><img src=\"https://github.com/sachinshelke/codevira/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\"></a>\n<a href=\"https://pepy.tech/project/codevira\"><img src=\"https://static.pepy.tech/badge/codevira\" alt=\"Downloads\"></a>\n<a href=\"https://github.com/sachinshelke/codevira/blob/main/LICENSE\"><img src=\"https://img.shields.io/badge/license-MIT-green\" alt=\"License: MIT\"></a>\n<a href=\"https://modelcontextprotocol.io\"><img src=\"https://img.shields.io/badge/protocol-MCP-purple\" alt=\"Model Context Protocol\"></a>\n<a href=\"https://github.com/sachinshelke/codevira/blob/main/CONTRIBUTING.md\"><img src=\"https://img.shields.io/badge/PRs-welcome-brightgreen\" alt=\"PRs welcome\"></a>\n</p>\n\n<p align=\"center\">\n<a href=\"#quick-start\"><strong>Quick Start</strong></a> &nbsp;·&nbsp;\n<a href=\"#see-it-in-action-record-block-recall\">See it in action</a> &nbsp;·&nbsp;\n<a href=\"#reference\">Reference</a> &nbsp;·&nbsp;\n<a href=\"https://github.com/sachinshelke/codevira/blob/main/docs/vs-other-memory-tools.md\">vs. other memory tools</a> &nbsp;·&nbsp;\n<a href=\"https://github.com/sachinshelke/codevira/blob/main/FAQ.md\">FAQ</a> &nbsp;·&nbsp;\n<a href=\"https://sachinshelke.github.io/codevira/\">Website</a>\n</p>\n\nCodevira is a **local-first MCP server** ([Model Context Protocol](https://modelcontextprotocol.io))\nthat gives every AI coding agent on your machine **one shared, in-repo memory** of the decisions\nyou've made and *why*. What one tool learns, all of them know — and a decision you lock, **none of\nthem can silently undo:** codevira refuses the edit in Claude Code and the commit in any editor.\n\n```bash\npipx install codevira              # ~66 MB pipx venv, no ML deps, no vectors\ncd ~/Projects/my-project\ncodevira init                      # opt this project in\ncodevira setup                     # wire it into the AI tools on this machine\n```\n\n|  |  |\n|---|---|\n| **What it is** | A local MCP server that stores your project's decisions **together with the reasoning behind them**, in your repo. |\n| **What's different** | It doesn't just remember — mark a decision `do_not_revert` and it **physically blocks the edit** (Claude Code) and, once you install the git hook, **the commit** (any editor) that would undo it. |\n| **Who it's for** | Anyone running two or more AI coding tools on the same repo. |\n| **Default scope** | Per-machine — memory is not git-tracked. `codevira init --shared` commits `.codevira/` so teammates on the same repo share one decision log. |\n| **Cost** | MIT · local-first · no cloud · no account · no vectors · nothing phones home. |\n\n<p align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/sachinshelke/codevira/main/website/assets/claude.svg\" height=\"26\" alt=\"Claude Code\">&nbsp;&nbsp;&nbsp;\n  <img src=\"https://raw.githubusercontent.com/sachinshelke/codevira/main/website/assets/cursor.png\" height=\"26\" alt=\"Cursor\">&nbsp;&nbsp;&nbsp;\n  <img src=\"https://raw.githubusercontent.com/sachinshelke/codevira/main/website/assets/antigravity.png\" height=\"26\" alt=\"Google Antigravity\">&nbsp;&nbsp;&nbsp;\n  <img src=\"https://raw.githubusercontent.com/sachinshelke/codevira/main/website/assets/codex.png\" height=\"26\" alt=\"OpenAI Codex\">&nbsp;&nbsp;&nbsp;\n  <img src=\"https://raw.githubusercontent.com/sachinshelke/codevira/main/website/assets/copilot.svg\" height=\"26\" alt=\"GitHub Copilot\">&nbsp;&nbsp;&nbsp;\n  <img src=\"https://raw.githubusercontent.com/sachinshelke/codevira/main/website/assets/mcp.svg\" height=\"26\" alt=\"Model Context Protocol\">\n</p>\n<p align=\"center\"><sub>Claude Code · Claude Desktop · Cursor · Google Antigravity · OpenAI Codex · GitHub Copilot · any MCP-compatible AI tool</sub></p>\n\n<p align=\"center\">\n<strong>30-second demo:</strong>\n<a href=\"https://github.com/sachinshelke/codevira/blob/main/docs/demo/codevira-demo.mp4\">MP4</a> ·\n<a href=\"https://github.com/sachinshelke/codevira/blob/main/docs/demo/codevira-demo.webm\">WebM</a> ·\n<a href=\"https://github.com/sachinshelke/codevira/blob/main/docs/demo/index.html\">offline HTML player</a> (no network, after cloning)\n</p>\n\n<details open>\n<summary><strong>The whole thing on one page</strong> — solution blueprint</summary>\n\n<br>\n\n<p align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/sachinshelke/codevira/main/website/assets/blueprint.png\"\n       alt=\"Codevira solution blueprint: persistent memory and decision enforcement for AI coding agents. Four levels — remember, surface, warn, block. Capabilities include decision memory, cross-tool sync, session context, code graph, enforcement engine, anti-regression, skill library and working memory. Works with Claude Code, Claude Desktop, Cursor and Antigravity over MCP, and with Codex and Copilot via AGENTS.md.\"\n       width=\"100%\">\n</p>\n\n</details>\n\n---\n\n## Why Codevira\n\nAI agents write a large share of your code now. They're fast and capable, but each one is\n**stateless across sessions and blind to the others** — so *you* quietly became the memory.\n\n| The pain | What Codevira does |\n|---|---|\n| **Re-explaining your codebase every session** — ten minutes and thousands of tokens, then again tomorrow | Every tool opens with the project's decisions already loaded |\n| **An agent \"simplifies\" a fix it never knew the reason for** — three hours of debugging, undone | A locked decision is refused at the edit (Claude Code) and at the commit (any editor), with the original reasoning attached |\n| **Cross-tool amnesia** — plan in Claude Code, code in Cursor, nothing carries over | One in-repo memory every MCP client reads |\n| **Token budget burned on re-discovery** — the same dozen files re-read every session | Summary-first recall of only what's relevant |\n\nThe root cause under all four: **your decisions live in your head, not anywhere the AI can be\nheld to them.**\n\n> **Codevira is not a knowledge base.** A knowledge base answers *\"what is true?\"* and hopes the\n> agent reads it. Codevira answers *\"what did we decide, and why?\"* — then blocks the edit that\n> would break it.\n\n---\n\n## See it in action: record, block, recall\n\n**1. You (or the AI) record a decision — one MCP call, ~50 tokens.**\n\n```text\nrecord_decision(\n  decision=\"Use bcrypt for password hashing\",\n  context=\"md5 considered and rejected — rainbow-table risk. Re-examine only if NIST guidance changes.\",\n  tags=[\"auth\", \"security\"],\n  do_not_revert=true,\n)\n→ D000412 recorded and locked.\n```\n\nIt lands in `<repo>/.codevira/decisions.jsonl` — plain text, human-readable, and diffable (and\ngit-tracked as soon as you run `codevira init --shared`). Codevira regenerates a slim `AGENTS.md`\ncontract from it — that file is always committed.\n\n**2. Weeks later, a fresh Claude Code session tries to swap bcrypt for md5.**\n\nThe `Edit` goes through Claude Code's `PreToolUse` hook first. Because the diff touches the\nlocked decision's subject, the hook **denies the tool call** and hands the agent the original\nreasoning:\n\n```text\n✗ Edit blocked — decision_lock (do_not_revert)\n  D000412: \"Use bcrypt for password hashing\"\n  context: md5 rejected — rainbow-table risk.\n  The file was not modified. Surface this to the human and re-decide deliberately.\n```\n\nThe regression never reaches disk. An orthogonal edit to the same file — one whose diff doesn't\ntouch the decision's subject — is *allowed* through and downgraded to a warn. Precision, not\nparanoia.\n\n**3. You switch to Cursor the next morning — and it already knows.**\n\nYou never re-explained anything. Cursor reads the same repo `AGENTS.md` and, over MCP, can call\n`search_decisions(\"auth\")` — D000412 comes back with its full context. A decision recorded in\none tool is visible to every tool.\n\n> **Where the block is physical.** Edit-time in Claude Code; commit-time in *every* editor via\n> `codevira engine install-git-hook` — because they all commit with git. Overrides, kill-switches\n> and the precise boundary: [Enforcement engine](#enforcement-engine) (expand).\n\n<details>\n<summary><strong>The whole path, in one diagram</strong> — record → violate → intercept → engine → refuse</summary>\n\n<br>\n\n<p align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/sachinshelke/codevira/main/website/assets/enforcement-flow.png\"\n       alt=\"Enforcement flow: record_decision appends to decisions.jsonl; weeks later an agent edits a covered file; the edit is intercepted at Claude Code PreToolUse or at git pre-commit; one dispatch() runs 7 prioritised policies; the refusal carries the original reasoning. Fails open, with kill switches.\"\n       width=\"100%\">\n</p>\n\n</details>\n\n---\n\n## What you get\n\n| | What it means |\n|---|---|\n| **One memory, every AI tool** | A decision logged in Claude Code is visible to Cursor, Antigravity, Codex, Copilot — all read the same `.codevira/decisions.jsonl` and generated `AGENTS.md`. No per-tool re-onboarding, no cloud sync. |\n| **Enforcement, not notes** | `do_not_revert` refuses the edit in Claude Code and refuses the commit in any editor. An Anti-Regression guard also blocks re-introducing a previously-fixed bug. Every guard ships a warn/off kill-switch. |\n| **One-command setup** | `codevira setup` detects installed AI tools via strong signals (binary on PATH + valid config file) and configures only what's actually there. `--force` overrides a missed detect. |\n| **Local-first, no ML** | Decision search is pure keyword/BM25 over SQLite FTS5 — no vectors, no ChromaDB, no sentence-transformers, no torch, nothing phones home. ~1–2 MB of memory per project. |\n| **Frugal by design** | Tools return summaries by default; `get_session_context()` is one ~500-token call; the server cold-starts in well under a second with no ML model to load. |\n| **Concurrent-safe** | Every write is a crash-safe atomic write behind a Posix `fcntl.flock`, so two IDEs on one project don't race. [Details](#concurrency--safety) (expand) |\n\n<sub><strong>Latest: 4.2.0.</strong> Upgrade if you use codevira in more than one project: a stray registration at <code>$HOME</code> could make <code>register-all</code> discover exactly one project and discard every real one as &ldquo;nested&rdquo; (measured on a real machine: 1 found, 11 excluded). 4.2.0 also stops background work writing false entries to the crash log &mdash; 39 of 45 entries on that machine were one harmless line &mdash; and adds <code>codevira reconcile</code> to report duplicate and contradicting decisions. Upgrading is automatic, <strong>but a registration that was already wrong is not repaired for you</strong>: run <code>codevira register-all</code> once after upgrading to recover projects that went missing. <a href=\"https://github.com/sachinshelke/codevira/blob/main/CHANGELOG.md\">Full release notes &rarr;</a></sub>\n\n---\n\n## Quick Start\n\n```bash\n# 1. Install (production install: ~66 MB pipx venv, no ML deps)\npipx install codevira\n\n# 2. Opt this project in (writes .codevira/, AGENTS.md, .gitignore)\ncd ~/Projects/my-project\ncodevira init\n\n# 3. Wire codevira into every AI tool detected on this machine\ncodevira setup\n\n# 4. Install the universal commit-time backstop (enforces do_not_revert in ANY editor)\ncodevira engine install-git-hook\n```\n\nStep 4 is what makes enforcement universal. `codevira init` installs only a `post-commit`\nreindex hook; the **enforcing** `pre-commit` hook is this separate, explicit opt-in.\n\nOpen any IDE — codevira's MCP server is ready. **Then, in your AI tool, ask:**\n*\"Use `get_session_context` to brief me on this project.\"* You get a ~500-token structured\nproject state in one tool call instead of the AI re-reading docs.\n\n**Verify the install:**\n\n```bash\ncodevira doctor          # health checks: ✓/⚠/✗ + a fix command for each\ncodevira replay          # browse the decisions timeline\ncodevira sync            # regenerate AGENTS.md from current decisions.jsonl\n```\n\n**Team sharing.** By default codevira keeps decision memory **per-machine** (not committed), so\nunrelated projects never bleed into each other; `AGENTS.md` and `.gitignore` are still committed.\nTo share memory with teammates on the same GitHub repo, run `codevira init --shared` — it keeps\n`.codevira/` git-tracked, and a built-in git merge driver reconciles concurrent edits.\n\n> **Opt-in tracking.** `codevira init` is the explicit opt-in. Codevira tracks **only** projects\n> you've `init`-ed; a project you merely open stays inert (its tools return a \"run `codevira init`\"\n> hint and nothing is written), so `~/.codevira/projects/` never fills with projects you didn't\n> choose. Set `CODEVIRA_AUTO_ADOPT=1` to track every project you open instead.\n\n---\n\n## How it works\n\nA local MCP server. Decisions live in `<repo>/.codevira/*.jsonl` — plain text, human-readable,\ndiffable, and git-tracked once you opt in with `init --shared`. A slim `AGENTS.md` is generated\nfrom them for every IDE to read, and Claude Code lifecycle hooks — plus the opt-in git\n`pre-commit` hook — enforce the ones you locked.\n\n<p align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/sachinshelke/codevira/main/website/assets/architecture.png\"\n       alt=\"Codevira architecture: AI tools connect over stdio MCP to one codevira process per project; canonical decision memory lives in the repo under .codevira/, a per-machine cache in .codevira-cache/, and cross-project state in ~/.codevira/\"\n       width=\"100%\">\n</p>\n\n<details>\n<summary><strong>Full file layout and hook flow</strong></summary>\n\n<br>\n\n<p align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/sachinshelke/codevira/main/website/assets/file-layout.png\"\n       alt=\"Codevira file layout and hook flow: three stacked layers. In the project repo, .codevira/ holds decisions.jsonl, digest.jsonl, outcomes.jsonl, manifest.yaml, enforcement.yaml, config.yaml, sessions.jsonl, roadmap.yaml and skills.jsonl; AGENTS.md is generated from it; .codevira-cache/ holds fts5.sqlite, hash-cache.db and working.jsonl and is gitignored; the code graph is a per-project SQLite db under ~/.codevira/, not in your repo. Below it, one pipx-installed codevira binary (CLI plus MCP server, ~66 MB venv, no chromadb, sentence-transformers or torch, no model, cold-start well under 1 s, warm tool calls ~2 ms), reached over MCP and hooks. Below that, your IDE and its four hook points: UserPromptSubmit into a relevance-gated inject, Edit or Write into PreToolUse which blocks if a do_not_revert decision is violated, PostToolUse into the Post-Edit Graph Refresh and working-memory fanout, and Stop into the Token Budget and Session-Log Enforcer.\"\n       width=\"100%\">\n</p>\n\n`codevira init` scaffolds everything above except `roadmap.yaml` and `skills.jsonl`, which are\nwritten on first use. Deeper detail: [`docs/architecture.md`](https://github.com/sachinshelke/codevira/blob/main/docs/architecture.md).\n\n</details>\n\n---\n\n## Built to be trusted\n\nCodevira holds a team's architectural decisions and can refuse your AI's edits. Every guarantee\nbelow is checked by the build, not asserted in this file.\n\n| | |\n|---|---|\n| **Test suite** | **3,499 tests** across 165 test files. More test code than product code (60,960 vs 46,782 lines). |\n| **CI** | Every push to `main` and every pull request runs the suite on **Python 3.10 / 3.11 / 3.12 / 3.13**, plus a separate random-order run (collection-order blindness had hidden real state-leak bugs) and a `mypy` type-check job. |\n| **\"Local-first\" is enforced, not promised** | [`tests/test_egress_boundary.py`](https://github.com/sachinshelke/codevira/blob/main/tests/test_egress_boundary.py) walks the import graph of the shipped package with an AST scan and **fails the build** if any module other than `egress.py` imports a network client. |\n| **Adversarial testing** | [`scripts/chaos_smoke.py`](https://github.com/sachinshelke/codevira/blob/main/scripts/chaos_smoke.py) runs 8 hostile scenarios — SIGKILL during a held lock, symlink traversal, malformed MCP payloads, corrupt-JSONL degradation, read-only directories. |\n| **No destructive MCP tools** | Every MCP tool carries `destructiveHint=false`. The only destructive operations (`reset`, `uninstall`) are CLI-only and require a typed confirmation — an autonomous agent cannot reach them. |\n| **Reversible memory** | After a default `init`, `.codevira/` is not git-tracked — so `git revert` can't undo a bad migration or an accidental wipe. `codevira memory snapshot` + `codevira memory undo` can, and the undo is itself undoable. |\n\n---\n\n## What's solid, what's not\n\n| Production-stable | Known-limited |\n|---|---|\n| Cross-IDE decision memory via in-repo JSONL | Hard `PreToolUse` enforcement at **edit time** is Claude Code only; other IDEs read `AGENTS.md` (advisory) and are backstopped at the commit boundary |\n| `do_not_revert` enforced at the Claude Code hook **and**, in any editor, at the commit boundary (`codevira engine install-git-hook`) | Graph tools cover Python / TS / JS / Go / Rust; other languages → the AI `Read`s the file directly |\n| FTS5/BM25 decision search | Real-time multi-machine sync — by design local-first; for team sharing, run `codevira init --shared` |\n| Per-project + cross-machine project inventory (`global.db`) | No web UI — use the `codevira://decisions` MCP resource, or `codevira replay --format html` |\n| 36 MCP tools advertised in `tools/list` (37 defined — `refresh_graph` is hidden) + 26 CLI commands + 7 engine policies | The HTTP server (`codevira serve`) is single-project per launch — for daily use, stick with stdio |\n| Concurrent-safe storage (Posix `fcntl.flock` + Windows sentinel), thread + subprocess + chaos-tested | Windows sentinel fallback is verified in unit tests but not yet load-tested on real Windows |\n| Anti-Regression on small `Edit`/`MultiEdit` hunks | Anti-Regression does not yet detect full-file `Write` reverts; accuracy depends on `fix:` commit hygiene |\n\n---\n\n# Reference\n\nEverything below is depth for when you need it. Each section is collapsed — open the one you came\nfor. **Browser find-in-page does not search inside a closed section, so expand before Ctrl+F.**\nWhat's in them:\n\n```text\nCLI      init setup doctor status projects untrack index sync repair-ids observe-git\n         replay search graph memory export import engine prune reset uninstall serve\n         working induce-skills eval register-all merge-driver\nEnv      CODEVIRA_ENGINE  CODEVIRA_TOOL_PROFILE  CODEVIRA_DECISION_LOCK_MODE\n         CODEVIRA_ANTI_REGRESSION_MODE  CODEVIRA_BLAST_RADIUS_MODE  CODEVIRA_GIT_HOOK_MODE\n         CODEVIRA_DECISION_LOCK_CONTENT_AWARE  CODEVIRA_SESSION_LOG_ENFORCER_MODE\n         CODEVIRA_AUTO_ADOPT  CODEVIRA_IDE\n```\n\n## MCP tool surface\n\n<details>\n<summary><strong>36 tools advertised (37 defined) — the lean-12 profile, every read/write tool, and what 4.0 removed</strong></summary>\n\n<br>\n\n**36 tools** are advertised to AI clients via `tools/list` (**37 are defined** — a 37th,\n`refresh_graph`, is registered but hidden; humans invoke it via `codevira sync`). Every tool\ncarries MCP `ToolAnnotations` (`readOnlyHint` / `destructiveHint=false` / `idempotentHint`): most\nare read-only and can run without a confirmation prompt, and **no MCP tool is destructive** — the\nonly destructive ops (`reset` / `uninstall`) are CLI-only, never exposed over MCP. Good to know\nfor anyone wiring codevira into an autonomous agent.\n\nThe **lean 12** (`CODEVIRA_TOOL_PROFILE=lean`) are the ones you keep — set that in the MCP\nserver's `env` block to cut `tools/list` from 36 tools to 12, roughly a two-thirds smaller\npayload (~8.9K → ~3.5K tokens of fixed per-session cost). Hidden tools still work when called\nexplicitly.\n\n```text\nget_session_context · get_impact · get_node · get_roadmap · search_decisions\nlist_decisions · expand · record_decision · update_phase_status\ncomplete_phase · update_next_action · write_session_log\n```\n\n**Reads — the memory surface**\n\n| Tool | Description |\n|---|---|\n| `get_session_context` | **THE \"catch me up\" call.** ~500 tokens: current phase, next action, recent decisions, top tags, last session brief. |\n| `search_decisions(query)` | FTS5/BM25 over `decisions.jsonl`. Top 5 truncated by default; `full=true` / `summary_only=true`. `all_projects=true` searches every registered repo, tagging each result with its project. |\n| `expand(ids=[…])` | Fetch full records for just the ids you care about — the summary-first complement to `search_decisions` / `list_decisions`. Read-only; in the lean 12. |\n| `list_decisions` | Paginate / filter: `since_date`, `file_pattern`, `protected_only`, `tags`, `include_superseded`. |\n| `list_tags` | All tags with decision counts. |\n| `get_history(file_path)` | Recent decisions touching a file. |\n| `check_conflict(decision_text)` | Surface duplicate / contradictory decisions BEFORE you write. |\n\n**Writes — capturing decisions**\n\n| Tool | Description |\n|---|---|\n| `record_decision` | Capture a decision. `do_not_revert=true` triggers Claude Code `PreToolUse` enforcement; `symbol=\"login\"` scopes the lock to one function/class. It **supersedes** a strong unprotected near-duplicate instead of appending a twin. |\n| `supersede_decision(old_id, new_decision, reason)` | Retire an old decision, link to its replacement, keep the audit trail. |\n| `mark_decision_outdated(decision_id, reason)` | Retire a decision that's simply no longer true (no successor) so it stops surfacing. Reversible via `set_decision_flag`. `do_not_revert` needs `force=True`. |\n| `reaffirm_decision(decision_id)` | Re-confirm a soft-expired `do_not_revert` lock. |\n| `set_decision_flag(decision_id, …)` | Toggle `do_not_revert` / tags / `is_outdated`. |\n| `write_session_log` | Structured session record. |\n\n**Roadmap** — `get_roadmap` · `get_phase` · `add_phase` · `update_phase_status` ·\n`update_next_action` · `complete_phase` · `defer_phase` · `bulk_import_phases`.\n\n**Code graph** — `get_node` (file metadata) · `get_impact` (blast radius) · `query_graph`\n(function-level callers/callees/tests/dependents/symbols) · `get_playbook` (curated rules for\n`add_tool` / `add_service` / `add_schema` / `debug_pipeline` / `commit` / `write_test`). Plus the\nhidden `refresh_graph`.\n\n**Memory subsystems**\n\n| Subsystem | Tools | What it covers |\n|---|---|---|\n| Working memory (4) | `working_add`, `working_get`, `working_promote`, `get_working_context` | Intra-session scratchpad, decay-scored (`importance × e^(−Δt/τ=6h) + 0.5·access_count`), capacity-bounded. Auto-populated by the `PostToolUse` fan-out. |\n| Skill library (6) | `record_skill`, `get_skill`, `apply_skill_outcome`, `list_skills`, `supersede_skill`, `promote_skill_to_playbook` | Reusable procedures; FTS5 composite ranking (BM25 + tag-Jaccard + recency); auto-archive at 5 consecutive failures or 90 unused days (`do_not_revert` exempt). |\n| Provenance (1) | `origin_of` | Which IDE, which machine, when — what attributes an amendment across a two-host merge. (`CODEVIRA_IDE` is a cooperative signal, spoofable, not a security boundary.) |\n\n**Workflow prompt** — `onboard_session`: full project catch-up for new sessions; wraps\n`get_session_context()`.\n\n**Removed in 4.0** (52 tools → 37 defined; 36 advertised). Cut on measured usage across 4,203\ntranscripts, not taste — the data they wrote is untouched, and `codevira export` still includes\neverything. See [MIGRATING.md](https://github.com/sachinshelke/codevira/blob/main/MIGRATING.md).\n\n| Removed | Instead |\n|---|---|\n| `consensus_check`, `consensus_status`, `consensus_propose_supersession`, `consensus_resolve` | `origin_of` |\n| `reflect`, `get_reflections`, `list_reflections` | — |\n| `spatial_nearby`, `spatial_heat`, `spatial_neighborhood`, `spatial_affordances` | `get_impact` |\n| `distill_preferences`, `search_preferences` | the `style` panel in `get_session_context` |\n| `get_code`, `get_signature` | read the file — both measured **zero** calls in 2.5 months |\n\n</details>\n\n## Enforcement engine\n\n<details>\n<summary><strong>The 7 default policies, how verdicts combine, and every kill-switch</strong></summary>\n\n<br>\n\nCodevira ships **7 default engine policies** (\"heroes\"), each hooked to Claude Code lifecycle\nevents: `SessionStart`, `PreToolUse`, `PostToolUse`, `UserPromptSubmit`, `Stop`.\n\n| Policy | Event | What it does |\n|---|---|---|\n| **Decision Lock** | PreToolUse | Blocks an edit that touches a `do_not_revert` decision's subject. **Content-aware:** a provably-orthogonal edit downgrades to a warn; a token-touching edit blocks. Strict file-level locking via `CODEVIRA_DECISION_LOCK_CONTENT_AWARE=0`. |\n| **Anti-Regression** | PreToolUse | Blocks edits that look like reverts of previously-fixed bugs. Fix-history is scanned from `fix:` / `bug:` / `hotfix:` / `fixes #N` commit messages and self-freshens on read when git HEAD advances. *Caveat: calibrated for small `Edit`/`MultiEdit` hunks; full-file `Write` reverts are deliberately exempt (future work).* |\n| **Blast-Radius Veto** | PreToolUse | Blocks a signature-*removing/modifying* edit to a high-fan-in file (purely-additive signatures pass). Shows the callers. |\n| **Relevance Inject** | UserPromptSubmit | Injects ≤3 relevant decisions per prompt; 0 tokens when off-topic. |\n| **Session-Log Enforcer** | SessionStart + Stop | Blocks (or, in `warn` mode, nudges) a session that shipped commits without a `write_session_log`. A second consecutive block degrades to a warn so a session that genuinely cannot log still finishes. |\n| **Post-Edit Graph Refresh** | PostToolUse | Reindexes edited files in the background. |\n| **Token Budget / telemetry** | Stop | Records outcome telemetry. |\n\n**How verdicts combine.** The three edit guards compose into a single verdict — **first block wins\nby priority** (Decision Lock 100 > Anti-Regression 80 > Blast-Radius 50). The highest-priority\nblock's message is what you see; the rest are recorded as telemetry.\n\n**Fail-open and opt-in.** The dispatcher never raises: each policy is wrapped in try/except and\nreturns *allow* on failure. `CODEVIRA_ENGINE=0` disables all policies; each edit guard also has a\nper-policy `off|warn|block` env override (`CODEVIRA_DECISION_LOCK_MODE`,\n`CODEVIRA_ANTI_REGRESSION_MODE`, `CODEVIRA_BLAST_RADIUS_MODE`). Enforcement is **not** global\nacross all Claude Code projects — in any project you never ran `codevira init` on, the hooks stay\nfully inert.\n\n**The universal backstop (4.0).** `codevira engine install-git-hook` installs a `pre-commit` hook\nthat runs locked decisions against staged changes through the same engine — so a `do_not_revert`\ndecision is enforced in *any* editor, because they all commit with git. `git commit --no-verify`\noverrides a single commit; `CODEVIRA_GIT_HOOK_MODE=warn` (or `off`) changes it globally; merge\ncommits are never blocked.\n\n**Why edit-time blocking is Claude Code only.** The hard-block path is Claude Code's real\n`PreToolUse` hook. Edits from Cursor / Codex / Copilot go straight to the filesystem — they never\nreach codevira's `PreToolUse` engine — so those IDEs get decisions as advisory `AGENTS.md`\ncontext, with the git `pre-commit` hook as the universal backstop. Verified: Claude Code returns\n`permissionDecision: deny` (exit 2) with the decision's reasoning, rejected alternatives and\nre-examination trigger attached; the git hook refuses the commit with the same reasoning. Other\nIDEs are supported but verified one at a time rather than inferred.\n\n</details>\n\n## CLI commands\n\n<details>\n<summary><strong>26 commands — the daily-use table, plus what's safe vs destructive</strong></summary>\n\n<br>\n\n26 subcommands. Two are internal (`merge-driver`, invoked by git's merge driver, and\n`register-all`, a setup helper); three more are advanced (`working`, `induce-skills`, `eval`).\nThe daily-use ones are below — run `codevira <cmd> --help` for full flags:\n\n| Command | What it does |\n|---|---|\n| `codevira init` | Opt this project in: `.codevira/` + AGENTS.md + .gitignore + git merge driver. Add `--shared` to commit memory for team sharing (default keeps it per-machine) |\n| `codevira setup` | Detect installed AI tools + write MCP configs + Claude Code hooks |\n| `codevira doctor` | Health checks (read-only; ✓/⚠/✗ + a fix command each) |\n| `codevira status` | Index health + project state |\n| `codevira projects` | List tracked projects with staleness; `projects archive <name>` drops one |\n| `codevira untrack <path>` | Remove one stray or temporary project entry |\n| `codevira index` | Build / refresh the code-graph cache |\n| `codevira sync` | Regenerate AGENTS.md + manifest + digest from `decisions.jsonl` |\n| `codevira repair-ids` | Detect/repair cross-engineer decision-id collisions (`--apply`; `--semantic` reports near-duplicates) |\n| `codevira observe-git` | Classify past decisions as kept/modified/reverted from git history |\n| `codevira replay` | Browse the decisions timeline (terminal / markdown / HTML) |\n| `codevira search <query>` | Search decisions from the terminal (FTS5/BM25); `--all-projects`, `--json` |\n| `codevira graph` | Render an interactive, offline HTML viewer of decision memory |\n| `codevira memory` | `snapshot` / `undo` the memory store — the rollback path `git revert` can't give you |\n| `codevira export` / `import` | Back up / restore project memory + global learning across machines |\n| `codevira engine` | `install-git-hook` installs the universal `pre-commit` backstop; `status` / `disable` / `enable` |\n| `codevira prune` | Remove orphaned project dirs, dead `global.db` rows, ghost dirs and legacy backups. Never touches decisions, IDE configs or hooks. `--dry-run` first |\n| `codevira reset` | Destructive cleanup of this project's memory (auto-exports first; requires a typed confirmation) |\n| `codevira uninstall` | Reverse every system write codevira made — `~/.codevira/` including snapshots, every IDE config entry, the launchd service. Preserves user content outside markers. Requires typing `uninstall` |\n| `codevira clean` | **Removed in 4.0.1** — it was a full uninstall mis-named as tidy-up, and its old description destroyed a real install. It now errors `invalid choice`. Use `prune` to tidy, `uninstall` to remove |\n| `codevira serve` | Start the single-project MCP HTTP server (stdio is the daily mode) |\n\nTo fully remove codevira: run the uninstall command above, then `pipx uninstall codevira`.\n\n</details>\n\n## Language support\n\n<details>\n<summary><strong>What's language-agnostic vs. what needs a grammar</strong></summary>\n\n<br>\n\n| Feature | Python | TS/JS | Go | Rust | Others |\n|---|:---:|:---:|:---:|:---:|:---:|\n| Decision capture + search | ✓ | ✓ | ✓ | ✓ | ✓ |\n| Cross-IDE memory via AGENTS.md | ✓ | ✓ | ✓ | ✓ | ✓ |\n| Roadmap / sessions | ✓ | ✓ | ✓ | ✓ | ✓ |\n| Code graph + blast radius | ✓ | ✓ | ✓ | ✓ | — |\n| Symbol-level `query_graph` | ✓ | ✓ | ✓ | ✓ | — |\n\nDecisions / `AGENTS.md` / roadmap are **language-agnostic** — they work for any language.\n**Code-graph and symbol tools** cover exactly Python (stdlib `ast`) plus TS / TSX / JS / JSX / Go\n/ Rust (bundled tree-sitter grammars). For any other language the AI `Read`s the file directly.\nThe legacy 17-grammar `[all-languages]` pack was removed in v2.2.0 to keep the install lean.\n\n</details>\n\n## Concurrency & safety\n\n<details>\n<summary><strong>Atomic writes, file locking, and how they're stress-tested</strong></summary>\n\n<br>\n\nEvery on-disk write goes through `mcp_server/storage/atomic.py`: a crash-safe atomic write\n(`mkstemp` + `fsync` + `os.replace`) behind a Posix `fcntl.flock` (with an in-process\n`threading.Lock` first, and a Windows `O_EXCL` sentinel fallback). Appends to the JSONL logs are\nline-atomic — concurrent appenders never interleave bytes. Result: two IDEs hitting the same\nproject don't race on `manifest.yaml` / `roadmap.yaml` / `AGENTS.md`.\n\nThis is exercised by a 50-operation stress over a 10-thread pool, a 20-subprocess cross-process\nstress (`spawn`), and an adversarial chaos harness ([`scripts/chaos_smoke.py`](https://github.com/sachinshelke/codevira/blob/main/scripts/chaos_smoke.py)\n— 8 scenarios including SIGKILL during a held lock, symlink traversal, malformed MCP payloads,\ncorrupt-JSONL graceful degradation, and read-only-directory hostility). See\n[`docs/architecture.md`](https://github.com/sachinshelke/codevira/blob/main/docs/architecture.md) § \"Concurrent-write safety\".\n\n</details>\n\n---\n\n## Upgrading & troubleshooting\n\n**Upgrading is automatic** — codevira migrates your memory on the first server start after an\nupgrade, and your existing decisions stay put. (After a `pipx upgrade codevira`, restart your IDE\nso its MCP server reloads the new binary.)\n\n**One exception, if you are coming from 4.1.0 or earlier.** A bug could register `$HOME` itself as\na project, and every genuine project below it was then discarded as a \"nested sub-store\". 4.2.0\nstops that happening, but it does **not** repair a registration that is already wrong — nothing\nprunes the bad row on upgrade. If projects went missing from an IDE, run this once:\n\n```bash\ncodevira register-all --dry-run   # read-only; shows what IS registered\n```\n\nIf that prints one project at your home directory with your real ones listed as *excluded\nnested*, that is this bug. Before clearing it, look at what would be removed:\n\n```bash\ncodevira untrack --dry-run \"$HOME\"   # read-only; lists IDE entries AND the data dir\n```\n\n**Read that output.** `untrack` deletes the project's data directory, not just the registry\nentry. If you were bound to `$HOME` by mistake, any decisions recorded during that time live in\n*that* directory and will go with it. If the dry-run lists a data dir you might want, copy it\naside first (`cp -R` the path it names). Your other projects each have their own directory and\nare not affected.\n\nThen clear and re-register:\n\n```bash\ncodevira untrack -y \"$HOME\"\ncodevira register-all\n```\n\nRestart the IDE afterwards.\n\n(`codevira doctor` will not catch this one: its checks cover the *current* binding and whether\n`global.db` opens, not what is registered inside it.)\n\nIf an IDE then shows the wrong project, doesn't show codevira at all, or memory looks missing,\nit's almost always a stale IDE-config entry rather than lost data. Two fixes cover most cases:\nremove a stray or temporary entry with `codevira untrack <path>` (or sweep dead ones with\n`codevira prune --ghosts`), then run `codevira doctor` — it names the bound project and ships the\nexact fix for each ⚠/✗.\n\nFull guides: [IDE config hygiene](https://github.com/sachinshelke/codevira/blob/main/docs/troubleshooting/config-hygiene.md) ·\n[Antigravity](https://github.com/sachinshelke/codevira/blob/main/docs/troubleshooting/antigravity.md) · [FAQ](https://github.com/sachinshelke/codevira/blob/main/FAQ.md)\n\n---\n\n## Frequently asked\n\n### How do I give Claude Code persistent memory across sessions?\n\nInstall codevira and run `codevira init` in the project. Every new session starts with\n`get_session_context()` — a ~500-token brief of the project's decisions, current phase and next\naction — instead of you re-explaining the codebase.\n\n### Does this work with Cursor and Antigravity, or only Claude Code?\n\nMemory works everywhere: every tool reads the same in-repo `.codevira/decisions.jsonl` and the\ngenerated `AGENTS.md`. `codevira setup` writes MCP server config automatically for the tools that\nsupport it (Claude Code, Claude Desktop, Cursor, Antigravity); Codex, Copilot and other agents are\ncovered by the generated `AGENTS.md`. Hard *edit-time* blocking is Claude Code only — every other\neditor is covered at the commit boundary by `codevira engine install-git-hook`.\n\n### How is this different from a hand-written `CLAUDE.md` or `AGENTS.md`?\n\nThose are static text you maintain by hand. Codevira **generates** `AGENTS.md` from a queryable\ndecision log, keeps the *reasoning* attached to each decision, and blocks the edit that would\nbreak a locked one.\n\n### Does it use vectors or embeddings?\n\nNo. Decision search is SQLite FTS5/BM25 keyword search — no ChromaDB, no sentence-transformers,\nno torch. An AST scan in CI fails the build if any module but `egress.py` imports a network\nclient.\n\n### Is my code or my memory sent anywhere?\n\nNo. Everything lives in `<repo>/.codevira/` and `~/.codevira/` on your machine. MIT-licensed, no\naccount, no API key, no cloud.\n\n### What does it cost in tokens?\n\nTools return summaries by default, `get_session_context()` is one ~500-token call, and the\nlean-12 tool profile cuts `tools/list` from 36 tools to 12 (~8.9K → ~3.5K tokens per session).\n\nLonger answers: [FAQ.md](https://github.com/sachinshelke/codevira/blob/main/FAQ.md).\n\n---\n\n## How Codevira compares\n\nMost memory tools for AI agents *retrieve*. Codevira also *enforces*, and it is per-project across\n*many* tools rather than per-session inside one. If you need cross-machine cloud memory, a\ntemporal knowledge graph at enterprise scale, or the top LongMemEval score, other tools are the\nbetter pick — that comparison is written out honestly, including where codevira loses:\n**[Codevira vs other AI memory tools](https://github.com/sachinshelke/codevira/blob/main/docs/vs-other-memory-tools.md)** (Mem0, claude-mem, Zep,\nMemPalace and others).\n\n**Deeper reading:** [Architecture](https://github.com/sachinshelke/codevira/blob/main/docs/architecture.md) ·\n[Wire protocol](https://github.com/sachinshelke/codevira/blob/main/PROTOCOL.md) ·\n[How we dogfood it](https://github.com/sachinshelke/codevira/blob/main/DOGFOOD.md) ·\n[Roadmap](https://github.com/sachinshelke/codevira/blob/main/ROADMAP.md) ·\n[Changelog](https://github.com/sachinshelke/codevira/blob/main/CHANGELOG.md) ·\n[Migrating to 4.0](https://github.com/sachinshelke/codevira/blob/main/MIGRATING.md) ·\n[How I built persistent memory for AI coding agents](https://github.com/sachinshelke/codevira/blob/main/docs/how-i-built-persistent-memory-for-ai-agents.md)\n\n---\n\n## Contributing\n\nContributions are genuinely welcome, and the backlog is open — see\n[CONTRIBUTING.md](https://github.com/sachinshelke/codevira/blob/main/CONTRIBUTING.md) for the dev setup and PR checklist.\n\n<details>\n<summary><strong>How the codebase is laid out</strong> — layers, the two persistence stacks, and where to add a tool / command / policy</summary>\n\n<br>\n\nStart here before your first PR. One caveat it makes loud: **82% of codevira's internal\nimports sit inside function bodies**, so a static import graph draws this codebase as\ndisconnected leaves — the arrows below are runtime call edges. The diagram also marks the\nboundaries that *don't* hold, rather than pretending the layering is clean.\n\n<p align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/sachinshelke/codevira/main/website/assets/internals.png\"\n       alt=\"Codevira internals: process entry points, the 48 root modules grouped by role, tools/ and engine/ as siblings, two separate persistence stacks (storage/ for decisions, indexer/ for the code graph), the jsonl_store and atomic write choke points, and on-disk layout\"\n       width=\"100%\">\n</p>\n\n</details>\n\n**Good places to start:**\n\n- **Run it in an IDE you use and report what happened.** That's how the support matrix grows.\n- **Windows.** The sentinel-lock fallback is unit-tested but never load-tested on real hardware.\n- **Docs.** Anything wrong or slow to find in this README or the [FAQ](https://github.com/sachinshelke/codevira/blob/main/FAQ.md) is a bug — file it.\n\nChannels:\n\n- **Bug?** [Open a bug report](https://github.com/sachinshelke/codevira/issues/new?template=bug_report.md)\n- **Feature or idea?** [Open a feature request](https://github.com/sachinshelke/codevira/issues/new?template=feature_request.md)\n- **Security issue?** Read [SECURITY.md](https://github.com/sachinshelke/codevira/blob/main/SECURITY.md) — please don't use public issues for\n  vulnerabilities.\n- **Conduct:** [CODE_OF_CONDUCT.md](https://github.com/sachinshelke/codevira/blob/main/CODE_OF_CONDUCT.md)\n\nIf Codevira saves you tokens or sanity, a ⭐ helps other developers find it.\n\n## License\n\nMIT — free to use, modify, and distribute. See [LICENSE](https://github.com/sachinshelke/codevira/blob/main/LICENSE).\n"}