{"slug": "forkmind-git-for-llm-context-branch-offload-and-restore-it", "title": "ForkMind – Git for LLM context: branch, offload, and restore it", "summary": "ForkMind, a new open-source tool that treats LLM context windows like Git repositories, launched to help developers branch, debug, and compare AI conversations locally. The tool captures every LLM call into a local directory, visualizes conversation trees as DAGs, and supports any OpenAI-compatible API including free local models via Ollama. ForkMind aims to simplify debugging of agentic and tool-calling flows by allowing users to branch from any historical turn and compare outcomes visually.", "body_md": "**Local-first LLM state branching & debugging.** ForkMind treats AI context\nwindows like a Git repository: it captures every LLM call into a local\n`.forkmind/`\n\ndirectory, visualizes the conversation as a Directed Acyclic Graph\n(DAG), and lets you **branch** alternative prompts or model params from any point\nin the history — all on your machine, no cloud, no account.\n\nWorks with **any OpenAI-compatible API**, defaulting to **free, open-source\nmodels** via [Ollama](https://ollama.com). Also supports Anthropic and any\nhosted free tier (Groq, OpenRouter, Together, vLLM, LM Studio).\n\nLive demo: a conversation tree with a branch off the root, the node inspector (request/response, tokens, provenance), and the\n\nFork from heredialog.\n\nDebugging agentic / tool-calling flows means re-running the same prompt with tiny tweaks over and over. ForkMind records each run as a node, so you can:\n\n**See** the whole conversation tree, including tool calls and token usage.**Branch** from any historical turn — edit the prompt, swap the model, re-run.**Compare** outcomes visually instead of scrolling through terminal logs.\n\nEverything is plain JSON on disk. No database. No telemetry.\n\n```\n# Run without installing (published on npm)\nnpx forkmind init\nnpx forkmind start\n\n# …or install the CLI globally\nnpm install -g forkmind\nforkmind start\n```\n\nNo npm registry needed either — ForkMind runs straight from the git link, and the dashboard builds automatically on install:\n\n```\n# Run without installing, from GitHub\nnpx github:medhovarsh/forkmind init\nnpx github:medhovarsh/forkmind start\n\n# …or clone to hack on it\ngit clone https://github.com/medhovarsh/forkmind\ncd forkmind && npm install\n```\n\nForkMind ships a Claude Code plugin (skill + `/forkmind`\n\ncommand) so Claude knows\nwhen and how to drive it — same install flow as any marketplace plugin:\n\n```\n/plugin marketplace add Medhovarsh/forkmind\n/plugin install forkmind\n```\n\nThe plugin bundles:\n\n— Claude reaches for ForkMind whenever you ask it to debug a prompt, compare models, branch from a past turn, or regression-test a call.`forkmind`\n\nskill— start / branch / test / mcp on demand.`/forkmind`\n\ncommand— runs model/prompt comparisons in an isolated context and returns a compact verdict instead of dumping transcripts.`forkmind-debugger`\n\nagent**MCP server, auto-wired**— agents query their own`.forkmind/`\n\nhistory (recall attempts, trace lineage, self-correct) with zero manual config.\n\nThe CLI is still what runs the proxy + dashboard; the plugin is the glue that teaches Claude to use it.\n\n```\n# 1. Install a free local model\n#    (install Ollama from https://ollama.com first)\nollama pull llama3\n\n# 2. Init + start ForkMind\nnpx github:medhovarsh/forkmind init    # create .forkmind/ in your project\nnpx github:medhovarsh/forkmind start   # proxy on http://localhost:4500 + dashboard\n\n# 3. Point your code at the proxy (see SDK below), make some calls\n\n# 4. Open the dashboard\nopen http://localhost:4500\nnpm i openai            # the wrapper extends the official SDK\njs\nconst { ForkMindOpenAI } = require('forkmind');\n\nconst client = new ForkMindOpenAI({\n  apiKey: 'ollama',                       // ignored by Ollama; required by SDK\n  upstream: 'http://localhost:11434',     // free local open-source models\n});\n\n// Each call is recorded; sequential calls auto-chain into a conversation tree.\nconst res = await client.chat.completions.create({\n  model: 'llama3',\n  messages: [{ role: 'user', content: 'Explain backpropagation simply.' }],\n});\n```\n\nRun the full example:\n\n```\nnode examples/chain.js\n```\n\nThe SDK wrapper is convenience, not a requirement. ForkMind's proxy speaks the\n**OpenAI-compatible wire protocol**, so capture works from *any* language: set\nyour client's base URL to `http://localhost:4500/v1`\n\nand you're recorded. Chain\nturns into a tree by passing back the `x-forkmind-node-id`\n\nfrom the previous\nresponse as the next request's `x-forkmind-parent`\n\nheader (the JS wrapper just\nautomates this).\n\n``` python\n# Python — official openai client, zero ForkMind code\nfrom openai import OpenAI\n\nclient = OpenAI(base_url=\"http://localhost:4500/v1\", api_key=\"ollama\")\nres = client.chat.completions.create(\n    model=\"llama3\",\n    messages=[{\"role\": \"user\", \"content\": \"Explain backpropagation simply.\"}],\n    extra_headers={\"x-forkmind-upstream\": \"http://localhost:11434\"},\n)\n# read res via .with_raw_response to grab x-forkmind-node-id and chain the next call\n# curl — anything that can POST JSON\ncurl http://localhost:4500/v1/chat/completions \\\n  -H 'content-type: application/json' \\\n  -H 'x-forkmind-upstream: http://localhost:11434' \\\n  -d '{\"model\":\"llama3\",\"messages\":[{\"role\":\"user\",\"content\":\"hi\"}]}' -i\n# response header `x-forkmind-node-id: <id>` → pass as `x-forkmind-parent` next call\n```\n\nGo, Ruby, Rust, Java — same deal: base URL + the two headers. The dashboard, branching, MCP, and regression testing all work regardless of source language.\n\nForkMind ships thin adapters for the two biggest JS LLM ecosystems. Both route through the same proxy, so capture, branching, the dashboard, MCP, and regression all work unchanged — no model-class swap, no callbacks.\n\n```\nnpm i @langchain/openai @langchain/core\njs\nconst { ChatOpenAI } = require('@langchain/openai');\nconst { forkmind } = require('forkmind/langchain');\n\nconst fm = forkmind({ upstream: 'http://localhost:11434' }); // free local Ollama\nconst model = new ChatOpenAI({\n  apiKey: 'ollama',\n  model: 'llama3',\n  configuration: fm.configuration, // baseURL → proxy + chaining fetch\n});\n\nawait model.invoke('Explain backpropagation simply.');\n// sequential calls on `fm` auto-chain; fm.setParent(id) to branch from a node.\nnpm i ai @ai-sdk/openai\njs\nconst { generateText } = require('ai');\nconst { forkmindOpenAI } = require('forkmind/vercel');\n\nconst openai = forkmindOpenAI({ upstream: 'http://localhost:11434' });\nconst { text } = await generateText({\n  model: openai('llama3'),\n  prompt: 'Explain backpropagation simply.',\n});\n// openai.setParent(id) / openai.resetParent() control the branch point.\n```\n\nBoth honor `FORKMIND_PROXY`\n\n(proxy base URL) and take an explicit `baseURL`\n\n/\n`upstream`\n\nper instance.\n\nForkMind is provider-agnostic — it forwards your auth headers verbatim and lets you set the upstream per client. Anything OpenAI-compatible just works:\n\n| Provider | `upstream` |\n`apiKey` |\n|---|---|---|\nOllama (local) |\n`http://localhost:11434` |\nany string |\nLM Studio (local) |\n`http://localhost:1234` |\nany string |\nGroq (free tier) |\n`https://api.groq.com/openai` |\n`gsk_...` |\nOpenRouter |\n`https://openrouter.ai/api` |\n`sk-or-...` |\nTogether |\n`https://api.together.xyz` |\nyour key |\nOpenAI |\n`https://api.openai.com` (default) |\n`sk-...` |\n\n```\nnew ForkMindOpenAI({ apiKey: process.env.GROQ_API_KEY,\n                     upstream: 'https://api.groq.com/openai' });\n```\n\nYou can also override per request with the `x-forkmind-upstream`\n\nheader if you\ncall the proxy directly instead of via the SDK.\n\n```\nnpm i @anthropic-ai/sdk\njs\nconst { ForkMindAnthropic } = require('forkmind');\nconst client = new ForkMindAnthropic({ apiKey: process.env.ANTHROPIC_API_KEY });\nawait client.messages.create({ model: 'claude-3-5-sonnet-latest', max_tokens: 512,\n                               messages: [{ role: 'user', content: 'hi' }] });\nyour app ──▶ ForkMindOpenAI (baseURL = localhost:4500/v1)\n                │  injects x-forkmind-parent\n                ▼\n         ForkMind proxy (Express, :4500)\n                │  forwards verbatim (your key, your upstream)\n                ▼\n         provider (Ollama / Groq / OpenAI / ...)\n                │  response\n                ▼\n         proxy reconstructs + saveNode()  ──▶  .forkmind/nodes/<id>.json\n                │  returns x-forkmind-node-id\n                ▼\n         wrapper chains it as the next call's parent\n```\n\n**Deterministic node IDs.**`sha256(request + parentId)`\n\n→ first 12 hex chars. Same prompt under the same parent collapses to one node. The ID doesn't depend on the response, so it can be returned as a header even before a streamed body finishes.**Streaming.** Bytes pass through to your app untouched (real SSE); the proxy tees them, reconstructs the full message (text**and** fragmented tool-call arguments), and saves the node on stream end.**Branching.** Each node records its provider + upstream, so \"Fork from here\" in the dashboard replays the edited request to the same host, linked to the historical parent.\n\nForkMind ships an [MCP](https://modelcontextprotocol.io) server so an AI agent\ncan read its own `.forkmind/`\n\nhistory mid-task and self-correct — recall what it\nalready tried, see how it reached a state, or search past attempts.\n\n```\nforkmind mcp          # stdio MCP server (or: forkmind-mcp)\n```\n\nOne-line install via [Smithery](https://smithery.ai) (configured in\n[ smithery.yaml](/Medhovarsh/forkmind/blob/master/smithery.yaml)) — run it from your project root so it sees\nyour\n\n`.forkmind/`\n\n:\n\n```\nnpx -y @smithery/cli install forkmind --client claude\n```\n\n…or register it manually with any MCP client (Claude Desktop / Claude Code / Cursor / Cline):\n\n```\n{\n  \"mcpServers\": {\n    \"forkmind\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"github:medhovarsh/forkmind\", \"mcp\"]\n    }\n  }\n}\n```\n\nTools exposed:\n\n| Tool | Purpose |\n|---|---|\n`forkmind_recent` |\nNewest captured turns (compact) |\n`forkmind_get_node` |\nFull request + response for one node |\n`forkmind_lineage` |\nRoot→node path — the exact context that produced a state |\n`forkmind_children` |\nSibling branches forking from a node |\n`forkmind_search` |\nSubstring search across all requests/responses |\n`forkmind_stats` |\nTree totals: nodes, roots, leaves, providers |\n`forkmind_context_save` |\nOffload context into an encrypted DAG capsule |\n`forkmind_context_list` |\nList saved capsules (title, digest, size, age) |\n`forkmind_context_digest` |\nDigest + segment map — cheap pre-restore probe |\n`forkmind_context_restore` |\nFull or per-segment restore, integrity-verified |\n`forkmind_context_forget` |\nIrreversible crypto-shred (requires id echo) |\n`forkmind_context_replicas` |\nReplica (RAID) health, optional sync |\n`forkmind_context_stats` |\nAggregate stats: count, bytes, estimated tokens |\n`forkmind_context_export` |\nPortable passphrase-encrypted bundle |\n`forkmind_context_import` |\nImport + re-verify a bundle, re-wrap locally |\n\nThe server reads the `.forkmind/`\n\nin its working directory — point the client's\n`cwd`\n\nat your project.\n\nMost context managers treat a full window as a cache-eviction problem: truncate\nand lose it. ForkMind **capsules** invert that — *persist first, verify, then\ncompact*. A capsule is an immutable, content-addressed DAG of context segments,\nAES-256-GCM encrypted on disk, restorable in full or one segment at a time.\n\n```\n# Save (items JSON from a file or stdin), get back a 12-char handle\necho '{\"title\":\"auth debug\",\"items\":[{\"role\":\"user\",\"content\":\"...\"}]}' \\\n  | forkmind context save --digest \"oauth loop root-caused; fix in token.js\"\n\nforkmind context list                 # all capsules, newest first\nforkmind context show 9f3ac21b7e04    # decrypt + verify + print\nforkmind context verify 9f3ac21b7e04  # DAG integrity: parents, acyclicity, hashes\nforkmind context forget 9f3ac21b7e04 --confirm 9f3ac21b7e04   # crypto-shred\n```\n\nSame engine over HTTP (`POST/GET/DELETE :4500/api/context…`\n\n) and via five MCP\ntools, so agents can archive their own context mid-task and pull it back later.\nThe Claude Code plugin ships a ** forkmind-archivist** skill + subagent that\nteaches Claude the offload contract:\n\n**save → verify on disk → only then drop it from the window**.\n\nGuarantees:\n\n**Immutable & acyclic by construction**— segment ids are hashes over content + parents (Git-style); a cycle would require a hash to contain itself.** No plaintext at rest**— per-capsule keys, wrapped by a master key stored*outside*`.forkmind/`\n\n(`~/.forkmind-keys/`\n\n); an accidentally committed`.forkmind/`\n\nleaks only ciphertext and structure.**Digests are opt-in**— the agent writes a ≤5-line retrieval summary, or omits it entirely for private capsules.** Forgetting is real**— delete destroys the key first (crypto-shredding), then tombstones the id so identical content can never resurrect it.** The model is never touched**— capsules operate on what the client sends; provider, weights, and KV cache are out of scope by design.\n\nMirror capsules to any number of extra filesystem targets (second disk, synced\nfolder, network mount). Replicas hold **ciphertext + manifests only — keys are\nnever replicated**. If the primary copy is lost or bit-rots, restore self-heals\nfrom the first replica that passes verification; healed copies get no trust\nshortcut (full integrity check still runs).\n\n```\nforkmind context replicas add D:\\backup\\forkmind   # add target + sync\nforkmind context replicas list                     # coverage per target\nforkmind context replicas sync                     # catch up offline targets,\n                                                   # propagate tombstones\n```\n\nForgetting reaches every copy: reachable replicas are shredded immediately;\na replica that was offline gets its stale ciphertext removed on the next\n`sync`\n\n(tombstone propagation) — and it was unreadable anyway, since the\ncapsule key died at forget time. Tombstones also make heal refuse to\nresurrect anything forgotten.\n\nMove a capsule to another machine or project — a laptop that doesn't share\nthis project's `~/.forkmind-keys/`\n\nmaster key, a teammate, cold storage:\n\n```\nforkmind context export 9f3ac21b7e04 --passphrase \"correct horse battery staple\" --out capsule.json\n# ... move capsule.json anywhere ...\nforkmind context import capsule.json --passphrase \"correct horse battery staple\"\n```\n\nThe bundle carries its own scrypt-derived key material (N=32768, deliberately slow to resist offline brute force of a weak passphrase) — it never depends on the source machine's master key, and the passphrase is never written into the bundle itself. On import, every segment is independently re-verified (recomputed id, recomputed hash, resolved parents, acyclic DFS) before anything touches disk — the bundle is never trusted blindly, only proven. Import is idempotent and honors tombstones, same as a fresh save.\n\nThe two halves connect: any conversation the proxy captured can be archived\ninto a capsule in one move — no manual JSON assembly — and restored later as\na provider-ready `messages[]`\n\narray, ready to splice into the next request:\n\n```\n# archive the whole lineage ending at a captured turn\nforkmind context save --from-node a1b2c3d4e5f6 --digest \"auth debug, resolved\"\n\n# restore as chat messages (or GET /api/context/:id/messages)\nforkmind context show 9f3ac21b7e04 --messages\n```\n\nSame via MCP: `forkmind_context_save { fromNodeId }`\n\nand\n`forkmind_context_restore { asMessages: true }`\n\n— an agent can archive its own\ncaptured history mid-task and splice it back whenever needed. Capsules keep\n`sourceNodeIds`\n\nlinks back into the turn DAG.\n\n`forkmind context save`\n\nand `forkmind context stats`\n\nreport an estimated\ntoken count freed from your context window (`~4 bytes/token`\n\n, the standard\nrough heuristic) — a concrete number for how much a capsule actually saved.\n\nTweaking a system prompt or swapping a model can silently degrade results.\nForkMind lets you pin a known-good captured node as a **baseline**, then re-run\nits exact request later and check the new output for drift.\n\n```\n# 1. Pin a good node (grab its id from the dashboard or forkmind_recent)\nforkmind regression pin a1b2c3d4e5f6 \\\n  --name octopus-fact \\\n  --contains \"hearts\" \\\n  --regex \"blue|copper\" \\\n  --min-similarity 0.5\n\n# 2. List / remove cases\nforkmind regression list\nforkmind regression remove octopus-fact\n\n# 3. Re-run after changing prompts/models (exit code 1 if any case fails — CI-ready)\nforkmind regression run                 # keyless local (Ollama)\nforkmind regression run --key $GROQ_API_KEY --upstream https://api.groq.com/openai\n```\n\nEach case checks the replayed output against:\n\n— substrings that must appear`contains`\n\n— substrings that must NOT appear`not-contains`\n\n— patterns that must match`regex`\n\n— Jaccard word-overlap vs the baseline (drift guard; defaults to`min-similarity`\n\n`0.3`\n\nso a wildly different answer fails even without explicit assertions). LLM output is non-deterministic, so prefer assertions over exact match.\n\nCases are JSON in `.forkmind/regressions/`\n\n— commit them to share baselines and\ngate prompt changes in CI.\n\n**No paid API required**— defaults to free local models via Ollama.** No database**— every turn is a plain JSON file under`.forkmind/`\n\n.**No account, no telemetry**— nothing leaves your machine except the LLM call you were already making (relayed verbatim to the provider you choose).\n\n```\n.forkmind/\n├── nodes/\n│   ├── a1b2c3d4e5f6.json     # one node per turn\n│   └── ...\n├── contexts/                 # encrypted context capsules\n│   └── 9f3ac21b7e04/\n│       ├── manifest.json     # public: DAG shape, hashes, opt-in digest\n│       └── seg-<id>.enc      # AES-256-GCM ciphertext per segment\n├── tombstones.json           # forgotten capsule ids (never resurrected)\n└── manifest.json            # version + root node ids\n```\n\nNode schema:\n\n```\n{\n  \"id\": \"a1b2c3d4e5f6\",\n  \"parentId\": null,           // null = root\n  \"timestamp\": \"2026-01-01T00:00:00.000Z\",\n  \"request\":  { /* the exact request body */ },\n  \"response\": { /* full or stream-reconstructed response */ },\n  \"meta\": { \"provider\": \"openai\", \"upstream\": \"http://localhost:11434\", \"stream\": true },\n  \"children\": [\"...\"]         // child node ids\n}\n```\n\n| Command | Does |\n|---|---|\n`forkmind init` |\nCreate `.forkmind/` in the current directory |\n`forkmind start` |\nStart the proxy (`:4500` ) + serve the dashboard if built |\n`forkmind context save/list/show/verify/forget` |\nEncrypted context capsules (see above) |\n\nEnv vars: `FORKMIND_PORT`\n\n, `FORKMIND_HOST`\n\n(default `127.0.0.1`\n\n— loopback\nonly; set `0.0.0.0`\n\nto expose on the LAN at your own risk),\n`FORKMIND_OPENAI_UPSTREAM`\n\n, `FORKMIND_ANTHROPIC_UPSTREAM`\n\n, `FORKMIND_PROXY`\n\n(SDK target base URL), `FORKMIND_KEY_DIR`\n\n(capsule master-key location,\ndefault `~/.forkmind-keys`\n\n).\n\n```\nnpm install            # installs proxy + dashboard (npm workspaces)\nnpm test               # jest: hashing, storage, stream reconstruction, API\nnpm run dashboard:dev  # vite dev server on :5173, proxies API to :4500\nnpm run dashboard:build\nnpm run lint\n```\n\nPublishing is tag-driven via `.github/workflows/release.yml`\n\n(needs an\n`NPM_TOKEN`\n\nrepo secret with publish rights):\n\n```\nnpm version patch        # bumps package.json + tags\ngit push --follow-tags   # tag push → CI lints, tests, builds dashboard, publishes\n```\n\n`prepack`\n\nrebuilds `dashboard/dist`\n\nso the tarball always ships the UI.\n\nSee [CONTRIBUTING.md](/Medhovarsh/forkmind/blob/master/CONTRIBUTING.md).\n\n- CLI + deterministic storage engine\n- Provider-agnostic proxy (OpenAI-compatible + Anthropic) with streaming\n- Drop-in SDK wrappers with auto-chaining\n- React Flow dashboard + branch execution\n- MCP integration — let agents query their own\n`.forkmind/`\n\nhistory - Automated regression: pin \"good\" branches, re-run on prompt edits\n- Context capsules — offload context as an encrypted, immutable DAG; restore in full or per segment; crypto-shred to forget\n- RAID — Redundant Array of Independent DAGs: replicate capsules across filesystem targets with self-healing restore and tombstone propagation\n- Capsule export/import — portable, passphrase-encrypted bundles to move context between machines and projects, independently re-verified on import\n- Dashboard capsule panel — browse capsules, inspect the DAG segment map, and run integrity verification from the UI (read-only by design)", "url": "https://wpnews.pro/news/forkmind-git-for-llm-context-branch-offload-and-restore-it", "canonical_source": "https://github.com/Medhovarsh/forkmind", "published_at": "2026-07-08 02:57:16+00:00", "updated_at": "2026-07-08 03:30:06.107538+00:00", "lang": "en", "topics": ["developer-tools", "large-language-models", "ai-tools", "ai-agents", "ai-research"], "entities": ["ForkMind", "Ollama", "OpenAI", "Anthropic", "Groq", "OpenRouter", "Together", "vLLM"], "alternates": {"html": "https://wpnews.pro/news/forkmind-git-for-llm-context-branch-offload-and-restore-it", "markdown": "https://wpnews.pro/news/forkmind-git-for-llm-context-branch-offload-and-restore-it.md", "text": "https://wpnews.pro/news/forkmind-git-for-llm-context-branch-offload-and-restore-it.txt", "jsonld": "https://wpnews.pro/news/forkmind-git-for-llm-context-branch-offload-and-restore-it.jsonld"}}