Claude Code Tools

lorekeeper

github

Autonomous per-repo memory for Claude Code, backed by qmd semantic search. Claude sees prior notes on SessionStart, writes new ones when it learns something worth remembering, and auto-reindexes in the background. Windows, macOS, and Linux installers. Optional caveman compression for input-token savings.

Stars
⭐ 0
License
MIT
Last Updated
2026-05-18
Source
github

lorekeeper

Autonomous per-repo memory for Claude Code and oh-my-pi (omp), backed by qmd for local semantic search and caveman for token-efficient prose. Each agent reads existing notes at session start, writes new ones when it learns something worth remembering, and re-indexes automatically — you never have to manage it by hand.

$XDG_DATA_HOME/lorekeeper/
├── notes/<repo>/    # session-to-session memory: gotchas, decisions, conventions
└── docs/<repo>/     # durable reference docs: overview, architecture, runbook

What it does

  • Reads automatically. A SessionStart hook injects an index of existing notes/docs for the current repo so Claude knows what memory is available. Claude uses qmd’s MCP tools to fetch the specific files the task needs. When the repo has no prior memory, the hook stays silent — no mid-session prompting.

  • Writes autonomously. A SessionEnd hook runs a structural gate, then a Haiku 4-way classifier — none | note | feature-doc | adr — then Sonnet drafts the right artifact:

    • notenotes/<repo>/<slug>.md — scratch gotcha, decision, or non-obvious behavior. Merges in place when slug matches an existing note.
    • feature-docdocs/<repo>/<slug>.md — completed feature doc (overview, how it works, config, usage). Merges in place when slug matches an existing doc.
    • adrdocs/<repo>/adr/ADR-NNNN-<slug>.md — architecture decision record with context / decision / consequences / alternatives. Sequential numbering.

    No mid-session hinting to Claude. Disable with touch $LOREKEEPER_HOME/.autonote-off or LOREKEEPER_AUTONOTE=off.

  • Distills on demand. lorekeeper distill runs inside a repo and spawns a Sonnet session with Read/Glob/Grep/Write to synthesize durable engineering docs from accumulated notes + the codebase: architecture.md, onboarding.md, runbook.md, conventions.md, api.md. Use <!-- AUTODOC:START --> / <!-- AUTODOC:END --> sentinels in any hand-curated doc to pin sections the distill pass is allowed to rewrite. Expensive (several $ per repo) and slow (minutes) — run occasionally, not on every session.

  • Re-indexes itself. A PostToolUse hook runs qmd update && qmd embed in the background whenever Claude writes under the notes/docs tree. The autonote hook triggers the same reindex directly after it writes.

  • Uses caveman if present. Ships a caveman-compressed CLAUDE.md block to cut input tokens on every session, and instructs Claude to write notes in caveman-speak so retrieval is cheap too.

Requirements

All platforms

  • Claude Code CLI (≥ 2.1)
  • Node.js ≥ 22
  • git
  • Optional: caveman plugin for token reduction

Linux/macOS only

  • jq (for settings.json merging in the bash installer)

qmd is installed by the installer if missing.

Install

Linux / macOS

git clone https://github.com/sizzlorox/lorekeeper ~/.local/share/lorekeeper
~/.local/share/lorekeeper/install.sh

Optional flags:

./install.sh --with-caveman         # also install caveman plugin
./install.sh --lorekeeper-home PATH # override data dir (default: $XDG_DATA_HOME/lorekeeper)
./install.sh --no-embed-bootstrap   # skip initial qmd embed (faster install, do it later)
./install.sh --no-claude            # skip Claude Code wiring (omp-only install)
./install.sh --no-omp               # skip omp plugin install (Claude-only install)

Windows

Use the native PowerShell installer — no bash, no jq needed. Works in PowerShell 5.1 (built into Windows) or PowerShell 7+.

Extra prerequisite: Git for Windows. qmd ships its npm entrypoint as a POSIX shell script, so it needs sh.exe — Git for Windows provides one at C:\Program Files\Git\bin\sh.exe. The installer locates it automatically (or honors $env:LOREKEEPER_SH) and rewrites qmd’s broken npm shims (qmd.ps1 / qmd.cmd) to call it directly. If you re-install qmd via npm later, re-run install.ps1 to repatch the shims.

git clone https://github.com/sizzlorox/lorekeeper "$env:LOCALAPPDATA\lorekeeper"
powershell -ExecutionPolicy Bypass -File "$env:LOCALAPPDATA\lorekeeper\install.ps1"

Flags mirror the bash installer:

.\install.ps1 -WithCaveman
.\install.ps1 -LorekeeperHome C:\path\to\data
.\install.ps1 -NoEmbedBootstrap
.\install.ps1 -NoClaude              # skip Claude Code wiring (omp-only install)
.\install.ps1 -NoOmp                 # skip omp plugin install (Claude-only install)

Defaults on Windows:

itempath
data home%LOCALAPPDATA%\lorekeeper
claude config%USERPROFILE%\.claude
CLI (lorekeeper.cmd)%LOCALAPPDATA%\lorekeeper\bin
hook scripts%USERPROFILE%\.claude\hooks\lorekeeper-*.ps1

The CLI directory is added to your user PATH automatically; open a new PowerShell window so the update takes effect. uninstall.ps1 strips it back out. Running install.sh from Git Bash/MSYS aborts and points you at install.ps1.

The installer is idempotent on either platform — re-run after pulling updates.

After install

Start a Claude Code session in any git repo. Work normally — nothing prompts Claude to take notes mid-session. When the session ends, the autonote hook scores the transcript and writes a note only if something non-obvious came up (debug dead-end, surprising library behavior, architectural decision, config in an odd place). After a few sessions you’ll have organic coverage; seed it manually for repos you care about:

# Create a starter note
lorekeeper note <repo-name> architecture
# Opens $EDITOR on $LOREKEEPER_HOME/notes/<repo-name>/architecture.md

Verify everything is wired:

lorekeeper status
# qmd: installed
# collections: lorekeeper-notes, lorekeeper-docs
# hooks: lorekeeper-prime ✓  lorekeeper-reindex ✓  lorekeeper-autonote ✓
# autonote: enabled
# caveman: detected (compressed CLAUDE.md in use)

CLI

lorekeeper status              Check install health
lorekeeper add-repo <name>     Create notes/ and docs/ dirs, register contexts in qmd
lorekeeper note <repo> <slug>  Open $EDITOR on a note (creates from template if missing)
lorekeeper doc <repo> <slug>   Same for docs/
lorekeeper reindex             Force qmd update + embed
lorekeeper distill [repo]      Synthesize durable docs (architecture/runbook/onboarding/
                               conventions/api) from notes + codebase. Must be run from
                               inside the repo's git worktree. Costs a few $ per run.
lorekeeper ls [repo]           List notes/docs per repo

omp support

lorekeeper installs in two surfaces concurrently:

surfacetriggerwhat gets wired
Claude Codealways (unless --no-claude)hook shims under ~/.claude/hooks/, settings.json entries, CLAUDE.md policy block
ompwhen omp and bun are on PATH (unless --no-omp)TS plugin built and symlinked into ~/.omp/plugins/node_modules/@lorekeeper/omp-plugin, AGENTS.md policy block, ~/.omp/.lorekeeper-home marker

Both surfaces share the canonical hooks that the installer drops into $LOREKEEPER_HOME/hooks/{prime,reindex,autonote}.{ps1,sh}. The Claude branch copies them into ~/.claude/hooks/lorekeeper-*.{ps1,sh} so Claude’s settings.json references resolve, while the omp plugin invokes the canonical scripts directly with a Claude-Code-shaped JSON envelope on stdin — one script set, two harnesses.

Coexistence with omp’s Hindsight

omp ships its own per-session memory (Hindsight). lorekeeper does not touch it; the two run side by side. lorekeeper’s value on top of Hindsight is the durable side: qmd-backed semantic search, distill-generated architecture/runbook docs, and ADRs.

omp plugin internals

The plugin lives at omp-plugin/ in this repo and is published structurally as @lorekeeper/omp-plugin. Event mapping:

omp eventaction
session_startspawn hooks/prime with {cwd, session_id, hook_event_name: "SessionStart"}
turn_endappend the turn (user/assistant + tool results) to a synthetic JSONL transcript
tool_resulton write/edit/multiedit/ast_edit/apply_patch success inside $LOREKEEPER_HOME → spawn hooks/reindex
session_shutdownspawn hooks/autonote with the synthetic transcript path

Transcripts live under $LOREKEEPER_HOME/transcripts/<session-id>.jsonl in the same shape Claude Code produces, so autonote runs unmodified across both harnesses.

The autonote classifier still shells out to claude -p for Haiku/Sonnet calls. If you only have omp installed and want autonote to keep working, install the Claude CLI as a soft dependency, or disable autonote with touch $LOREKEEPER_HOME/.autonote-off.

How caveman fits

Caveman is two separate things with different trade-offs:

  1. Caveman skill (output). With the caveman plugin active, Claude’s conversational output is caveman-style. The notes Claude writes under $LOREKEEPER_HOME/notes/ are produced in that same compressed form — so when a future session retrieves them via qmd, the input-token cost of the note is already low. This is the biggest compounding win.

  2. Caveman-compress (input). The global CLAUDE.md block that lorekeeper installs is pre-compressed (see templates/CLAUDE.caveman.md). It loads on every session; compression here saves tokens every time. Installer picks the compressed version when --with-caveman is passed or caveman is already installed.

If you don’t want caveman, pass --no-caveman and the installer uses the uncompressed policy.

Uninstall

Linux/macOS:

~/.local/share/lorekeeper/uninstall.sh

Windows:

powershell -ExecutionPolicy Bypass -File "$env:LOCALAPPDATA\lorekeeper\uninstall.ps1"

Removes the hooks, the CLAUDE.md block, and the qmd collections. Your actual notes/docs are left in place — delete $LOREKEEPER_HOME (Linux/macOS) or %LOCALAPPDATA%\lorekeeper (Windows) by hand if you want them gone.

How the pieces wire together

Claude Code session starts


SessionStart hook ─► reads git toplevel ─► ls $LOREKEEPER_HOME/{notes,docs}/<repo>
    │                                          │
    │                                          ▼
    │               if memory exists: injects index → Claude queries via qmd MCP
    │               if empty:         stays silent  → no hint, no noise

Claude works normally


Session ends → SessionEnd hook fires (detached)

    ├─► structural gate  (≥10 tool calls AND error/decision/shipped keywords?)
    │       │ no → skip
    │       ▼ yes
    ├─► Haiku classifier  ("none | note | feature-doc | adr")
    │       │ none → skip
    │       ▼
    └─► Sonnet drafter (per-kind template)

            ├─ note        → notes/<repo>/<slug>.md              (overwrite = Sonnet-merged)
            ├─ feature-doc → docs/<repo>/<slug>.md               (overwrite = Sonnet-merged)
            └─ adr         → docs/<repo>/adr/ADR-NNNN-<slug>.md  (monotonic numbering)

        then: qmd update && qmd embed, append $LOREKEEPER_HOME/.autonote.log

`lorekeeper distill` (on-demand, not scheduled)

    └─► Sonnet + Read/Glob/Grep/Write inside the repo:
        reads all notes, scans codebase, writes/updates
        docs/<repo>/{architecture,onboarding,runbook,conventions,api}.md
        Hand-curated docs: add <!-- AUTODOC:START --> / <!-- AUTODOC:END -->
        around the sections the distill pass is allowed to rewrite.

Next session: the new note is searchable via MCP immediately.

Turning autonote off

  • Per-install: touch $LOREKEEPER_HOME/.autonote-off (Windows: create %LOCALAPPDATA%\lorekeeper\.autonote-off)
  • Per-session: export LOREKEEPER_AUTONOTE=off before launching claude

License

MIT. See LICENSE.

Credits