Skip to content

Lore 0.4.0

Choose a tag to compare

@aoc81 aoc81 released this 18 Aug 14:20
· 26 commits to main since this release

Recall now honors your config everywhere, stops repeating itself during a refactor, and works for prompts that aren't in English.

Recall correctness

  • staleStatuses is respected everywhere. It only reached prompt-time ranking before; freshness flags and edit-time recall hardcoded superseded/obsolete/deprecated. A project-defined status like archived was penalized on prompt recall but treated as live guidance when you edited the file. Both paths now read the config.
  • Edit-time matches are ranked before they're cut. maxRecall truncated in alphabetical path order, so a superseded entry could displace a current one. Live entries now sort first, ties keep store order.
  • New staleAfterMonths (default 6) — one configurable freshness threshold, replacing the same constant duplicated in two units (STALE_AFTER_MONTHS = 6 in recall, STALE_AFTER_DAYS = 183 in the linter).

Edit-time recall dedupes per session

The PreToolUse hook fires on every Edit/Write, so a refactor touching one file ten times injected the same learning ten times. Surfaced entries are now remembered for the session in .git/lore-recall-seen.json (local, inside .git, never committed) and not re-injected. Keyed by the hook's session_id; a new session starts clean. Fails open — no session id, no .git, or corrupt state means the learning still surfaces.

Non-English prompts

  • Unicode, accent-folding tokenizer. [a-z0-9_]+ split autenticación into autenticaci + n, quietly degrading recall for anyone prompting in Spanish (or any accented language). Tokens are now \w+ with diacritics folded, so an accented prompt also matches a tag written without accents (autenticación ↔ autenticacion).
  • Spanish stop words. para, este, cuando, quiero, necesito and ~85 more reached the scorer and could prefix-match real vocabulary (para → parameters). Deliberately not stopped: todo/todos/algo, which are real English/domain tokens.
  • New stopWords config key — words added to the built-in list, for domain noise (a product name in every prompt) or the three above.
  • Docs: write tags in the language you prompt in — accents fold, languages don't.

Hardening

  • Injected titles are capped at 140 characters and stripped of control characters. Recall's "never inject bodies" promise limits the prompt-injection surface of a shared store — but title: was injected verbatim and unbounded, so a malicious PR could smuggle an instruction payload through it.
  • The secret scanner no longer double-reports an Anthropic key (the OpenAI sk- rule also matched it).

Performance & diagnostics

  • iter_entries reads a bounded 8 KB head instead of whole entry files — it only ever needed the frontmatter, and it runs on every prompt and every edit. Constant cost per entry, with a full-read fallback so correctness never depends on the window.
  • The linter names ignored .lore.json keys. load_config deliberately never fails, so a typo like maxRecal silently did nothing. /lore:lint and /lore:stats now report unknown keys with a did-you-mean suggestion, plus wrongly-typed values.

Tests

52 → 86. Closes the coverage gaps on run_pretool, the run_hook JSON envelope, --index, and recall-log rotation, and covers every change above (including a regression test that fails against the old English-only stop list).

No behavior change requiring action: every new config key defaults to the previous behavior.

Install / update: /plugin install lore@lore (auto-updates).