reray-grimoire
v0.1.0
Published
Turn Claude Code sessions into a personal knowledge base and devlog drafts you approve before posting.
Maintainers
Readme
ReRay Grimoire
Your Claude Code sessions, automatically distilled into a personal knowledge base — and drafted into devlog posts you approve before anything goes out.
日本語版はこちら / Japanese version here
What it does
- Ingest — when a Claude Code session ends, ReRay Grimoire pulls the transcript, scrubs out secrets, and distills it into a few bullet points: what you did, what you decided, what blocked you, what's left.
- Consolidate — those bullets get merged into one daily note per project, deduplicated across however many sessions you ran that day.
- Draft — on request, it turns a day's daily note into short-form (X) and long-form (blog-style) post drafts.
- Approve — you review each draft, edit if you want, and approve it — which copies the text to your clipboard. ReRay Grimoire never posts anything on its own.
Everything lands in your own Obsidian vault as plain Markdown. No cloud service, no accounts, no telemetry.
Requirements
- Node.js 20+
- Claude Code, installed and logged in — it's what ReRay Grimoire uses as its summarization engine.
That's it. No separate API key to manage — every LLM call (distillation, consolidation, drafting) runs through your existing Claude Code login, on whatever plan you're already paying for.
Quickstart (10 minutes)
1. Install and configure
npx reray-grimoire initYou'll be asked for:
- Your Obsidian vault path (where daily notes and drafts get written)
- One or more projects to track — a name, and the local path to that project's repo
- The language generated content should be written in (default
ja; type anything else — e.g.en— if you want your daily notes and drafts in a different language). This only affects what gets generated; ReRay Grimoire's own CLI output stays English either way.
init does not register any hook — running ingest is a manual step by default. If you want it to run automatically whenever a Claude Code session ends, opt in with reray-grimoire hook enable (see Auto-ingest hook below).
2. Do some work
Use Claude Code as usual, inside one of the repos you registered. When you're done, run reray-grimoire ingest (or check reray-grimoire status first to see how much is waiting).
Already have Claude Code history for a registered project? Start your first backfill small — every session costs real Claude usage to distill, and a large backlog can eat a meaningful share of your plan's usage window in one run. Get a feel for both the output and the consumption before processing everything:
reray-grimoire ingest --limit 53. Check status
reray-grimoire statusFlags anything that needs a look before you go further: a daily note that couldn't be fully deduplicated (see Known limitations), or sessions that look like accidental duplicates.

Recording trimmed for length: distillation takes tens of seconds per session and up, depending on the model and session size. The completion line shows what a run actually cost you (calls and model).
4. Generate drafts
reray-grimoire draftReads today's daily note (or --date <date> for another day) and writes a few X-post drafts to drafts/<project>/. On weekends — or with --long — it also writes a long-form note draft.
5. Review and approve
reray-grimoire postWalks through each draft one at a time:
| Key | Action |
|---|---|
| [s] | Approve — copies the text to your clipboard, moves the file to published/ |
| [e] | Edit in $EDITOR, then come back to this prompt |
| [n] | Skip for now |
| [d] | Discard |
Paste from your clipboard into X, note, or wherever. ReRay Grimoire's job ends at the clipboard — publishing is always a deliberate, manual step.

Recording trimmed for length: draft generation is an LLM call too — expect tens of seconds and up, depending on the model and the day's note size.
That's the whole loop. Most days after this are just steps 2–5: work, then draft, then post.
Optional: browse everything in a browser
reray-grimoire reviewStarts a read-only local web viewer at http://127.0.0.1:54321 — daily notes, drafts, and published posts for every tracked project, with the CLI command for whatever you're looking at ready to copy. Binds to 127.0.0.1 only; there's no way to publish or edit anything from it. Port in use? --port <n> picks a different one.

Usage, by what you're trying to do
- "What's pending before I generate anything?" →
reray-grimoire status - "I want to turn yesterday's work into a long-form note." Don't count on remembering the right flags tomorrow — write it down now:
reray-grimoire draft --date <date> --long. (--datedefaults to today, and a note only gets generated on weekends unless you pass--long— the kind of thing that's obvious today and easy to forget by the time you actually need it.) - "I only want the short X-post drafts, not a long note." →
reray-grimoire draft --date <date>on a weekday, without--long. - "A daily note is stuck at
consolidated: falseanddraftrefuses to run." →reray-grimoire statusshows why. See Known limitations below (Issue A). - "I think two sessions got logged as duplicates." →
reray-grimoire statuslists duplicate candidates by matching opening content. Nothing gets auto-deleted; it's your call. - "I ingested a big backfill and want to try just a few sessions first." →
reray-grimoire ingest --limit <n>. - "I want to see what would be ingested before committing to it." →
reray-grimoire ingest --inspect --project <name>— dumps the parsed session content and an estimated LLM-call count, without writing anything. - "I want generated content in English (or any other language) instead of Japanese." → edit
languagein~/.reray-grimoire/config.json(see Configuration).
Why ReRay Grimoire works the way it does
Why it never posts automatically. Distillation and drafting are automated; the decision to publish is not, and never will be. An LLM's job here is to summarize what you did — not to decide what's worth telling people, or how to phrase it in public. post copies approved text to your clipboard and stops there; you paste it yourself. That boundary isn't a missing feature — it's the point. A personal devlog tool that could post on your behalf is one bad prompt away from saying something you never meant to say, in public, under your name.
Why everything gets scrubbed. Real session transcripts routinely contain API keys, tokens, internal hostnames, and client names, because that's what real development work looks like. Every string that reaches an LLM prompt, and every string an LLM generates, passes through one scrubbing gateway (scrubText) before it's used anywhere — not "scrubbed sometimes," not "scrubbed for the parts we remembered." One function, every path in and out. See src/core/scrub.ts.
Why it's local-only. Your vault is plain Markdown on your own disk. There's no server, no account, no telemetry, and no cloud dependency beyond the LLM call itself. grimoire review binds to 127.0.0.1 and nothing else. Stop using this tool at any point and you keep a vault full of ordinary Markdown files — nothing is locked in.
Known limitations
This is a tool its own author uses daily, and its rough edges are tracked openly in ISSUES.md rather than smoothed over. A few worth knowing before you start:
- Session-to-project attribution follows your working directory, not your intent. Claude Code logs a session under whichever directory you ran it from, so doing project B's work inside project A's repo attributes that session to project A. Keep separate projects in separate directories. See Issue B.
- Very active days can outrun daily-note consolidation. Deduplicating a day's notes means comparing every item against every other item in one LLM pass; past roughly 40 items that stops being reliably fast, and a genuinely busy day (hundreds of items) can exceed even a generous timeout. When that happens the note is marked
consolidated: false— or partially merged — instead of silently losing content, andstatussurfaces it.draftwon't run against a day in that state until you've looked at it. See Issue A. - A
--resume'd Claude Code session can duplicate content under a second session ID. Claude Code sometimes writes a resumed session to a brand-new file that replays the original opening verbatim. ReRay Grimoire detects this (by hashing each session's opening) and warns viastatus— it never auto-deletes anything; that decision stays yours. See Issue D.
None of these are secret, and none are excuses — they're the actual tradeoffs of a tool that ingests messy real transcripts and tries to stay fast and safe rather than slow and complete. The full list, including ones already fixed, is in ISSUES.md.
Configuration
~/.reray-grimoire/config.json, written by init:
{
"vaultPath": "/path/to/your/Obsidian/vault",
"projects": [
{ "name": "my-project", "repoPath": "/path/to/my-project", "claudeProjectDir": "auto" }
],
"summarizer": { "adapter": "claude-cli", "model": "sonnet", "concurrency": 3 },
"scrub": { "ngWords": [], "maskToken": "[REDACTED]" },
"draft": { "xVariants": 3, "noteOnWeekend": true },
"consolidation": { "maxItems": 40 },
"ingest": { "maxCallsPerRun": 50, "maxCallsPerHookRun": 15, "maxConsecutiveFailures": 5 },
"tmp": { "pruneDays": 7 },
"timezone": "Asia/Tokyo",
"language": "ja"
}Fields worth knowing about:
language— the language generated content (daily notes, drafts) is written in. Defaults to"ja"; set it to"en"or any other language name. The tool's own CLI messages and errors are always English, independent of this setting.scrub.ngWords— add client or company names here so they get masked wherever they'd otherwise appear in generated drafts. Never commit this file — it lives outside the repo (~/.reray-grimoire/) on purpose.consolidation.maxItems— the safety threshold discussed in Known limitations. Raising it buys more headroom before a day gets markedconsolidated: false, but doesn't change the underlying scaling limit — see Issue A before assuming a higher number will just work.summarizer.model— which Claude model every distillation and consolidation call runs on, and therefore the single biggest lever on how much of your plan's usage windowingestconsumes. Defaults to"sonnet": in a real A/B comparison on actual sessions, switching from Opus to Sonnet cut usage-window consumption dramatically while producing visually equivalent output for both distillation and consolidation (items, decision rationales, and measured numbers all survived intact). Set"opus"if you want to trade budget for maximum quality. Avoid"default"unless you mean it: it passes no--modelflag, so each call silently uses whatever your Claude Code CLI is configured to — which can be Opus without you noticing. Theingestcompletion message shows the model actually used, so you can verify what a run cost you.summarizer.concurrency— how many sessionsingestdistills in parallel. Defaults to3.
Auto-ingest hook (optional)
By default, nothing runs automatically — ingest is something you run yourself, whenever you like. If you'd rather have it happen on its own:
reray-grimoire hook enable # register a SessionEnd hook in ~/.claude/settings.json
reray-grimoire hook status # check whether it's currently registered
reray-grimoire hook disable # remove it
The registered hook command is just reray-grimoire ingest --quiet --hook — Claude Code runs it via your shell, so reray-grimoire needs to actually resolve on PATH at that point (a global install, or npm link from a checkout). If you've only ever run it through npx reray-grimoire, the hook won't find the command and will silently fail — install it globally first (npm install -g reray-grimoire) before running hook enable.
hook enable registers reray-grimoire ingest --quiet --hook, which runs automatically every time a Claude Code session ends, across every project you've registered. Two things guard against runaway automatic runs:
Only one
ingestcan run at a time (a lock file under~/.reray-grimoire/) — a session ending while a prior auto-run is still in flight is a no-op instead of a second run stacking up.ingestrefuses to run at all if it detects it's being invoked from inside aclaude -pprocess that ReRay Grimoire itself spawned (its own distillation calls) — so the hook can't re-trigger itself through its own child sessions. It detects this via theRERAY_GRIMOIRE_CHILD_SESSION=1environment variable, which ReRay Grimoire sets on everyclaude -pprocess it spawns for distillation.If you register your own global
SessionEnd(or other) hooks, treatRERAY_GRIMOIRE_CHILD_SESSIONas a general-purpose signal, not something private to this tool: a hook fires for every Claude Code session that ends, including ReRay Grimoire's own child ones, and there's no other way to tell them apart from the outside. Check for it near the top of your own hook and exit early if it's set — otherwise your hook will fire once per distillation call during a largeingestrun (dozens to hundreds of times), not once per real session.
This is opt-in on purpose: see ISSUES.md Issue N for the incident that motivated making it opt-in rather than the default.
Uninstall
- If you enabled the hook, run
reray-grimoire hook disable(or manually: open~/.claude/settings.jsonand, underhooks.SessionEnd, delete the entry whosecommandstarts with"reray-grimoire ingest"— leave any other hooks in that array alone). - Delete
~/.reray-grimoire/(config and ingest state). - Uninstall the package (
npm uninstall -g reray-grimoire, or however you installed it).
Your vault is untouched by any of this — daily/, sessions/, knowledge/, drafts/, and published/ stay right where they are, as ordinary Markdown files you can keep, move, or delete independently of the tool.
Development
git clone https://github.com/mml-kobayashi/reray-grimoire.git
cd reray-grimoire
npm install
npm run typecheck && npm test && npm run buildSee ISSUES.md for the current list of known issues and the design tradeoffs behind them.
License
MIT — see LICENSE.
