| name | lore |
| description | Use to recall anything from past agent sessions with the server-free `lore` CLI — the "what did we decide", "how did we build X", "why did we drop Y", "find that earlier conversation", "pull context from my last session" task. Trigger whenever you need memory of prior work (yours or another harness's) — searching transcripts by keyword or recency, reading a remembered message back in full, seeing what surrounded it, skimming or jumping around a past session, listing recent sessions, or charting when a project was active. Also covers writing new memory in live (`lore push`). This skill is self-bootstrapping — if the CLI isn't installed or your sessions aren't indexed yet, it covers setup too (detail in references/setup/index.md) — installing lore, indexing or backfilling a harness (Claude Code, Codex, Cursor, Cline, openclaw, Hermes, or any tool that records transcripts), teaching lore a new format by writing and proving an adapter, registering the MCP server, wiring freshness hooks, or feeding a live process via push. lore is a local SQLite store; this skill drives it entirely through the CLI, so NOTHING here needs the MCP server running. Reach for this skill even when the user just says "remember", "recall", "last time", "previously", "search my history", "index my sessions", or "set up lore" without naming lore. |
lore
lore is your long-term memory: a local SQLite + FTS5 store of agent session
transcripts at ~/.lore/lore.db, shared by every harness on this machine
(claude-code, codex, cursor, …). This skill drives the whole app from the
CLI. The lore command opens the SQLite file directly, so every task here —
find, read back, navigate, write — works with no server and no client. The
MCP server (lore serve) is just one more reader of the same store; you never
need it to use lore.
If lore help errors, the CLI isn't installed yet — and if a search comes back
empty because a harness was never indexed, that's the onboarding job. Both are
covered by this same skill: read references/setup/index.md to install lore, index
or backfill a harness, teach lore a new format, or feed a live process, then come
back here to use what you indexed. This skill self-bootstraps the low-level CLI substrate; for higher-level workflows, route to the workflow skills below instead of re-inventing their output contracts.
Workflow skills built on top of lore
Use this lore skill for the raw substrate: install, index, sync, search, get, context, session navigation, push, and destructive-memory safety. When the task is not just retrieval mechanics, hand the work to the workflow skill that owns the behavior:
lore-recall (lore:recall in product docs): use for bounded memory answers, query plans, freshness labels, evidence packets, and retrieval-failure ledgers. It should still call the CLI commands documented here, but it owns the reasoning workflow and packet shape.
lore-brief (lore:brief): use for daily/rolling continuity briefs, proposal-only synthesis, learned signals, memory-card candidates, and contradiction candidates. It must not create jobs, issues, wiki pages, skills, tasks, memory cards, code, or automations unless the user explicitly asks for that follow-up.
lore-handoff (lore:handoff): use for compact continuation packets for the next agent, with verified/open/stale/risky sections, artifacts, proposals, memory-card candidates, contradiction candidates, and next actions.
lore-dev-verification (lore:dev-verification): use when changing this repository, workflow skills, CLI/MCP retrieval, packaging, adapters, store compatibility, privacy, or destructive-memory behavior.
If a workflow skill reports that Lore is stale or unsynced, come back to this skill for the mechanical recovery command (lore sync, lore index, hook setup, or adapter work). If lore status --json shows schemaVersion greater than supportedSchemaVersion, read-only search may work but write recovery such as lore sync can be refused; update Lore before promising that sync will fix freshness.
The one rule that governs everything: drill down, never dump
A session can be thousands of messages — millions of tokens. Never pull a whole
session into context. Every command here returns a bounded amount on purpose;
your job is to narrow from a broad question to the few messages that actually
answer it. The loop is always the same, and it is self-threading:
broad words ──▶ lore search ──▶ output hands you real ids
(message <id>, session <id>)
│
pick the id you want ─────────────┘
▼
lore get <id> --full (read that one message in full)
lore context <id> (see what surrounded it)
lore session <id> --around <id> (jump into that spot in the session)
You never invent an id. Every id you pass to get / context / session
came verbatim out of a previous command's output. Searching is how you discover
ids; the drill-down commands are how you spend them. If you catch yourself about
to page through an entire session to "find" something, stop — that's what
lore search --session <id> is for.
Lead with the narrowest query that could work. Broaden (drop filters, switch to
--relevant) only if it comes back empty. Reading one message in full beats
skimming fifty snippets.
Find — lore search
Keyword search (bm25) across every indexed session. This is the front door:
lore search "fts tokenizer"
lore search "fts tokenizer" --relevant
lore search "alamo" --json
Each hit leads with its message <id> and session <id> — those are the keys
you drill with next. Snippets are elided; pull the full text with lore get <id> --full.
Filters (all optional, combine freely):
| flag | scopes to |
|---|
--project <path> | one repo/project |
--source <name> | one harness namespace (claude-code, codex, …) |
--session <id> | one conversation (everything matching, inside it) |
--branch <name> | one git branch |
--agent <name> / --skill <name> / --tool <name> | messages that used a named agent/skill/tool |
--role user|assistant|system | one speaker |
--model <name> | one model |
--since <iso> / --until <iso> | a time window |
--limit <n> | cap the hit count |
--relevant reranks by keyword strength × recency (1/(1+ageHours)), so a fresh
memory beats an old one with the same words. It honors every filter above —
including --session, which makes it a strict superset of the MCP
find_relevant tool. Use it for "what did I do recently about X"; use plain
search for "find the best keyword match, whenever it happened."
Read back — lore get, lore context
Once search hands you an id, read it:
lore get <message-id>
lore get <message-id> --full
lore get <message-id> --json
To see what was happening around a message — the question that prompted an
answer, the reply that followed a decision:
lore context <message-id>
lore context <message-id> --before 2 --after 8
lore context <message-id> --json
An unknown id returns { "error": "not_found", "message_id": "…" } and a
non-zero exit — the same envelope MCP gives, so a script can branch on it.
Navigate — lore session, lore sessions, lore timeline
Skim or jump within one session. lore session walks a session's folded
timeline (primary + subagent messages interleaved in real time) a bounded page
at a time. It never dumps — a cursor carries you forward:
lore session <session-id>
lore session <session-id> --limit 40 --cursor <c>
lore session <session-id> --around <message-id>
lore session <session-id> --around <message-id> --before 10 --after 10
The human output trails each page with the exact --cursor command to continue.
--json gives { messages, nextCursor } (paged) or { messages } (--around),
matching MCP get_session. Prefer --around over page-walking: if search already
gave you the id you care about, jump to it instead of reading from the top.
List recent conversations to find a session id when you don't have one:
lore sessions
lore sessions --project <path> --source codex --limit 20
lore sessions --json
Each rollup shows message count, project, and time span. Copy a sessionId
straight into lore search --session <id> or lore session <id>.
Chart activity over time — useful for picking a --since/--until window or
spotting when a project was hot:
lore timeline
lore timeline --bucket hour --project <path>
lore timeline --json
Write memory in live — lore push
To add a session that has no on-disk transcript (a live process, a homegrown
tool), pipe one normalized JSON batch to lore push:
echo "$BATCH_JSON" | lore push
cat batch.json | lore push
The batch is { sourceFile, messages, toolCalls } (the exact shape of the MCP
push tool). It's validated whole at the boundary and written idempotently —
re-pushing the same batch never duplicates. On success it prints the write result
({ sourceFileId, sessionId, messages, toolCalls }) and exits 0. On a malformed
batch it prints { "error": "invalid_batch", "detail": "…" } and exits non-zero,
so a caller can tell a rejected write from an accepted one. push is data
only — it never receives or runs code.
For the record shapes, see src/core/records.ts; for when to push vs. write an
adapter, see references/setup/index.md (PUSH vs PULL decision).
Remove memory — lore forget, lore exclude
These are destructive, irreversible commands. They follow a mandatory two-step
confirmation: run the bare command to see the exact scope and counts; run again
with --confirm to execute. The store is never touched on a bare run.
lore forget --session <session-id>
lore forget --session <session-id> --confirm
lore sessions --project "$PWD" --source claude-code --limit 10
lore forget --project /path/to/project
lore forget --project /path/to/project --confirm
lore exclude --project /path/to/project
lore exclude --project /path/to/project --confirm
lore exclude --list
lore exclude --remove /path/to/project
Verb semantics:
forget = point-in-time delete. What exists now is gone; future sessions for
the same project still get indexed.
exclude = standing rule. Deletes existing data AND bars all future captures
from the project until --remove is called. Use when you never want a project
in lore.
How tombstones protect you: After a forget or exclude --confirm, a
tombstone is written to the store. Re-indexing or lore push with the same
session or project id is silently dropped -- the data cannot come back through
the normal ingestion path.
A mistyped id/path is safe. The preview for a non-existent session or project
shows zero counts and exits 0. Nothing is deleted.
Human-in-the-loop rule (enforced for agents)
An agent using lore forget or lore exclude MUST follow this sequence and
MUST NOT supply --confirm on its own initiative:
- Run the bare command (no
--confirm) and surface the exact scope and counts
to the human.
- Wait for explicit human approval of the displayed scope.
- Only after the human confirms: re-run the same command with
--confirm.
This is not optional ceremony. forget/exclude are irreversible. Showing
the blast radius before acting is the safety contract. An agent that decides
the counts look fine and adds --confirm on its own has violated this rule.
These commands are intentionally CLI-only and are NOT exposed as MCP tools.
A compromised MCP client must never be able to wipe memory.
Index & teach new formats — see references/setup/index.md
This part of the skill is about using what's indexed. Getting transcripts
into lore — lore setup (auto-detect Claude Code / Codex), lore index <dir>,
lore sync <source> (incremental active transcript-tree catch-up for sources
such as codex and claude-code), lore sample <dir>,
lore hook (compaction capture for harnesses that emit a transcript path), and
writing a reviewed code adapter for a brand-new harness (the
checkAdapterConformance round-trip) — is the deterministic onboarding flow in
references/setup/index.md. Read that reference when the answer is "the thing I
want isn't indexed yet"; don't re-derive the procedure here.
Quick reference only:
lore setup
lore index <dir> [--source <name>] [--subagents] [--no-redact]
lore sync <source>
lore sample <dir>
Understand the store (so you can extend it)
One SQLite file, queryable read-only while another process writes (WAL). Three
ids, deliberately distinct:
source_file_id — one physical transcript file (the ingest/watermark unit).
session_id — one logical conversation, shared by a primary file and its
subagent files. This is what folds primary + subagent messages into a single
timeline.
message_id — a synthetic hash of (source_file_id + uuid + seq); uuid
alone collides across and within files, so it is never the key.
Tables: source_files, sessions (rollups: project, branch, first/last
timestamp, message_count), messages (role, timestamp, project, branch, model,
agent, skill, text, text_truncated), tool_calls (input/result/is_error, linked
to their message_id), and a messages_fts FTS5 external-content table kept in
sync by triggers. The tokenizer keeps _-. as token chars, so identifiers and
paths (getUserById, foo.bar.ts, trust-metadata) are searchable as whole
tokens — search for the symbol, not a fragment. Full schema:
src/core/store/schema.ts.
LORE_DB overrides the store path (default ~/.lore/lore.db) — handy for
pointing at a fixture store in tests.
CLI ⇄ MCP parity (why the server is unnecessary)
Every --json output is byte-shaped like the matching MCP tool's response, so
"the CLI does what the server does" is verifiable, not asserted:
| task | CLI | MCP tool | --json envelope |
|---|
| keyword find | lore search | search_memory | { count, hits } |
| recency find | lore search --relevant | find_relevant | { count, hits } |
| one message | lore get | get_message | detail obj / { error: "not_found", message_id } |
| neighbors | lore context | get_context | { messages } / not_found |
| session page | lore session | get_session | { messages, nextCursor } |
| session list | lore sessions | list_sessions | { count, sessions } |
| activity | lore timeline | timeline | { buckets } |
| status/freshness | lore status | status | status envelope |
| write | lore push | push | result / { error: "invalid_batch", detail } |
Worked recipes
"What did we decide about the FTS tokenizer?"
lore search "fts tokenizer" --relevant
lore get <message-id> --full
lore context <message-id> --before 3 --after 3
"Pull up my last session in this repo and find where we touched auth."
lore sessions --project "$PWD" --source claude-code --limit 5
lore search "auth" --session <session-id>
lore session <session-id> --around <message-id>
"When was this project active, and what happened in May?"
lore timeline --project "$PWD"
lore search "<topic>" --project "$PWD" --since 2026-05-01 --until 2026-06-01
Checklist