Start
Core concepts
The handful of ideas everything else builds on: what a project and a rule are, how a rule is scoped and tagged, and where Lore keeps its data.
Project
A project is a folder Lore knows about: a name and a root path. The name is the folder's name by default (letters, digits, ., _ and -; a name already used by a different folder is refused). A project is registered automatically the first time an agent works in a git repository, or by hand with memorize.py.
Registering builds a map: the project's sections, languages and manifest files. The map holds no file contents.
Section
A section is a folder-level area of a project. A file's section is its top-level folder, except that for folders that merely group real areas (src, packages, apps, services, lib, libs, modules, internal, cmd, pkg) it is the folder plus the next level. Files in the root belong to the section root.
| File | Section |
|---|---|
src/api/users.py | src/api |
tests/test_users.py | tests |
docs/intro.md | docs |
README.md | root |
src/main.py | src |
Unusual layouts can use a glob: scope instead. Vendored and build directories such as node_modules, vendor, dist and .venv are ignored when mapping.
Rule
A rule is one short sentence an agent should follow, with the metadata Lore needs to manage it. Rules are stored as plain JSON in ~/.lore/<project>/rules.json.
{
"id": "4d138ebe",
"text": "Paginate list endpoints with a cursor",
"scope": {"type": "section", "value": "src/api"},
"status": "active",
"source": "agent",
"evidence": "seen in 3 reviews",
"created": "2026-10-18T09:12:44",
"hits": 0,
"refs": ["https://github.com/acme/shop/pull/41#discussion_r1"],
"always": false,
"title": "Cursor pagination",
"triggers": ["list", "endpoint", "page", "paginate"],
"tagged": "agent 2026-10-18T09:13:02",
"auto": "2026-10-18T09:12:44"
}
| Field | Meaning |
|---|---|
id | Eight hex characters derived from the normalised text and the scope. The same wording in another scope is a different rule. |
text | The rule itself: at most 500 characters, one line, no hidden characters or HTML comments. |
scope | Where it applies: global, a section, or one or more globs. See below. |
status | pending (no effect) or active (served to agents). |
source | Where it came from: manual (review.py add), ui, feedback, agent, review (learn.py), discover, or the file it was read from (AGENTS.md, docs/standards.md). |
evidence | Why Lore believes it: numbers from discovery, the reviewers' wording, a user correction. |
refs | Web links to what justifies it, such as review comments. Only http(s) links are kept. |
hits / edited | How often the same rule was proposed again, and when a person last edited it. |
always | The rule must be followed on essentially every edit in its scope, so it is sent on every request. |
title / triggers | A 3–6 word name (up to 60 characters) and up to 12 words (40 characters each) a task contains when the rule matters. Written by the agent; see how rules are chosen. |
tagged | Who wrote the tags and when, such as agent 2026-10-18T09:13:02. Empty means untagged. |
auto | When Lore activated the rule itself, with no person approving it. Empty for rules a person approved. |
Scope
A rule's scope says which files it covers. There are three kinds:
| Scope | Written as | Covers |
|---|---|---|
| Global | global | Every file in the project. |
| Section | section:src/api | Files in that section. api matches both src/api and api; src matches src and everything below it. |
| Glob | glob:**/*.{ts,tsx} | Files matching one or more comma-separated patterns. **, *, ? and {a,b} are understood, and a bare *.py matches anywhere. |
When several rules cover a file, the most specific are listed first: glob (file level), then section, then global. Section names and globs may not contain quotes, backslashes, backticks, line breaks or hidden characters, and are limited to 200 characters.
Status
review.py reject- Rules you write (
review.py add, the UI) and rules trained from your own documents (train.py) start active. - Rules from
discover.py,learn.pyand instruction files imported bymemorize.pystart pending. - Rules the agent proposes are activated by Lore when they pass screening, and wait as pending otherwise. See automatic mode.
- Approving a rule yourself clears its
automark. Rejecting deletes the rule.
Tags and pinning
Three optional fields decide when an active rule is sent. They are written by the agent once per rule, not on every request:
always- Sent on every request that touches a file in the rule's scope. Meant for style, safety and architecture rules. Pinned from the CLI or UI by a person, or set to true by the agent. The agent can never switch it off.
title- Names the rule in the list of rules that were not sent.
triggers- Words (with synonyms) that a task contains when the rule matters, used when ranking.
Session
One MCP server process serves one agent session. During it, Lore remembers which rules it already sent (so it never repeats them), which projects the agent is working on, and how many rules it activated by itself. A new session starts from nothing.
Usage counters
Every time get_rules or search_rules hands over a rule, Lore counts one delivery in usage.json. review.py usage lists approved rules least-used first, and the web UI shows "served 12× · last 2026-10-10" on each. Previews (review.py resolve, the UI's preview) never count. "Never served" only means no file the agent worked on matched that rule yet; give a rule weeks before calling it dead weight.
Where the data lives
Everything is under ~/.lore. Set LORE_HOME to use another folder.
~/.lore/
config.json settings (optional): approval, auto_register, auto_limit
<project>/
project.json name and root folder
map.json sections, languages, manifests (no file contents)
rules.json every rule
usage.json how often each rule was handed to an agent
review-ledger.json review comments already proposed or dismissed, and when they were last read
trust.json whether the repository counts as yours (cached for a week)
.rules.lock .usage.lock lock files, so two processes never overwrite each other
Files are written atomically (a temporary file, then a rename) and writers take a lock, so two agent sessions can use Lore at once. Rules and usage are kept in separate files so that counting can never overwrite an edit. Nothing is sent anywhere by Lore itself; the only network use is through your own gh login when reading review comments or checking push access.
Hygiene: what can become a rule
All text that can reach an agent is checked before it is stored, and refused with a message rather than quietly cleaned:
- Hidden characters: zero-width, bidirectional controls, Unicode "tag" characters, variation selectors and blank look-alikes.
- HTML comment markers (
<!--,-->), which hide text in rendered views. - More than 500 characters, or empty text.
Rules saved before these checks that contain such characters are shown with <U+XXXX> markers and a warning, are never served or exported, and cannot be approved until edited or rejected. More in security and trust.