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.
Files changed (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +666 -0
  3. package/bin/lore.js +108 -0
  4. package/package.json +53 -0
  5. package/src/commands/drafts.js +144 -0
  6. package/src/commands/edit.js +30 -0
  7. package/src/commands/embed.js +63 -0
  8. package/src/commands/export.js +76 -0
  9. package/src/commands/graph.js +80 -0
  10. package/src/commands/init.js +110 -0
  11. package/src/commands/log.js +149 -0
  12. package/src/commands/mine.js +38 -0
  13. package/src/commands/onboard.js +112 -0
  14. package/src/commands/score.js +88 -0
  15. package/src/commands/search.js +49 -0
  16. package/src/commands/serve.js +21 -0
  17. package/src/commands/stale.js +41 -0
  18. package/src/commands/status.js +59 -0
  19. package/src/commands/watch.js +67 -0
  20. package/src/commands/why.js +58 -0
  21. package/src/lib/budget.js +57 -0
  22. package/src/lib/config.js +52 -0
  23. package/src/lib/drafts.js +104 -0
  24. package/src/lib/embeddings.js +97 -0
  25. package/src/lib/entries.js +59 -0
  26. package/src/lib/format.js +23 -0
  27. package/src/lib/git.js +18 -0
  28. package/src/lib/graph.js +51 -0
  29. package/src/lib/guard.js +13 -0
  30. package/src/lib/index.js +84 -0
  31. package/src/lib/nlp.js +106 -0
  32. package/src/lib/relevance.js +81 -0
  33. package/src/lib/scorer.js +188 -0
  34. package/src/lib/sessions.js +51 -0
  35. package/src/lib/stale.js +27 -0
  36. package/src/mcp/server.js +52 -0
  37. package/src/mcp/tools/drafts.js +54 -0
  38. package/src/mcp/tools/log.js +93 -0
  39. package/src/mcp/tools/overview.js +141 -0
  40. package/src/mcp/tools/search.js +96 -0
  41. package/src/mcp/tools/stale.js +88 -0
  42. package/src/mcp/tools/why.js +91 -0
  43. package/src/watcher/comments.js +113 -0
  44. package/src/watcher/graph.js +149 -0
  45. package/src/watcher/index.js +134 -0
  46. package/src/watcher/signals.js +217 -0
  47. 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