Skip to main content
Glama
README.md
# lore

**A standalone, cross-project learning base for AI agents and humans.**

`lore` keeps durable **product** and **technical** learnings in one place, each tagged to
the project it came from — so insight earned on one repo improves the next. It's a single
static binary that is three things at once:

- a **CLI** — `lore add`, `lore search`, `lore list`, …
- an **MCP server** — `lore mcp`, so **Claude Code, Claude Desktop, Cursor**, and any other
  MCP client can capture and recall learnings as native tool calls
- a **web UI** — `lore ui`, a browsable, themeable view of everything (with illustrations)

No runtime to install, no CGO (pure-Go SQLite), one file of data you own.

---

## Why

Agents forget everything between sessions and between repos. Notes rot in scattered
markdown. `lore` gives an agent a durable, queryable memory of *lessons* — not tasks, not
transcripts — split cleanly into:

- **product** — how the product should behave; principles; information architecture; domain decisions.
- **technical** — code structure, stack, build/tooling, gotchas, security invariants, conventions.

Each learning records its **source project**, so `lore search` on a new repo surfaces what
you already worked out on an old one.

## Install

```sh
# from source (Go 1.24+)
go install github.com/hadelekan/lore@latest

# or grab a prebuilt binary from the Releases page and put it on your PATH
```

Data lives outside the binary, in your OS config dir (`%APPDATA%\lore\lore.db` on Windows,
`~/.config/lore/lore.db` on Linux, `~/Library/Application Support/lore` on macOS). Override
with `$LORE_DB` (a file path) or `$LORE_HOME` (a directory). See `lore path`.

## CLI

```sh
lore add "A saved item must snapshot, not reference, an ephemeral source" \
  -c product -p my-app -t persistence,feeds -b "RSS keeps only N items; a pointer dangles…"

lore search ssrf            # match title/body/tags/project
lore list -c technical      # filter by category / -p project / -t tag
lore show 12                # one learning + its illustrations
lore projects               # per-project counts
lore export -p my-app       # markdown (or --format json) for reuse elsewhere
lore asset 12 --path diagram.png --caption "the flow"   # attach an illustration
lore import old.db          # pull learnings from another lore/knowledge DB

lore rm 12                  # move #12 to the trash (soft delete; recoverable)
lore restore 12             # bring it back out of the trash
lore trash                  # list what's in the trash
lore purge --all            # empty the trash now (or --days N for the policy)
lore rm 12 --permanent      # skip the trash and delete for good
```

### Deleting & the trash

Deletion is **temporal**: `lore rm` (and the web UI's delete) move a learning to a
**trash**, where it stays fully recoverable with `lore restore`. A **retention policy**
then permanently purges anything older than **30 days** (override with
`$LORE_TRASH_RETENTION_DAYS`); the purge runs on `lore ui` startup and on demand via
`lore purge`. Trashed learnings are hidden from the library, search, and all counts.

Bodies are markdown; pass them with `-b`, `--body-file`, or piped stdin.

## MCP — wire it into your agent

`lore mcp` speaks MCP over stdio. It advertises capture/recall **instructions**, so the
model applies the workflow (honor `@learn`, keep product vs technical separate, tag the
source project, recall before deciding) without extra prompting.

**Claude Code:**

```sh
claude mcp add lore -- lore mcp
```

**Claude Desktop / Cursor** (`mcpServers` in the client config):

```json
{
  "mcpServers": {
    "lore": { "command": "lore", "args": ["mcp"] }
  }
}
```

Tools exposed: `lore_create`, `lore_search`, `lore_list`, `lore_get`, `lore_update`,
`lore_delete`, `lore_projects`, `lore_tags`, `lore_stats`, `lore_attach_asset`, `lore_add_quiz`.

Each article is **attributed** (the authoring model + an author handle, defaulting to
`$LORE_AUTHOR`), can embed a **Mermaid diagram** (rendered in the reader), and — by the server's
standing instruction — ships with an **exhaustive quiz** you can take in the web UI.

**Directing captures in a session** — you don't have to wait for it to notice something:
`@learn <note>`, "note this as a learning: …", "write a lore article on <topic>", or
"capture what we figured out about X". The model researches, writes the article + diagram, and
attaches the quiz.

## Web UI

```sh
lore ui --open       # http://localhost:4180
```

Filter by category / project / tag, full-text search, and open any learning to read its
rendered markdown and illustrations. Light + dark themes. Reads the same database the CLI
and MCP server write, so captures appear live on refresh. The reader has an **"On this page"**
section outline (click to jump, highlights as you scroll), prev/next navigation, share, and
per-article **delete** (into the trash).

### AI rewrite (bring-your-own-key)

With an LLM key configured, the reader shows an **AI rewrite** action that asks the model to
improve an article — tightening the concept → worked-example → diagram structure and adding a
**Recommended reading** (real sources with authors + links) and **Related** section. You review
the proposal in a preview and save (or discard) it; nothing is changed until you accept. Enable
it with any OpenAI-compatible endpoint:

```sh
export LORE_LLM_API_KEY="sk-…"                        # required (enables the feature)
export LORE_LLM_BASE_URL="https://api.openai.com/v1"  # optional (OpenAI, OpenRouter, Groq, local, Anthropic-compat…)
export LORE_LLM_MODEL="gpt-4o-mini"                   # optional
lore ui
```

## Capturing from other AI chats

Not on Claude Code? The web server exposes a token-guarded `POST /api/learnings` so ChatGPT
(Custom GPT Action), Gemini, or a phone can post a learning to a hosted lore — plus a universal
"paste format" that works anywhere. See **[docs/INTEGRATIONS.md](docs/INTEGRATIONS.md)**.

```sh
LORE_INGEST_TOKEN="a-secret" LORE_AUTHOR="you" lore ui   # enables POST /api/learnings
```

## Build

The web UI is **TypeScript** (`internal/web/app.ts`), compiled by bun into
`internal/web/assets/app.js`, which the Go binary embeds. The compiled output is committed so
`go install` works without bun.

```sh
bun run build:web           # internal/web/app.ts -> internal/web/assets/app.js
bun run check:web           # type-check with tsc --noEmit
go build -o lore .          # single binary, embeds the web UI, no CGO
go test ./...
```

## License

MIT © Adelekan Adedokun