Using Rekal
July 25, 2026 · View on GitHub
This is the operational guide: how the two databases fit together, what travels over git and what stays local, how agents query, and how the skill routes. For the marketing overview and quick start, see the README; for tuning, see configuration.md.
Setup and teardown
cd your-project
rekal init
rekal init creates the following on your system:
.rekal/directory containingdata.db(shared truth) andindex.db(local search index)- A
post-commitandpre-pushgit hook (marked# managed by rekal) - The Claude Code skill under
.claude/skills/rekal/(see the agent skill) - One marker-tagged sentence in
CLAUDE.mdpointing agents at the skill (created if missing; your own content is never touched) - For each other AI agent detected on your machine, one marker-tagged line
in the file it reads:
AGENTS.md(Codex / Cursor / OpenCode),GEMINI.md(Gemini),.github/copilot-instructions.md(Copilot), or.kiro/steering/rekal.md(Kiro). Detection is per machine — a teammate who clones the repo and uses a different agent re-runsrekal initto add theirs. A file Rekal newly creates is gitignored (it's machine-specific, so it stays local); a file you already track keeps its tracked status and just gains the one line. - An orphan branch
rekal/<your-email>for transport - Appends
.rekal/to your.gitignore
Skill files also self-heal: the next recall after a binary upgrade compares the
pinned .rekal-version in .claude/skills/ to the running binary and
re-installs the skill when it lags (hooks and instruction files are not
touched). Running rekal init again in an already-initialized repo does
not rebuild your store — it refreshes the skill, hooks, CLAUDE.md marker,
and detected-agent rules, and leaves your data untouched. A full reinitialize
still requires rekal clean first.
rekal clean
rekal clean removes everything init created:
- Deletes the
.rekal/directory and all its contents - Removes the git hooks (only the ones marked
# managed by rekal) - Removes the installed skill (
.claude/skills/rekal/plus any legacyrekal-*companion dirs), pruning.claude/skills/and.claude/only if they are left empty — your own.claudecontent is never touched - Removes the marker-tagged
CLAUDE.mdsentence (deleting the file only if nothing else remains)
No residue. If you want to start over, run clean then init.
rekal version
When a newer release is available, the CLI prints an update notice after each command.
Two databases
Rekal keeps two local DuckDB databases in .rekal/. The split is deliberate —
thin on the wire, rich on the machine.
data.db— the shared truth. Append-only. Sessions, turns, tool calls, checkpoints, files touched — every branch, merged or not. This is the only sourcerekal pushencodes from (filtered to merged work — see below), and whatrekal queryreads.index.db— local intelligence. Full-text indexes, vector embeddings, file co-occurrence graphs, knowledge chunks. Never synced. Rebuilt anytime withrekal index. This is what powersrekal "<query>"search.
Orphan branches and what gets shared
Rekal data lives on git orphan branches named rekal/<email>. These branches
have no common ancestor with your code branches — they never appear in your
project history, never affect merges, and never clutter your working tree.
Standard git push/git fetch move the data.
Your local databases keep every branch — full fidelity, nothing gated. The
wire is different: rekal push shares a session only when its code landed on
the default branch, detected two ways, both exact:
- its commit is an ancestor of
main(merge-commit and rebase workflows), or - its branch's changes landed as a squash merge (patch-equivalence detection — no heuristics)
Unmerged work simply waits: it stays local, is re-checked on every push, and ships automatically the moment its branch merges. Abandoned branches never qualify, so a dead-end spike never reaches your teammates. Commit everything for yourself; share only what merged.
Worktrees
Linked git worktrees (git worktree add) share one .rekal/ store — the
one in the main checkout. Init once in the main repo; every worktree then reads
and writes the same data, index, and config, so there's no per-worktree
rekal sync or reindex. Checkpoints still record the branch and commit of
whichever worktree you committed in. A repo that never uses worktrees is
unaffected — the store is just its own .rekal/.
How your agent uses it
The agent controls how much context it loads: search first, drill down progressively, load full sessions only when needed.
| Agent does | Rekal does |
|---|---|
rekal "auth middleware" | Hybrid search (BM25 + LSA + deep embed + facets) plus a separate knowledge block for prose at HEAD; returns a seed digest (INJECT/KNOWLEDGE/SILENCE + per-seed conf and a drill pointer), or structured confidence / mass JSON with --json |
rekal find "auth middleware" | Complete, time-ordered enumeration of every ledger mention — for "all / every / how many" asks |
rekal query --session <id> --offset N --limit 5 | Readable window of turns around the relevant part (--json for one object; has_more for pagination) |
rekal query --session <id> --role human | Returns only human turns — cheapest way to understand session intent |
rekal query --session <id> --full | Returns everything: turns, tool calls, files touched — only when the agent needs full detail |
rekal --file src/billing/ "discount" | Scoped search filtered by file path |
rekal --commit <sha> | Finds the session(s) that produced a commit — the anchor for change provenance |
rekal --explain "…" | Adds per-layer scores and related-session joins (JSON shape; pair with --json) |
rekal query --session <id> --role human_steering | Returns only the mid-course corrections — the highest-signal turns for intent and preferences |
rekal query --session <id> --role summary | Returns the harness-written compaction distillations — the cheapest overview of a long session |
rekal query --sql "SELECT …" | Analytical / temporal SQL → TSV rows (--json for NDJSON; --index for index DB) |
rekal embed | Fill missing semantic vectors (also started in the background after index / sync) |
rekal sync (optional, at session start) | Pulls team context before the agent starts working |
# Agent touches src/billing/ — first, recall prior context
rekal --file src/billing/ "discount logic"
# Agent finds a relevant session, drills into the matching turn
rekal query --session 01JNQX... --offset 10 --limit 5
# Agent loads full detail only if needed
rekal query --session 01JNQX... --full
The agent skill
The raw commands above are the interface; the skill is the playbook.
rekal init installs one Claude Code skill under .claude/skills/rekal/ — a
thin route (substrate triage + silence + dispatch) plus on-demand references/
and a couple of built-in gate scripts/ (progressive disclosure). Retrieval and
navigation are commands in the binary, not scripts. The agent never picks among
skills; it classifies the question, routes to one substrate, and loads only the
module it needs. For a question that belongs to the past-reasoning ledger, a
second step classifies the answer type and loads exactly one specialist
workflow — so a "how long", a "how many", and a "when" each get concentrated,
non-overlapping guidance. Design detail:
design/skill-router.md.
flowchart TB
tip["SKILL.md route<br/>always loaded, thin"]
tip --> triage{"Which substrate?"}
triage -->|Tree now| grep["grep / read HEAD"]
triage -->|Knowledge| readk["rekal '<q>' → Read HEAD prose"]
triage -->|Map| mapf["map.sh fresh → map.md"]
triage -->|Ledger / past reasoning| gate{"Answer type?"}
gate -->|duration| w1["workflows/duration.md"]
gate -->|count / set| w2["workflows/complete-set.md"]
gate -->|event time| w3["workflows/event-time.md"]
gate -->|inference| w4["workflows/inference.md"]
gate -->|fact / why| w5["workflows/point-fact.md"]
| Home | What |
|---|---|
Route (SKILL.md) | Thin. Decide substrate: tree (grep, now) / knowledge (prose at HEAD) / ledger (past) / map. For a ledger question, classify the answer type and route to exactly one workflow. Trusts reasoning; silence when memory is the wrong tool. |
| Commands (in the binary) | rekal "<q>" (seed digest: INJECT/KNOWLEDGE/SILENCE + per-seed confidence), rekal find (complete-set sweep), rekal query --session/--sql (drill / analytical). Compact text by default, --json for machines. |
Knowledge (references/) | Rich, on demand: ledger.md (reasoning over the past — recall, widen, time-axis, enumeration, why-arcs, provenance, analytical SQL) · references/workflows/ (five answer-type specialists: duration, complete-set, event-time, inference, point-fact) · map · wiki · flags/SQL. Read one and stop. |
Gates (scripts/) | The two workflow gates that remain scripts: map.sh (fresh/watermark), wiki-gate.sh. |
flowchart LR
j["rekal '<q>'"] --> dg["seed digest"]
dg -->|confident episode| i["INJECT + per-seed conf<br/>even if knowledge present"]
dg -->|else + knowledge| k["KNOWLEDGE — Read HEAD"]
dg -->|else| s["SILENCE"]
Skills are versioned with the binary. After you upgrade, run rekal init once
to refresh them (it leaves your data untouched; legacy rekal-* dirs are
removed).
Starting from Claude Code — the plugin
If you'd rather not start at a shell, this repository is also a plugin marketplace:
/plugin marketplace add rekal-dev/rekal-cli
/plugin install rekal@rekal-dev
The plugin is setup only — two commands:
| Command | Scope |
|---|---|
/rekal:install | once per machine — installs the binary |
/rekal:init | once per repository — runs rekal init |
Both confirm before touching anything, and both are model-invoked too: a rekal
command reporting command not found routes to the first, not initialized to
the second. The plugin also ships the installer itself on PATH
(bin/rekal-install), so setup runs code that came with the plugin rather than a
live curl | bash.
The recall skill above is not in the plugin; rekal init installs it, versioned
with the binary whose commands it describes. Shipping it in both places would put
two copies in your context and let the plugin's copy drift ahead of your
installed binary. Detail:
design/plugin-distribution.md.
Cross-repo recall (optional)
Your agent's memory can span your whole machine, not just this repo:
rekal index --include-all # recall every local agent session (all agents, repos + shell)
rekal index --include /path/to/repo # just that repo
rekal index --no-local # back to this repo only
Imported sessions live in the index only — never in data.db, which is the
only thing push reads — so they are structurally impossible to share. Results
are labeled with their origin (repo:/path, shell:/path). The setting
persists across rebuilds.
Ad-hoc usage
# Raw SQL for edge cases
rekal query "SELECT id, user_email, branch FROM sessions ORDER BY captured_at DESC LIMIT 5"
# Rebuild the search index after manual DB changes
rekal index
# View recent checkpoints
rekal log