{"id":49965677,"url":"https://github.com/sizzlorox/lorekeeper","last_synced_at":"2026-05-23T06:05:20.076Z","repository":{"id":353709340,"uuid":"1216734690","full_name":"sizzlorox/lorekeeper","owner":"sizzlorox","description":"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.","archived":false,"fork":false,"pushed_at":"2026-05-18T03:57:27.000Z","size":134,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-18T05:42:34.147Z","etag":null,"topics":["bash","claude-code","claude-code-hook","developer-tools","linux","macos","mcp","memory","powershell","qmd","rag","windows"],"latest_commit_sha":null,"homepage":"","language":"PowerShell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sizzlorox.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-21T07:21:42.000Z","updated_at":"2026-05-18T03:55:27.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/sizzlorox/lorekeeper","commit_stats":null,"previous_names":["sizzlorox/lorekeeper"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/sizzlorox/lorekeeper","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sizzlorox%2Florekeeper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sizzlorox%2Florekeeper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sizzlorox%2Florekeeper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sizzlorox%2Florekeeper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sizzlorox","download_url":"https://codeload.github.com/sizzlorox/lorekeeper/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sizzlorox%2Florekeeper/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33384606,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-23T04:15:53.637Z","status":"ssl_error","status_checked_at":"2026-05-23T04:15:53.242Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bash","claude-code","claude-code-hook","developer-tools","linux","macos","mcp","memory","powershell","qmd","rag","windows"],"created_at":"2026-05-18T05:17:08.639Z","updated_at":"2026-05-23T06:05:20.071Z","avatar_url":"https://github.com/sizzlorox.png","language":"PowerShell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# lorekeeper\n\nAutonomous per-repo memory for Claude Code and [oh-my-pi (omp)](https://github.com/can1357/oh-my-pi), backed by [qmd](https://github.com/tobi/qmd) for local semantic search and [caveman](https://github.com/JuliusBrussee/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.\n\n```\n$XDG_DATA_HOME/lorekeeper/\n├── notes/\u003crepo\u003e/    # session-to-session memory: gotchas, decisions, conventions\n└── docs/\u003crepo\u003e/     # durable reference docs: overview, architecture, runbook\n```\n\n## What it does\n\n- **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.\n- **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:\n    - `note` → `notes/\u003crepo\u003e/\u003cslug\u003e.md` — scratch gotcha, decision, or non-obvious behavior. Merges in place when slug matches an existing note.\n    - `feature-doc` → `docs/\u003crepo\u003e/\u003cslug\u003e.md` — completed feature doc (overview, how it works, config, usage). Merges in place when slug matches an existing doc.\n    - `adr` → `docs/\u003crepo\u003e/adr/ADR-NNNN-\u003cslug\u003e.md` — architecture decision record with context / decision / consequences / alternatives. Sequential numbering.\n\n  No mid-session hinting to Claude. Disable with `touch $LOREKEEPER_HOME/.autonote-off` or `LOREKEEPER_AUTONOTE=off`.\n\n- **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 `\u003c!-- AUTODOC:START --\u003e` / `\u003c!-- AUTODOC:END --\u003e` 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.\n- **Re-indexes itself.** A `PostToolUse` hook runs `qmd update \u0026\u0026 qmd embed` in the background whenever Claude writes under the notes/docs tree. The autonote hook triggers the same reindex directly after it writes.\n- **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.\n\n## Requirements\n\n**All platforms**\n\n- Claude Code CLI (≥ 2.1)\n- Node.js ≥ 22\n- `git`\n- Optional: [caveman](https://github.com/JuliusBrussee/caveman) plugin for token reduction\n\n**Linux/macOS only**\n\n- `jq` (for `settings.json` merging in the bash installer)\n\nqmd is installed by the installer if missing.\n\n## Install\n\n### Linux / macOS\n\n```bash\ngit clone https://github.com/sizzlorox/lorekeeper ~/.local/share/lorekeeper\n~/.local/share/lorekeeper/install.sh\n```\n\nOptional flags:\n\n```bash\n./install.sh --with-caveman         # also install caveman plugin\n./install.sh --lorekeeper-home PATH # override data dir (default: $XDG_DATA_HOME/lorekeeper)\n./install.sh --no-embed-bootstrap   # skip initial qmd embed (faster install, do it later)\n./install.sh --no-claude            # skip Claude Code wiring (omp-only install)\n./install.sh --no-omp               # skip omp plugin install (Claude-only install)\n```\n\n### Windows\n\nUse the native PowerShell installer — no bash, no `jq` needed. Works in PowerShell 5.1 (built into Windows) or PowerShell 7+.\n\n**Extra prerequisite:** [Git for Windows](https://git-scm.com/download/win). `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.\n\n```powershell\ngit clone https://github.com/sizzlorox/lorekeeper \"$env:LOCALAPPDATA\\lorekeeper\"\npowershell -ExecutionPolicy Bypass -File \"$env:LOCALAPPDATA\\lorekeeper\\install.ps1\"\n```\n\nFlags mirror the bash installer:\n\n```powershell\n.\\install.ps1 -WithCaveman\n.\\install.ps1 -LorekeeperHome C:\\path\\to\\data\n.\\install.ps1 -NoEmbedBootstrap\n.\\install.ps1 -NoClaude              # skip Claude Code wiring (omp-only install)\n.\\install.ps1 -NoOmp                 # skip omp plugin install (Claude-only install)\n```\n\nDefaults on Windows:\n\n| item              | path                                           |\n| ----------------- | ---------------------------------------------- |\n| data home         | `%LOCALAPPDATA%\\lorekeeper`                    |\n| claude config     | `%USERPROFILE%\\.claude`                        |\n| CLI (`lorekeeper.cmd`) | `%LOCALAPPDATA%\\lorekeeper\\bin`           |\n| hook scripts      | `%USERPROFILE%\\.claude\\hooks\\lorekeeper-*.ps1` |\n\nThe 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`.\n\nThe installer is idempotent on either platform — re-run after pulling updates.\n\n## After install\n\nStart 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:\n\n```bash\n# Create a starter note\nlorekeeper note \u003crepo-name\u003e architecture\n# Opens $EDITOR on $LOREKEEPER_HOME/notes/\u003crepo-name\u003e/architecture.md\n```\n\nVerify everything is wired:\n\n```bash\nlorekeeper status\n# qmd: installed\n# collections: lorekeeper-notes, lorekeeper-docs\n# hooks: lorekeeper-prime ✓  lorekeeper-reindex ✓  lorekeeper-autonote ✓\n# autonote: enabled\n# caveman: detected (compressed CLAUDE.md in use)\n```\n\n## CLI\n\n```\nlorekeeper status              Check install health\nlorekeeper add-repo \u003cname\u003e     Create notes/ and docs/ dirs, register contexts in qmd\nlorekeeper note \u003crepo\u003e \u003cslug\u003e  Open $EDITOR on a note (creates from template if missing)\nlorekeeper doc \u003crepo\u003e \u003cslug\u003e   Same for docs/\nlorekeeper reindex             Force qmd update + embed\nlorekeeper distill [repo]      Synthesize durable docs (architecture/runbook/onboarding/\n                               conventions/api) from notes + codebase. Must be run from\n                               inside the repo's git worktree. Costs a few $ per run.\nlorekeeper ls [repo]           List notes/docs per repo\n```\n\n## omp support\n\nlorekeeper installs in two surfaces concurrently:\n\n| surface     | trigger             | what gets wired                                                              |\n| ----------- | ------------------- | ---------------------------------------------------------------------------- |\n| Claude Code | always (unless `--no-claude`)   | hook shims under `~/.claude/hooks/`, `settings.json` entries, `CLAUDE.md` policy block |\n| omp         | when `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 |\n\nBoth surfaces share the **canonical hooks** that the installer drops into\n`$LOREKEEPER_HOME/hooks/{prime,reindex,autonote}.{ps1,sh}`. The Claude branch\ncopies them into `~/.claude/hooks/lorekeeper-*.{ps1,sh}` so Claude's\n`settings.json` references resolve, while the omp plugin invokes the\ncanonical scripts directly with a Claude-Code-shaped JSON envelope on\nstdin — one script set, two harnesses.\n\n### Coexistence with omp's Hindsight\n\nomp ships its own per-session memory ([Hindsight](https://github.com/can1357/oh-my-pi)).\nlorekeeper does not touch it; the two run side by side. lorekeeper's value\non top of Hindsight is the durable side: qmd-backed semantic search,\n`distill`-generated architecture/runbook docs, and ADRs.\n\n### omp plugin internals\n\nThe plugin lives at `omp-plugin/` in this repo and is published structurally\nas `@lorekeeper/omp-plugin`. Event mapping:\n\n| omp event           | action                                                                        |\n| ------------------- | ----------------------------------------------------------------------------- |\n| `session_start`     | spawn `hooks/prime` with `{cwd, session_id, hook_event_name: \"SessionStart\"}` |\n| `turn_end`          | append the turn (user/assistant + tool results) to a synthetic JSONL transcript |\n| `tool_result`       | on `write`/`edit`/`multiedit`/`ast_edit`/`apply_patch` success inside `$LOREKEEPER_HOME` → spawn `hooks/reindex` |\n| `session_shutdown`  | spawn `hooks/autonote` with the synthetic transcript path                       |\n\nTranscripts live under `$LOREKEEPER_HOME/transcripts/\u003csession-id\u003e.jsonl` in\nthe same shape Claude Code produces, so `autonote` runs unmodified across\nboth harnesses.\n\nThe autonote classifier still shells out to `claude -p` for Haiku/Sonnet\ncalls. If you only have omp installed and want autonote to keep working,\ninstall the Claude CLI as a soft dependency, or disable autonote with\n`touch $LOREKEEPER_HOME/.autonote-off`.\n\n## How caveman fits\n\nCaveman is two separate things with different trade-offs:\n\n1. **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.\n\n2. **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.\n\nIf you don't want caveman, pass `--no-caveman` and the installer uses the uncompressed policy.\n\n## Uninstall\n\nLinux/macOS:\n\n```bash\n~/.local/share/lorekeeper/uninstall.sh\n```\n\nWindows:\n\n```powershell\npowershell -ExecutionPolicy Bypass -File \"$env:LOCALAPPDATA\\lorekeeper\\uninstall.ps1\"\n```\n\nRemoves 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.\n\n## How the pieces wire together\n\n```\nClaude Code session starts\n    │\n    ▼\nSessionStart hook ─► reads git toplevel ─► ls $LOREKEEPER_HOME/{notes,docs}/\u003crepo\u003e\n    │                                          │\n    │                                          ▼\n    │               if memory exists: injects index → Claude queries via qmd MCP\n    │               if empty:         stays silent  → no hint, no noise\n    ▼\nClaude works normally\n    │\n    ▼\nSession ends → SessionEnd hook fires (detached)\n    │\n    ├─► structural gate  (≥10 tool calls AND error/decision/shipped keywords?)\n    │       │ no → skip\n    │       ▼ yes\n    ├─► Haiku classifier  (\"none | note | feature-doc | adr\")\n    │       │ none → skip\n    │       ▼\n    └─► Sonnet drafter (per-kind template)\n            │\n            ├─ note        → notes/\u003crepo\u003e/\u003cslug\u003e.md              (overwrite = Sonnet-merged)\n            ├─ feature-doc → docs/\u003crepo\u003e/\u003cslug\u003e.md               (overwrite = Sonnet-merged)\n            └─ adr         → docs/\u003crepo\u003e/adr/ADR-NNNN-\u003cslug\u003e.md  (monotonic numbering)\n\n        then: qmd update \u0026\u0026 qmd embed, append $LOREKEEPER_HOME/.autonote.log\n\n`lorekeeper distill` (on-demand, not scheduled)\n    │\n    └─► Sonnet + Read/Glob/Grep/Write inside the repo:\n        reads all notes, scans codebase, writes/updates\n        docs/\u003crepo\u003e/{architecture,onboarding,runbook,conventions,api}.md\n        Hand-curated docs: add \u003c!-- AUTODOC:START --\u003e / \u003c!-- AUTODOC:END --\u003e\n        around the sections the distill pass is allowed to rewrite.\n\nNext session: the new note is searchable via MCP immediately.\n```\n\n### Turning autonote off\n\n- Per-install: `touch $LOREKEEPER_HOME/.autonote-off`  (Windows: create `%LOCALAPPDATA%\\lorekeeper\\.autonote-off`)\n- Per-session: `export LOREKEEPER_AUTONOTE=off` before launching `claude`\n\n## License\n\nMIT. See [LICENSE](LICENSE).\n\n## Credits\n\n- [tobi/qmd](https://github.com/tobi/qmd) — local hybrid search engine that does the actual retrieval\n- [JuliusBrussee/caveman](https://github.com/JuliusBrussee/caveman) — token compression for agents\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsizzlorox%2Florekeeper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsizzlorox%2Florekeeper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsizzlorox%2Florekeeper/lists"}