Skip to content

Data and Backup

Maxim Mironenko edited this page Jul 20, 2026 · 9 revisions

Data and Backup

File Locations

All data is stored centrally in ~/.knowledge-graph/. The files are plain JSON, so any file backup tool works:

Data Path Scope
User graph ~/.knowledge-graph/user.json Global, all projects
Project graphs ~/.knowledge-graph/projects/<slug>/graph.json Per-project
Sessions ~/.knowledge-graph/sessions.json Active session tracking
Tool-event counters ~/.knowledge-graph/projects/<slug>/tool_events.json Per-project; feeds capture nudges + DEBT activity. Rebuilds from zero if lost
Server logs ~/.local/state/knowledge-graph/mcp_server.log Ephemeral
Server PID ...server/.mcp_server.pid Runtime

The <slug> is derived from the project directory name (last path component). For example, /home/user/DevProj/my-appmy-app.

Graph File Format

Both user and project graphs use the same JSON structure:

{
  "nodes": {
    "node-id": {
      "id": "node-id",
      "gist": "Short description",
      "notes": ["additional context"],
      "touches": ["related/file.py"],
      "_archived": true,
      "_orphaned_ts": 1706000000.0
    }
  },
  "edges": {
    "source->target:relationship": {
      "from": "source",
      "to": "target",
      "rel": "relationship",
      "notes": ["edge context"]
    }
  },
  "_meta": {
    "versions": {
      "node:node-id": {"v": 3, "ts": 1706000000.0, "session": "abc12345"}
    },
    "progress": {
      "scout": {"last_ts": 1706000000, "sessions_reviewed": ["xyz"]}
    }
  }
}
  • _archived and _orphaned_ts are optional flags on nodes
  • _meta.versions tracks change history for sync
  • _meta.progress stores persistent task state (scout, extract)

Write-Through Persistence

Every mutation (kg_put_node, kg_put_edge, kg_delete_*, kg_read with archived node promotion) saves to disk immediately via atomic write. No data loss on crash or unexpected termination.

Atomic Writes

All saves use atomic writes to prevent corruption:

  1. Write to <file>.tmp
  2. fsync to ensure data hits disk
  3. rename temp to final path (POSIX atomic operation)

If the process crashes mid-write, the temp file is left behind and cleaned up on next save attempt.

Built-in Crash Protection

Every save keeps one rolling copy of the previous good state as <file>.prev. This covers crash/corruption recovery but not accidental deletion or longer-term history.

Self-Healing on Load

Introduced in 0.9.12.

A node is meant to be stored as separate fields — a short gist headline plus a notes list. Rarely, a client serializes the whole node (gist + notes + surrounding tool-call markup) into the single gist string and leaves notes empty. Because every full-graph kg_read renders id + gist, those oversized gists can be 20–30× their intended size and dominate the size budget — which is why kg_* calls sometimes consumed a surprisingly large share of context.

The server repairs this automatically, in two places:

  • On writekg_put_node sanitizes incoming data before storing, so this corruption can no longer land.
  • On load — when a graph is first read from disk, any already-malformed nodes are healed and the repaired file is written back.

Healing splits the real headline out and recovers the embedded notes/touches into their proper fields. It is idempotent (clean nodes are skipped, so re-running it is free) and never overwrites data you supplied — only fields left empty are backfilled.

What you'll see the first time you run 0.9.12: the server log (/tmp/mcp_server.log) prints one line per repaired node, then a summary:

WARNING - Healed corrupt node 'some-node-id': gist 2013->482 chars, recovered 4 note(s)
...
INFO    - Healed 30 corrupt node(s) on load

This is expected and one-time per graph — the next load finds clean data and does nothing. After healing, affected nodes are smaller and their previously-hidden notes reappear in kg_read(id) and the visual editor.

Before upgrading, take a snapshot. Self-healing rewrites graph files on load. The usual <file>.prev rolling backup still applies, but a point-in-time backup (Git or Borg, below) is cheap insurance against any data-touching change. See Recovery if you ever need to roll back.

Recovery

From the rolling .prev backup (one save back):

# Restore previous state (user graph)
cp ~/.knowledge-graph/user.json.prev ~/.knowledge-graph/user.json

# Restore previous state (project graph)
cp ~/.knowledge-graph/projects/<slug>/graph.json.prev \
   ~/.knowledge-graph/projects/<slug>/graph.json

From git history (if you set up versioned history — any point in time):

cd ~/.knowledge-graph
git log --oneline user.json          # find the commit you want
git checkout <commit> -- user.json   # restore that version

After restoring, restart the MCP server (or start a new Claude Code session) to reload from disk.

Data Recovery from Session History

If graph files are lost entirely, you can reconstruct knowledge from Claude Code conversation history using the kg-scout skill. Scout scans ~/.claude/projects/ JSONL session files for past decisions, preferences, and patterns and rebuilds knowledge graph entries from them.

/skill kg-scout

Scout uses a tension-driven approach — it scans session metadata first and only deep-dives into sessions that show signals of useful knowledge (decisions, corrections, recurring patterns). See Skills Reference for details.

Claude Code Session History Retention

Claude Code stores full conversation transcripts as JSONL files in ~/.claude/projects/. These files are the raw material that kg-scout mines for knowledge recovery — and they're also the archive that lets you trace back any decision or insight from past sessions.

By default, Claude Code deletes session files older than 30 days at startup, controlled by the cleanupPeriodDays setting.

Why this matters: If you rely on kg-scout to recover or fill gaps in your knowledge graph, a 30-day window limits how far back it can reach. Extending this gives you a longer recovery window and richer history for mining.

Recommended: set it to 90 days (or whatever matches your working style):

// ~/.claude/settings.json
{
  "cleanupPeriodDays": 90
}

You can also use /config in Claude Code's interactive REPL to set this via the Settings UI.

Note: Session files can grow large over time. At 90 days with active use, expect a few hundred MB in ~/.claude/projects/. The knowledge graph itself stays compact — scout extracts the signal and discards the noise.

Versioned History (Recommended: Git)

The .prev backup holds exactly one previous state — it cannot undo "I deleted a node yesterday and only noticed today." For real history, use git. The plugin has built-in support: if ~/.knowledge-graph is a git repository, the kg-memory script auto-commits all changes on every stop / restart (throttled to once per 10 minutes), and kg-memory commit forces a commit at any time.

Setup is one-time:

cd ~/.knowledge-graph
git init
printf '*.prev\n*.tmp\n' >> .gitignore
git add -A && git commit -m "initial"

That's it — from now on the server commits for you. If your server runs continuously (systemd) and rarely stops, add a periodic commit:

# crontab -e
0 * * * * ~/.local/bin/kg-memory commit

Why git is the right tool here: the graphs are small, human-readable JSON, so diffs are meaningfulgit log -p user.json answers "what changed in my memory this week," and recovering a single node is a git checkout <commit> -- <file> away. No new tools, no opaque archives.

Alternatives

The data is plain JSON in one directory, so any file backup tool works as an additional or off-machine layer — Borg, restic, rsync, your existing backup system. These complement git (independent second copy) rather than replace it (no readable diffs, coarser granularity).

Manual Editing

Graph files are plain JSON — you can edit them with any text editor. This is intentional.

Safe edits:

  • Delete a node: remove its entry from nodes and any edges referencing it
  • Edit a gist or notes: modify the text directly
  • Unarchive: delete the _archived key from a node

Note: With write-through persistence, the server saves on every mutation. If you edit files while the server is running, use the visual editor or restart the server after manual edits to reload from disk.

Data Size

Typical graph sizes:

  • Small project: 5-20 nodes, 10-30 edges, ~2-5 KB on disk
  • Medium project: 20-50 nodes, 30-80 edges, ~10-30 KB on disk
  • Active user graph after months: 30-100 nodes, ~15-50 KB on disk

The fixed compaction budget per level (17,500 exact rendered characters — not configurable by design) keeps the active graph small. Archived nodes stay on disk and cost only their anchor line.

Clone this wiki locally