lore:
0.1.0-alpha.5 GitHub

Concepts

Notes, and the ways they reach code

lore has one kind of thing, a note, and four ways for a note to reach a file: the code cites it, the note anchors the code, it is a CONTEXT.md above the file, or it is linked from a note that does one of those.

Notes

A note is a Markdown or Org file under the notes directory, docs/ by default, plus every CONTEXT.md in the repo. Frontmatter is optional. When present, it gives the note a type and fields the schema checks:

frontmatter
---
type: Decision
status: accepted
summary: One line shown in context output.   # default: a section or the first paragraph
aliases: [login]                              # other names that link here
anchors: [pkg/auth/**, "symbol:SessionManager"]
---

The default schema has three types, each with a home directory, so a note in docs/specs/ is a Spec without saying so:

TypeWhat it holdsStatuses
SpecWhat something should do, for whom, and what it leaves out. Edited in place.draft accepted retired
DecisionA choice and its reasons. Numbered, and never edited once accepted.proposed accepted superseded
EffortA plan against one or more specs, with a task checklist.planned active done

The types are yours to change in .lore/schema.yml.

Names

A note’s name is its type, lowercased, then its filename: spec/due-dates, effort/due-dates, decision/0002-rotating-refresh-tokens. A numbered note also answers to its number within its type, decision/0002. lore writes every link and message with these names.

So a spec and the effort that builds it can share a filename; the type tells them apart. A bare filename still works while only one note has it, so lore show auth is fine, but lore show due-dates asks which:

~/app
lore show due-dates
lore show: 'due-dates' matches 2 notes:
  effort/due-dates  docs/efforts/due-dates.md
  spec/due-dates  docs/specs/due-dates.md

When lore new gives a second note a filename that bare links already use, or a number they name a note by, as in [[0003]], it lists those links and the name each one meant, so you can qualify them before lore check complains.

Notes link to each other with double brackets, by name: [[decision/0001]] finds 0001-hard-expiry.md. A filename, path or alias works too while it names one note. A link inside a frontmatter field, such as spec: "[[spec/auth]]", is an edge lore context follows: a file governed by this decision is shown its spec too.

docs/decisions/0002-rotating-refresh-tokens.md
---
type: Decision
status: accepted
supersedes: ["[[decision/0001-hard-expiry]]"]
spec: "[[spec/auth]]"
---
# Rotating refresh tokens

## Context
Hard expiry (see [[decision/0001]]) signed people out mid-task,
and [[spec/auth]] says a session survives a browser restart.

## Decision
Refresh tokens rotate on every use; access tokens last 15 minutes.
1Decision 0001superseded

Hard expiry

Every session hard-expires after 15 minutes.

supersedes: the history
2Specaccepted

Auth

Who can sign in, how, and for how long.

spec: shown with this decision

Field links are edges lore follows; the same links in the body are references a reader follows. lore check reports any link that matches no note, or more than one.

Citations

Code points at a note with a comment containing lore: and the note’s name, such as // see lore:decision/0012. lore finds them with ripgrep, in any language.

pkg/auth/session.ts
const ACCESS_TTL = 15 * 60;
// see lore:decision/0002 -- a refresh token is good for one use.
export function refresh(token: string) {

A citation is the strongest match lore knows: it ranks first in lore context. If the decision it names is superseded, lore check says so, and the code gets looked at again.

Anchors

Where a citation is code pointing at a note, an anchor is a note claiming code. The anchors field takes three forms:

pkg/auth
A path: the file, or everything under the directory.
pkg/auth/**
A glob. More specific anchors rank higher.
symbol:SessionManager
Any file that uses the word, found with ripgrep.

An anchor that matches nothing is a lore check problem, so a note cannot quietly lose the code it governs in a rename.

CONTEXT.md

A CONTEXT.md describes the directory it sits in: what lives there, and the rules for it. Every CONTEXT.md above a file applies to it, nearest first, so pkg/auth/session.ts gets pkg/auth/CONTEXT.md, then pkg/CONTEXT.md, then the root one.

How context ranks

lore context lists notes most relevant first, and says why each one matched:

  1. Code citations in the file.
  2. Symbol anchors that the file uses.
  3. Path anchors, most specific first.
  4. CONTEXT.md files, nearest first.
  5. Notes one link away through a frontmatter field, such as the spec of a decision found above.

Output stops at a budget, 4000 tokens unless you pass --budget, so an agent is never handed the whole notes directory.

Superseding

Decisions are never edited or deleted once accepted. A new decision lists the old one in supersedes, and the old one becomes superseded. lore new --supersedes does both, and moves the old note’s anchors to the new one.

~/app
lore new Decision "Rotating refresh tokens" --supersedes 0001
created docs/decisions/0002-rotating-refresh-tokens.md
marked docs/decisions/0001-hard-expiry.md superseded

lore context always shows the decision in force, with one line of what it replaced. lore show walks the whole chain:

~/app
lore show decision/0002
Rotating refresh tokens  (Decision, accepted)
docs/decisions/0002-rotating-refresh-tokens.md
Refresh tokens rotate on every use; access tokens last 15 minutes.

History (newest first):
  ▸ decision/0002-rotating-refresh-tokens  (accepted)
    decision/0001-hard-expiry  (superseded)

Links to:
  supersedes: decision/0001-hard-expiry → docs/decisions/0001-hard-expiry.md
  spec: spec/auth → docs/specs/auth.md
  decision/0001 → docs/decisions/0001-hard-expiry.md
  spec/auth → docs/specs/auth.md

Cited by code:
  pkg/auth/session.ts:4

Efforts and freezing

An effort links the specs it was planned against and tracks its tasks as a checklist. lore freeze writes a hash of each spec’s body into the effort’s frozen field. If a spec changes while the effort is not done, lore check reports it and lore next sends you back to planning, because the tasks may be stale.

docs/efforts/due-dates.md, after lore freeze
---
type: Effort
status: active
specs: ["[[spec/due-dates]]"]
frozen:
  docs/specs/due-dates.md: 34dd79dc3cec
---

Once an effort is done, its frozen versions are history. A spec that changes after all its efforts shipped shows up in lore next as new work to plan.

Org notes

Notes can be Org files, and both kinds sit in one repo: a Markdown effort can plan against an Org spec. Fields are the #+key: value lines at the top, links are [[spec/auth]], [[spec/auth][label]] or [[file:prd.org][the PRD]], and checklists use [X].

docs/specs/search.org
#+title: Search
#+status: accepted
#+anchors: [src/search/**]

Find tasks by words in their title. Builds on [[spec/due-dates][due dates]] for filtering.

* Behaviour
- [X] Match whole words, case-insensitively
- [ ] Filter by due date
~/app
lore show search
Search  (Spec, accepted)
docs/specs/search.org
Find tasks by words in their title. Builds on [[spec/due-dates][due dates]] for filtering.
Checklist: 1 of 2 done

Links to:
  spec/due-dates → docs/specs/due-dates.md

Anchors:
  src/search/** → 1 file

A value in brackets or quotes is read as YAML, so #+anchors: [a, b] is a list; anything else is text. Set format: org on a type and lore new writes .org notes from .lore/templates/<Type>.org.

No index

lore keeps no database and no cache. Every command reads the working tree, so it can never disagree with the files in front of you, on any branch. On a 21,000-file repository, lore context answers in about a tenth of a second.