Class: ClaudeMemory::Shortcuts
- Inherits:
-
Object
- Object
- ClaudeMemory::Shortcuts
- Defined in:
- lib/claude_memory/shortcuts.rb
Overview
Predicate-based shortcuts for the three common “give me X” queries that MCP clients (and humans via CLI) expect to be trivially fast and noise-free.
Prior implementation did FTS text search (“convention style format pattern prefer”) with a hardcoded global-only scope on ‘conventions`. That produced cross-predicate matches (uses_database rows leaking into the decisions shortcut) and silently dropped every project convention on the floor. Switching to predicate-based filtering at the store level eliminates both classes of bug; the cost is we no longer rank by FTS relevance, but for “list the project’s conventions” that’s the correct trade.
Constant Summary collapse
- SHORTCUTS =
{ decisions: { predicates: %w[decision], limit: 10 }, architecture: { # Includes the stack-shaping predicates so an agent asking # "what's the architecture?" gets both narrative architecture # facts AND the constraints (uses_database, uses_framework, ...). # Without these the shortcut returns only freeform architecture # facts and the constraints section stays invisible. predicates: %w[architecture uses_database uses_framework uses_language deployment_platform auth_method], limit: 10 }, conventions: { predicates: %w[convention], limit: 20 }, project_config: { predicates: %w[uses_database uses_framework uses_language deployment_platform auth_method], limit: 10 } }.freeze
Class Method Summary collapse
- .architecture(manager, **overrides) ⇒ Object
-
.collect_facts(manager, predicates, limit) ⇒ Object
Query both stores for active facts matching the given predicates.
- .conventions(manager, **overrides) ⇒ Object
- .decisions(manager, **overrides) ⇒ Object
- .fetch_active_facts(store, predicates, limit) ⇒ Object
-
.for(shortcut_name, manager, **overrides) ⇒ Array<Hash>
Result hashes with :fact, :receipts (empty), :source (“project”/“global”).
- .project_config(manager, **overrides) ⇒ Object
Class Method Details
.architecture(manager, **overrides) ⇒ Object
57 58 59 |
# File 'lib/claude_memory/shortcuts.rb', line 57 def self.architecture(manager, **overrides) self.for(:architecture, manager, **overrides) end |
.collect_facts(manager, predicates, limit) ⇒ Object
Query both stores for active facts matching the given predicates. Project facts take precedence (returned first); global facts fill any remaining slots up to the limit. Does NOT create missing DBs —callers like activity_logging’s “orphan manager” depend on this surface staying read-only when the project DB hasn’t been initialized yet.
75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/claude_memory/shortcuts.rb', line 75 def self.collect_facts(manager, predicates, limit) project_store = manager.store_if_exists("project") global_store = manager.store_if_exists("global") project_rows = fetch_active_facts(project_store, predicates, limit) global_rows = fetch_active_facts(global_store, predicates, limit) results = project_rows.map { |row| {fact: row, receipts: [], source: "project"} } + global_rows.map { |row| {fact: row, receipts: [], source: "global"} } results.first(limit) end |
.conventions(manager, **overrides) ⇒ Object
61 62 63 |
# File 'lib/claude_memory/shortcuts.rb', line 61 def self.conventions(manager, **overrides) self.for(:conventions, manager, **overrides) end |
.decisions(manager, **overrides) ⇒ Object
53 54 55 |
# File 'lib/claude_memory/shortcuts.rb', line 53 def self.decisions(manager, **overrides) self.for(:decisions, manager, **overrides) end |
.fetch_active_facts(store, predicates, limit) ⇒ Object
88 89 90 91 92 93 94 95 96 97 |
# File 'lib/claude_memory/shortcuts.rb', line 88 def self.fetch_active_facts(store, predicates, limit) return [] unless store Core::FactQueryBuilder.build_facts_dataset(store) .where(Sequel[:facts][:predicate] => predicates, Sequel[:facts][:status] => "active") .reverse_order(Sequel[:facts][:id]) .limit(limit) .all end |
.for(shortcut_name, manager, **overrides) ⇒ Array<Hash>
Returns result hashes with :fact, :receipts (empty), :source (“project”/“global”).
45 46 47 48 49 50 51 |
# File 'lib/claude_memory/shortcuts.rb', line 45 def self.for(shortcut_name, manager, **overrides) config = SHORTCUTS.fetch(shortcut_name) limit = overrides[:limit] || config[:limit] predicates = config[:predicates] collect_facts(manager, predicates, limit) end |
.project_config(manager, **overrides) ⇒ Object
65 66 67 |
# File 'lib/claude_memory/shortcuts.rb', line 65 def self.project_config(manager, **overrides) self.for(:project_config, manager, **overrides) end |