lore-memory 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +666 -0
- package/bin/lore.js +108 -0
- package/package.json +53 -0
- package/src/commands/drafts.js +144 -0
- package/src/commands/edit.js +30 -0
- package/src/commands/embed.js +63 -0
- package/src/commands/export.js +76 -0
- package/src/commands/graph.js +80 -0
- package/src/commands/init.js +110 -0
- package/src/commands/log.js +149 -0
- package/src/commands/mine.js +38 -0
- package/src/commands/onboard.js +112 -0
- package/src/commands/score.js +88 -0
- package/src/commands/search.js +49 -0
- package/src/commands/serve.js +21 -0
- package/src/commands/stale.js +41 -0
- package/src/commands/status.js +59 -0
- package/src/commands/watch.js +67 -0
- package/src/commands/why.js +58 -0
- package/src/lib/budget.js +57 -0
- package/src/lib/config.js +52 -0
- package/src/lib/drafts.js +104 -0
- package/src/lib/embeddings.js +97 -0
- package/src/lib/entries.js +59 -0
- package/src/lib/format.js +23 -0
- package/src/lib/git.js +18 -0
- package/src/lib/graph.js +51 -0
- package/src/lib/guard.js +13 -0
- package/src/lib/index.js +84 -0
- package/src/lib/nlp.js +106 -0
- package/src/lib/relevance.js +81 -0
- package/src/lib/scorer.js +188 -0
- package/src/lib/sessions.js +51 -0
- package/src/lib/stale.js +27 -0
- package/src/mcp/server.js +52 -0
- package/src/mcp/tools/drafts.js +54 -0
- package/src/mcp/tools/log.js +93 -0
- package/src/mcp/tools/overview.js +141 -0
- package/src/mcp/tools/search.js +96 -0
- package/src/mcp/tools/stale.js +88 -0
- package/src/mcp/tools/why.js +91 -0
- package/src/watcher/comments.js +113 -0
- package/src/watcher/graph.js +149 -0
- package/src/watcher/index.js +134 -0
- package/src/watcher/signals.js +217 -0
- package/src/watcher/staleness.js +104 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,666 @@
|
|
|
1
|
+
# Lore
|
|
2
|
+
|
|
3
|
+
> *"Your codebase has a story. Lore remembers it."*
|
|
4
|
+
|
|
5
|
+
Persistent project memory for developers. Every architectural decision, invariant, gotcha, and abandoned approach — captured automatically, structured, versioned in git, and injected into your AI coding sessions.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## The Problem
|
|
10
|
+
|
|
11
|
+
Every AI coding session starts from zero. You re-explain why you chose JWT over sessions, why that Redis approach was abandoned, why the 200ms budget is a hard limit. That context lives in your head, not your codebase.
|
|
12
|
+
|
|
13
|
+
Without it, your AI assistant suggests things you've already rejected, removes workarounds that exist for real reasons, and retreads ground you've already covered.
|
|
14
|
+
|
|
15
|
+
Lore fixes that.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install -g lore-memory
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Or from source:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
git clone <this repo>
|
|
29
|
+
cd lore
|
|
30
|
+
npm install
|
|
31
|
+
npm link # makes `lore` available globally
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Table of Contents
|
|
37
|
+
|
|
38
|
+
- [Quick Start](#quick-start)
|
|
39
|
+
- [Usage Guide](#usage-guide)
|
|
40
|
+
- [Day 1: Initialize and populate](#day-1-initialize-and-populate)
|
|
41
|
+
- [Day 2+: Passive capture with the watcher](#day-2-passive-capture-with-the-watcher)
|
|
42
|
+
- [Reviewing drafts](#reviewing-drafts)
|
|
43
|
+
- [Querying your knowledge base](#querying-your-knowledge-base)
|
|
44
|
+
- [Connecting to Claude Code](#connecting-to-claude-code)
|
|
45
|
+
- [Checking health](#checking-health)
|
|
46
|
+
- [Team workflows](#team-workflows)
|
|
47
|
+
- [Entry Types](#entry-types)
|
|
48
|
+
- [All Commands](#all-commands)
|
|
49
|
+
- [How It Works](#how-it-works)
|
|
50
|
+
- [MCP Tools Reference](#mcp-tools-reference)
|
|
51
|
+
- [Configuration](#configuration)
|
|
52
|
+
- [Semantic Search & Embeddings](#semantic-search--embeddings)
|
|
53
|
+
- [.lore/ Structure](#lore-structure)
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Quick Start
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
cd your-project
|
|
61
|
+
lore init # sets up .lore/ and scans for comments
|
|
62
|
+
lore watch --daemon # starts passive capture in background
|
|
63
|
+
lore mine . # immediately scan all source files for comments
|
|
64
|
+
lore drafts # review what was found
|
|
65
|
+
lore score # see your knowledge base health
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Usage Guide
|
|
71
|
+
|
|
72
|
+
### Day 1: Initialize and populate
|
|
73
|
+
|
|
74
|
+
**1. Initialize**
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
cd your-project
|
|
78
|
+
lore init
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
This creates `.lore/` in your project root, installs a git post-commit hook, and immediately scans your codebase for comments worth capturing.
|
|
82
|
+
|
|
83
|
+
**2. Scan for existing knowledge**
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
lore mine .
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Lore walks every `.js`, `.ts`, `.py`, `.go`, `.rs` file looking for comments that contain signal phrases (`WARNING:`, `because`, `never`, `hack`, `we chose`, etc.). Each match becomes a draft for you to review.
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
📖 Mining comments in . ...
|
|
93
|
+
✓ Found 7 drafts — run: lore drafts
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**3. Review the drafts**
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
lore drafts
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
For each draft Lore shows what it found and asks what you want to do:
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
Draft 1 of 7
|
|
106
|
+
────────────────────────────────
|
|
107
|
+
Type: invariant
|
|
108
|
+
Title: Never add synchronous calls to payment path
|
|
109
|
+
Evidence: // WARNING: never add synchronous calls here — 200ms SLA
|
|
110
|
+
Files: src/payments/processor.js
|
|
111
|
+
Confidence: 90%
|
|
112
|
+
|
|
113
|
+
[a] accept [e] edit [s] skip [d] delete [q] quit
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
- **Accept** — saves it as a real entry, updates the index, generates embedding
|
|
117
|
+
- **Edit** — opens a prompt to tweak the title/type/context before saving
|
|
118
|
+
- **Skip** — leaves it in the queue for later
|
|
119
|
+
- **Delete** — removes permanently
|
|
120
|
+
|
|
121
|
+
**4. Log entries manually**
|
|
122
|
+
|
|
123
|
+
For things you know right now, use `lore log`:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
lore log
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Interactive prompts walk you through type → title → context → files → tags. Or go inline:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
lore log \
|
|
133
|
+
--type decision \
|
|
134
|
+
--title "Use JWT over sessions" \
|
|
135
|
+
--context "API consumed by both mobile and web. Stateless auth was the only option that worked cleanly for both. Sessions require sticky routing which our k8s setup doesn't support." \
|
|
136
|
+
--files "src/auth/"
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
### Day 2+: Passive capture with the watcher
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
lore watch --daemon # runs in background, survives terminal close
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
From this point, Lore watches your project and automatically creates drafts when it detects signals:
|
|
148
|
+
|
|
149
|
+
| What you do | What Lore captures |
|
|
150
|
+
|---|---|
|
|
151
|
+
| Delete a file > 100 lines | Why did this exist? → graveyard draft |
|
|
152
|
+
| Edit the same file 5+ times in a week | This might be a footgun → gotcha draft |
|
|
153
|
+
| Commit with "replace", "migrate", "switch" | Decision draft |
|
|
154
|
+
| Commit with "never", "always", "must" | Invariant draft |
|
|
155
|
+
| Add or remove a dep in `package.json` | Decision or graveyard draft |
|
|
156
|
+
| Write `// WARNING:` or `// must never` | Invariant draft |
|
|
157
|
+
| Write `// because` or `// we chose` | Decision draft |
|
|
158
|
+
| Write `// HACK:` or `// workaround` | Gotcha draft |
|
|
159
|
+
|
|
160
|
+
To stop the daemon:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
lore watch --stop
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
To run in foreground (useful to see activity live):
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
lore watch
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**Check what the watcher captured:**
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
lore status # shows draft count alongside entry counts
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
📖 Lore Status
|
|
180
|
+
decisions: 4
|
|
181
|
+
invariants: 2
|
|
182
|
+
graveyard: 1
|
|
183
|
+
gotchas: 3
|
|
184
|
+
drafts: 5 pending — run: lore drafts
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
### Reviewing drafts
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
lore drafts
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Drafts are sorted by confidence — highest first. Each shows the signal that triggered it and which file it came from. You approve or discard each one.
|
|
196
|
+
|
|
197
|
+
**Batch accept everything high-confidence:**
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
lore drafts --auto
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Accepts all drafts with ≥ 80% confidence silently. Useful after a busy coding session.
|
|
204
|
+
|
|
205
|
+
**Edit an existing entry:**
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
lore edit decision-use-jwt-1703001234
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Opens the entry JSON in your editor (VSCode by default, falls back to printing the path).
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
### Querying your knowledge base
|
|
216
|
+
|
|
217
|
+
**Why is this file the way it is?**
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
lore why src/payments/stripe.js
|
|
221
|
+
lore why src/auth/ # works on directories too
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Returns entries weighted by how closely they relate to the file:
|
|
225
|
+
|
|
226
|
+
```
|
|
227
|
+
📖 src/payments/stripe.js
|
|
228
|
+
|
|
229
|
+
[INVARIANT] All payment calls must complete within 200ms
|
|
230
|
+
Never add synchronous external calls to this path.
|
|
231
|
+
Files: src/payments/
|
|
232
|
+
Score: 1.00
|
|
233
|
+
|
|
234
|
+
[GRAVEYARD] Tried Stripe webhooks with idempotency keys (2023)
|
|
235
|
+
Removed — DB transactions weren't atomic with the webhook handler.
|
|
236
|
+
Files: src/payments/stripe.js
|
|
237
|
+
Score: 1.00
|
|
238
|
+
|
|
239
|
+
[DECISION] Use polling over webhook push for payment status
|
|
240
|
+
Files: src/payments/ (imported by this file)
|
|
241
|
+
Score: 0.30
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
**Search by keyword:**
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
lore search "postgres"
|
|
248
|
+
lore search "rate limit"
|
|
249
|
+
lore search "why not redis"
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
**See the dependency graph:**
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
lore graph --build # index all imports (run once, updates automatically)
|
|
256
|
+
lore graph src/api/server.js # what does this file import, and what imports it?
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
```
|
|
260
|
+
📖 src/api/server.js
|
|
261
|
+
|
|
262
|
+
Imports:
|
|
263
|
+
src/auth/middleware.js → 2 Lore entries
|
|
264
|
+
src/payments/processor.js → 1 Lore entry
|
|
265
|
+
src/lib/db.js → 0 Lore entries
|
|
266
|
+
|
|
267
|
+
Imported by:
|
|
268
|
+
src/index.js → 0 Lore entries
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
### Connecting to Claude Code
|
|
274
|
+
|
|
275
|
+
This is where Lore pays off the most. Add the MCP server to your Claude Code config:
|
|
276
|
+
|
|
277
|
+
**Global** (`~/.claude/settings.json`) — works in every project:
|
|
278
|
+
|
|
279
|
+
```json
|
|
280
|
+
{
|
|
281
|
+
"mcpServers": {
|
|
282
|
+
"lore": {
|
|
283
|
+
"command": "lore",
|
|
284
|
+
"args": ["serve"]
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
**Per-project** (`.claude/settings.json` in your repo) — only for this project:
|
|
291
|
+
|
|
292
|
+
```json
|
|
293
|
+
{
|
|
294
|
+
"mcpServers": {
|
|
295
|
+
"lore": {
|
|
296
|
+
"command": "lore",
|
|
297
|
+
"args": ["serve"]
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
After restarting Claude Code, Lore is live. You don't need to do anything — Claude automatically calls `lore_why` when you ask it to work on a file, and the context is injected before it writes a single line.
|
|
304
|
+
|
|
305
|
+
**What Claude sees when you say "refactor src/payments/stripe.js":**
|
|
306
|
+
|
|
307
|
+
```
|
|
308
|
+
[INVARIANT] All payment calls must complete within 200ms
|
|
309
|
+
Never add synchronous external calls to this path.
|
|
310
|
+
|
|
311
|
+
[GRAVEYARD] Tried Stripe webhooks with idempotency keys
|
|
312
|
+
Removed — DB transactions weren't atomic. Current polling approach is intentional.
|
|
313
|
+
|
|
314
|
+
[GOTCHA] Stripe test clock doesn't advance automatically in CI
|
|
315
|
+
Call stripe.testHelpers.testClocks.advance() explicitly in test setup.
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
Claude now knows the constraints. It won't suggest adding an inline fraud-check API call. It won't suggest switching to webhooks. It won't write tests that silently break.
|
|
319
|
+
|
|
320
|
+
**Claude also surfaces your draft queue:**
|
|
321
|
+
|
|
322
|
+
If you have unreviewed drafts, Claude will mention it:
|
|
323
|
+
> *"You have 3 unreviewed Lore drafts — run `lore drafts` to review."*
|
|
324
|
+
|
|
325
|
+
**Export to CLAUDE.md (without MCP):**
|
|
326
|
+
|
|
327
|
+
If you prefer a static file over the MCP server:
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
lore export
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
Generates a `CLAUDE.md` at project root that Claude Code reads automatically at session start. Less dynamic than MCP (no per-file context injection) but requires no server.
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
|
|
337
|
+
### Checking health
|
|
338
|
+
|
|
339
|
+
**Lore Score:**
|
|
340
|
+
|
|
341
|
+
```bash
|
|
342
|
+
lore score
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
```
|
|
346
|
+
📖 Lore Score: 73/100 (Good)
|
|
347
|
+
────────────────────────────────
|
|
348
|
+
|
|
349
|
+
Coverage ████████░░ 80%
|
|
350
|
+
8 / 10 active modules documented
|
|
351
|
+
Highest risk unlogged: src/billing (12 commits this quarter)
|
|
352
|
+
|
|
353
|
+
Freshness ███████░░░ 70%
|
|
354
|
+
3 entries may be stale — run: lore stale
|
|
355
|
+
|
|
356
|
+
Depth ██████░░░░ 65%
|
|
357
|
+
14 entries across 8 modules
|
|
358
|
+
|
|
359
|
+
────────────────────────────────
|
|
360
|
+
Trend: 45 → 58 → 73 (improving)
|
|
361
|
+
Tip: Add invariants or gotchas to improve your depth score.
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
- **Coverage** — what fraction of your actively-changed modules have at least one entry. "Active" means > 5 commits in the last 90 days.
|
|
365
|
+
- **Freshness** — how recently entries were updated relative to their linked files. Stale entries drag this down.
|
|
366
|
+
- **Depth** — how many entries you have per active module. Invariants and gotchas count 1.5× because they're the most valuable.
|
|
367
|
+
|
|
368
|
+
**Stale entries:**
|
|
369
|
+
|
|
370
|
+
```bash
|
|
371
|
+
lore stale
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
```
|
|
375
|
+
⚠️ Stale entries (linked files changed since entry was written):
|
|
376
|
+
|
|
377
|
+
invariant-payment-timeout → src/payments/processor.js changed 4 days ago
|
|
378
|
+
⚠ External HTTP call added to a performance-critical path
|
|
379
|
+
Review with: lore edit invariant-payment-timeout
|
|
380
|
+
|
|
381
|
+
decision-use-polling → src/payments/stripe.js changed 12 days ago
|
|
382
|
+
Review with: lore edit decision-use-polling
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
Stale detection combines mtime (file changed after entry was written) with pattern analysis — e.g. if you added a `fetch()` call to a file covered by a 200ms invariant, Lore flags it specifically.
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
### Team workflows
|
|
390
|
+
|
|
391
|
+
Lore entries live in `.lore/decisions/`, `.lore/invariants/`, etc. as plain JSON files. Commit them like any other source file.
|
|
392
|
+
|
|
393
|
+
**Recommended `.gitignore` additions** (already set up by `lore init`):
|
|
394
|
+
|
|
395
|
+
```
|
|
396
|
+
.lore/drafts/ # personal draft queue, not shared
|
|
397
|
+
.lore/graph.json # rebuilt automatically
|
|
398
|
+
.lore/score.json # personal history
|
|
399
|
+
.lore/watch-state.json
|
|
400
|
+
.lore/watcher.pid
|
|
401
|
+
.lore/watcher.log
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
**Onboarding a new team member:**
|
|
405
|
+
|
|
406
|
+
```bash
|
|
407
|
+
lore onboard
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
Prints a brief covering recent decisions, active invariants, and anything flagged stale. Useful after a long weekend too:
|
|
411
|
+
|
|
412
|
+
```bash
|
|
413
|
+
lore onboard --days 7 # pretend you've been away 7 days
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
**When you join a repo that already has Lore:**
|
|
417
|
+
|
|
418
|
+
```bash
|
|
419
|
+
git pull
|
|
420
|
+
lore status # see what's there
|
|
421
|
+
lore onboard # get the brief
|
|
422
|
+
lore why src/ # see what the whole src/ directory remembers
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
---
|
|
426
|
+
|
|
427
|
+
## Entry Types
|
|
428
|
+
|
|
429
|
+
**decision** — An architectural or technical choice with its rationale.
|
|
430
|
+
|
|
431
|
+
```bash
|
|
432
|
+
lore log --type decision \
|
|
433
|
+
--title "Use Postgres over MongoDB" \
|
|
434
|
+
--context "We started with Mongo but our data is highly relational. Join queries were getting complex. Migrated to Postgres in Q3 2023." \
|
|
435
|
+
--files "src/db/"
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
**invariant** — A rule or constraint that must not be broken without deliberate review.
|
|
439
|
+
|
|
440
|
+
```bash
|
|
441
|
+
lore log --type invariant \
|
|
442
|
+
--title "All auth tokens must be validated on every request" \
|
|
443
|
+
--context "Never cache auth results in memory. Token revocation must take effect immediately. This burned us in a security audit." \
|
|
444
|
+
--files "src/auth/middleware.js"
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
**gotcha** — A non-obvious behavior, footgun, or thing that's bitten you.
|
|
448
|
+
|
|
449
|
+
```bash
|
|
450
|
+
lore log --type gotcha \
|
|
451
|
+
--title "Date.now() in test fixtures produces flaky tests" \
|
|
452
|
+
--context "Jest doesn't freeze time by default. Use jest.useFakeTimers() or pass timestamps explicitly. Spent 2 days on this." \
|
|
453
|
+
--files "src/__tests__/"
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
**graveyard** — An approach that was tried and abandoned, with a record of why.
|
|
457
|
+
|
|
458
|
+
```bash
|
|
459
|
+
lore log --type graveyard \
|
|
460
|
+
--title "Tried GraphQL for the public API" \
|
|
461
|
+
--context "Removed in v2. N+1 queries in the default resolver were hammering the DB. REST with explicit eager-loading is intentional." \
|
|
462
|
+
--files "src/api/"
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
---
|
|
466
|
+
|
|
467
|
+
## All Commands
|
|
468
|
+
|
|
469
|
+
### Setup & capture
|
|
470
|
+
|
|
471
|
+
| Command | Description |
|
|
472
|
+
|---|---|
|
|
473
|
+
| `lore init` | Initialize `.lore/` in the current repo, install git hook |
|
|
474
|
+
| `lore log` | Log an entry interactively |
|
|
475
|
+
| `lore log --type <t> --title <t> --context <c> --files <f>` | Log inline, no prompts |
|
|
476
|
+
| `lore mine [path]` | Scan a file or directory for lore-worthy comments |
|
|
477
|
+
| `lore mine .` | Scan the entire project |
|
|
478
|
+
| `lore watch` | Start the file watcher in the foreground |
|
|
479
|
+
| `lore watch --daemon` | Start the file watcher in the background |
|
|
480
|
+
| `lore watch --stop` | Stop the background watcher |
|
|
481
|
+
|
|
482
|
+
### Review & edit
|
|
483
|
+
|
|
484
|
+
| Command | Description |
|
|
485
|
+
|---|---|
|
|
486
|
+
| `lore drafts` | Review pending auto-captured drafts interactively |
|
|
487
|
+
| `lore drafts --auto` | Accept all drafts with ≥ 80% confidence silently |
|
|
488
|
+
| `lore edit <id>` | Open an entry in your editor |
|
|
489
|
+
|
|
490
|
+
### Query
|
|
491
|
+
|
|
492
|
+
| Command | Description |
|
|
493
|
+
|---|---|
|
|
494
|
+
| `lore why <file>` | Show all entries relevant to a file or directory |
|
|
495
|
+
| `lore search <query>` | Search entries by keyword (semantic if Ollama running) |
|
|
496
|
+
| `lore graph` | Show dependency graph stats |
|
|
497
|
+
| `lore graph <file>` | Show imports and importers for a specific file |
|
|
498
|
+
| `lore graph --build` | Build or rebuild the full dependency graph |
|
|
499
|
+
|
|
500
|
+
### Health & export
|
|
501
|
+
|
|
502
|
+
| Command | Description |
|
|
503
|
+
|---|---|
|
|
504
|
+
| `lore status` | Entry counts, draft count, stale summary |
|
|
505
|
+
| `lore stale` | Full stale report with semantic pattern analysis |
|
|
506
|
+
| `lore score` | Lore Score (0–100): coverage, freshness, depth |
|
|
507
|
+
| `lore export` | Generate `CLAUDE.md` at project root |
|
|
508
|
+
| `lore onboard` | Print re-onboarding brief |
|
|
509
|
+
| `lore onboard --days <n>` | Simulate returning after N days |
|
|
510
|
+
|
|
511
|
+
### AI integration
|
|
512
|
+
|
|
513
|
+
| Command | Description |
|
|
514
|
+
|---|---|
|
|
515
|
+
| `lore serve` | Start the MCP server (used by Claude Code, called automatically) |
|
|
516
|
+
| `lore embed` | Generate semantic embeddings for all entries via Ollama |
|
|
517
|
+
|
|
518
|
+
---
|
|
519
|
+
|
|
520
|
+
## How It Works
|
|
521
|
+
|
|
522
|
+
### Comment mining
|
|
523
|
+
|
|
524
|
+
Lore uses the Babel AST parser for JS/TS files and regex for Python/Go/Rust. It scores each comment on:
|
|
525
|
+
|
|
526
|
+
- Does it contain a signal phrase? (`must`, `never`, `warning`, `hack`, `because`, `we chose`, `tried`, etc.)
|
|
527
|
+
- Is it longer than 20 characters?
|
|
528
|
+
- Is it more than a generic `TODO` or `FIXME`?
|
|
529
|
+
|
|
530
|
+
Comments scoring above the threshold become drafts with a suggested type and a title extracted from the first meaningful words.
|
|
531
|
+
|
|
532
|
+
### Graph-weighted context
|
|
533
|
+
|
|
534
|
+
When you run `lore why src/api/payments.js`, entries are ranked by how closely they relate:
|
|
535
|
+
|
|
536
|
+
| Relationship | Weight |
|
|
537
|
+
|---|---|
|
|
538
|
+
| Entry directly linked to this file | 1.0 |
|
|
539
|
+
| Entry linked to a parent directory | 0.7 |
|
|
540
|
+
| Entry for a file this file imports | 0.3 |
|
|
541
|
+
| Entry for a file that imports this file | 0.2 |
|
|
542
|
+
|
|
543
|
+
This means the context you get isn't just "entries tagged to this file" — it's the full blast radius of relevant knowledge, ranked by relevance.
|
|
544
|
+
|
|
545
|
+
### Staleness detection
|
|
546
|
+
|
|
547
|
+
Every entry records which files it references. When those files change:
|
|
548
|
+
|
|
549
|
+
1. **mtime check** — if the file was modified after the entry was written, it's flagged
|
|
550
|
+
2. **pattern check** — specific patterns are analyzed: a `fetch()` call added near a 200ms invariant, a WebSocket import near a "we chose polling" decision, a graveyard dep re-appearing in `package.json`
|
|
551
|
+
|
|
552
|
+
No Ollama required for either of these. If Ollama is running and embeddings exist, a semantic similarity check runs additionally.
|
|
553
|
+
|
|
554
|
+
---
|
|
555
|
+
|
|
556
|
+
## MCP Tools Reference
|
|
557
|
+
|
|
558
|
+
When connected via MCP, Claude Code has access to these tools:
|
|
559
|
+
|
|
560
|
+
| Tool | Input | Returns |
|
|
561
|
+
|---|---|---|
|
|
562
|
+
| `lore_why` | `filepath` | All relevant entries for that file, graph-weighted and token-budgeted |
|
|
563
|
+
| `lore_overview` | — | Entry counts, Lore Score, draft count, highest-risk unlogged module |
|
|
564
|
+
| `lore_stale` | — | Stale entries with mtime and semantic pattern reasons |
|
|
565
|
+
| `lore_drafts` | — | Pending draft count and summary |
|
|
566
|
+
| `lore_search` | `query` | Matching entries |
|
|
567
|
+
| `lore_log` | `type`, `title`, `context`, `files` | Confirmation after saving |
|
|
568
|
+
|
|
569
|
+
The token budget (default 4000, configurable) ensures Lore never floods Claude's context window. If entries exceed the budget, the lowest-scored ones are summarized to a single line.
|
|
570
|
+
|
|
571
|
+
---
|
|
572
|
+
|
|
573
|
+
## Configuration
|
|
574
|
+
|
|
575
|
+
`.lore/config.yaml` is created by `lore init` with sensible defaults. Edit it to tune behaviour:
|
|
576
|
+
|
|
577
|
+
```yaml
|
|
578
|
+
# Entry types to enable
|
|
579
|
+
types:
|
|
580
|
+
- decision
|
|
581
|
+
- invariant
|
|
582
|
+
- graveyard
|
|
583
|
+
- gotcha
|
|
584
|
+
|
|
585
|
+
# Directories the watcher ignores
|
|
586
|
+
watchIgnore:
|
|
587
|
+
- node_modules
|
|
588
|
+
- dist
|
|
589
|
+
- .git
|
|
590
|
+
- coverage
|
|
591
|
+
|
|
592
|
+
# Comment phrases that trigger draft creation
|
|
593
|
+
commentPatterns:
|
|
594
|
+
- must
|
|
595
|
+
- never
|
|
596
|
+
- warning
|
|
597
|
+
- hack
|
|
598
|
+
- because
|
|
599
|
+
- we chose
|
|
600
|
+
- tried
|
|
601
|
+
|
|
602
|
+
# Minimum confidence for --auto mode in lore drafts
|
|
603
|
+
signalThreshold: 0.8
|
|
604
|
+
|
|
605
|
+
# Pattern-based semantic staleness (no Ollama needed)
|
|
606
|
+
semanticStaleness: true
|
|
607
|
+
|
|
608
|
+
# Lore Score component weights (must sum to 1.0)
|
|
609
|
+
scoringWeights:
|
|
610
|
+
coverage: 0.4
|
|
611
|
+
freshness: 0.35
|
|
612
|
+
depth: 0.25
|
|
613
|
+
|
|
614
|
+
# Max tokens Lore injects into Claude's context per request
|
|
615
|
+
mcp:
|
|
616
|
+
tokenBudget: 4000
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
---
|
|
620
|
+
|
|
621
|
+
## Semantic Search & Embeddings
|
|
622
|
+
|
|
623
|
+
Optional. Requires [Ollama](https://ollama.com) running locally.
|
|
624
|
+
|
|
625
|
+
```bash
|
|
626
|
+
ollama pull nomic-embed-text
|
|
627
|
+
lore embed
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
What this enables:
|
|
631
|
+
- `lore search "why not redis"` finds entries that are semantically related, not just keyword matches
|
|
632
|
+
- `lore stale` adds similarity-based staleness (diff vs entry embedding)
|
|
633
|
+
- MCP `lore_why` ranks entries partly by semantic relevance
|
|
634
|
+
|
|
635
|
+
Lore works fully without this. All core features — capture, review, why, stale, score, MCP — work with no Ollama dependency.
|
|
636
|
+
|
|
637
|
+
---
|
|
638
|
+
|
|
639
|
+
## .lore/ Structure
|
|
640
|
+
|
|
641
|
+
```
|
|
642
|
+
.lore/
|
|
643
|
+
decisions/ ← committed to git
|
|
644
|
+
invariants/ ← committed to git
|
|
645
|
+
graveyard/ ← committed to git
|
|
646
|
+
gotchas/ ← committed to git
|
|
647
|
+
modules/ ← committed to git
|
|
648
|
+
index.json ← committed to git
|
|
649
|
+
config.yaml ← committed to git
|
|
650
|
+
|
|
651
|
+
drafts/ ← gitignored (personal review queue)
|
|
652
|
+
graph.json ← gitignored (rebuilt automatically)
|
|
653
|
+
score.json ← gitignored (personal history)
|
|
654
|
+
watch-state.json ← gitignored (watcher bookkeeping)
|
|
655
|
+
watcher.pid ← gitignored (daemon PID)
|
|
656
|
+
watcher.log ← gitignored (daemon logs)
|
|
657
|
+
embeddings.db ← gitignored (SQLite, local only)
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
Entries are plain JSON. You can read, edit, or delete them directly. The index is rebuilt on next `lore status` or `lore why` if it drifts.
|
|
661
|
+
|
|
662
|
+
---
|
|
663
|
+
|
|
664
|
+
## Stack
|
|
665
|
+
|
|
666
|
+
Node.js · CommonJS · Commander · Inquirer · Chalk · Chokidar · Babel Parser · fs-extra · js-yaml · natural · better-sqlite3 · Ollama (optional) · MCP SDK
|