appydave-tools 0.80.0 → 0.81.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cb0b711e430f2082be55712eb0c3e630726bcc77628dc8ab144d72f27fc05bd7
4
- data.tar.gz: 8fc9be5413601f6da5cccd649d324578df676efb842b138623998a1f6dd7b676
3
+ metadata.gz: '09f48a7490c924291dff958e3df8ba53c28c2dae599cae0ab8581ac3e4ad3ee2'
4
+ data.tar.gz: f1e55198dd31bb3b2b61b61d4f929fc3bda799ecd4cedb96e5f810c994edae4a
5
5
  SHA512:
6
- metadata.gz: d7527c25930ba5fb35206e6321fea074f12593a9188ed4b7d51f1f832f01f60a9929336b8670bf48bea0f68eeba0df150ecb542ea244be899334781ef432a7a1
7
- data.tar.gz: 051f6c24d48fa6caa2ac342436a1105403d7524e871ee248996b772e0e16aafde612cd33386d4b6bba92b5f1f0c2e2f6cf61406e9f76db5a42e55d367031c642
6
+ metadata.gz: 9d4f2bc474af95d2ff538d5360d9ec659b559f155b611c9b7c13f9c475118311a1fc99a40b1f3fc6655b20bee568a3c5fcb4466f709eef948cd400d4efee6709
7
+ data.tar.gz: 84af7abbcc284e85742f1db64737622e8c929b57815988908a2aba716d970adcfd0f52e29f7a432fb2d544fd8be950fd27254d7ec61fdf705802c126b34e6d84
data/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ # [0.80.0](https://github.com/appydave/appydave-tools/compare/v0.79.0...v0.80.0) (2026-04-03)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * resolve RSpec linting violations in test suite ([0bb643c](https://github.com/appydave/appydave-tools/commit/0bb643c374934227ab6831f87b4b8e7fd6d2444d))
7
+
8
+
9
+ ### Features
10
+
11
+ * add brain_context CLI tool for querying brains + OMI ([7498e25](https://github.com/appydave/appydave-tools/commit/7498e25d8fa3094ee97ddfb67980d414f70efbab))
12
+
1
13
  # [0.79.0](https://github.com/appydave/appydave-tools/compare/v0.78.0...v0.79.0) (2026-04-03)
2
14
 
3
15
 
data/CLAUDE.md CHANGED
@@ -170,6 +170,8 @@ bin/console # Interactive Ruby console for experimentation
170
170
  | **DAM (Digital Asset Management)** | `vat` | Multi-tenant video project storage orchestration | ✅ ACTIVE |
171
171
  | **Configuration** | `ad_config` | Manage JSON configs (channels, paths, sequences) | ✅ ACTIVE |
172
172
  | **Move Images** | N/A (dev only) | Organize video asset images | ✅ ACTIVE |
173
+ | **Brain Query** | `query_brain` | Query brain knowledge index by name/tag/category | ✅ ACTIVE |
174
+ | **OMI Query** | `query_omi` | Query OMI transcripts by routing/brain/activity | ✅ ACTIVE |
173
175
  | **Prompt Tools** | `prompt_tools` | OpenAI Completion API wrapper | ⚠️ DEPRECATED API |
174
176
  | **YouTube Automation** | `youtube_automation` | Prompt sequence runner | ⚠️ INTERNAL USE |
175
177
 
@@ -434,7 +436,92 @@ bin/move_images.rb -f b40 thumb b40
434
436
 
435
437
  **Note:** This is a development/workflow tool specific to video project organization. Not installed as a gem command.
436
438
 
437
- #### 8. Bank Reconciliation (`bin/bank_reconciliation.rb`) 🗄️ DEPRECATED
439
+ #### 8. Brain Query (`bin/query_brain`)
440
+ Query the brain knowledge index to locate relevant brain files for LLM context pipelines:
441
+
442
+ ```bash
443
+ # Find brains by name, alias, or tag
444
+ query_brain --find paperclip
445
+ query_brain --find bmad --find method
446
+
447
+ # Find all brains in a category
448
+ query_brain --category tools
449
+ query_brain --category workflows
450
+
451
+ # Find high-activity brains
452
+ query_brain --active
453
+
454
+ # Exclude INDEX.md from results
455
+ query_brain --find paperclip --files-only
456
+
457
+ # Return JSON metadata instead of file paths
458
+ query_brain --active --meta
459
+ query_brain --find bmad --meta
460
+ ```
461
+
462
+ **Options:**
463
+ - `--find TERM` — find by name, alias, or tag (repeatable)
464
+ - `--category CAT` — all brains in a category (repeatable)
465
+ - `--active` — all high-activity brains
466
+ - `--files-only` — exclude INDEX.md from results
467
+ - `--meta` — return JSON metadata instead of file paths
468
+
469
+ **Pipeline examples:**
470
+ ```bash
471
+ # Feed brain files directly into LLM context
472
+ query_brain --find paperclip | xargs llm_context.rb -i
473
+
474
+ # Metadata pipeline (direct to LLM — no llm_context needed)
475
+ query_brain --active --meta
476
+ ```
477
+
478
+ #### 9. OMI Query (`bin/query_omi`)
479
+ Query OMI wearable transcript sessions by routing type, brain reference, or activity:
480
+
481
+ ```bash
482
+ # Find sessions mentioning a brain
483
+ query_omi --brain paperclip
484
+ query_omi --brain bmad
485
+
486
+ # Filter by routing type
487
+ query_omi --routing brain-update
488
+ query_omi --routing til
489
+ query_omi --routing todo-item
490
+ query_omi --routing personal
491
+ query_omi --routing archive
492
+
493
+ # Filter by activity
494
+ query_omi --activity planning
495
+ query_omi --activity meeting
496
+ query_omi --activity debugging
497
+
498
+ # Limit by recency
499
+ query_omi --days 7
500
+ query_omi --brain paperclip --days 30 --limit 10
501
+
502
+ # Return JSON metadata instead of file paths
503
+ query_omi --brain paperclip --meta
504
+ query_omi --routing brain-update --limit 5 --meta
505
+ ```
506
+
507
+ **Options:**
508
+ - `--brain NAME` — sessions mentioning a brain
509
+ - `--routing TYPE` — brain-update, til, todo-item, personal, archive
510
+ - `--activity ACT` — planning, meeting, debugging, etc.
511
+ - `--days N` — last N days
512
+ - `--limit N` — most recent N results
513
+ - `--meta` — return JSON metadata instead of file paths
514
+
515
+ **Pipeline examples:**
516
+ ```bash
517
+ # Feed recent brain-update sessions into LLM context
518
+ query_omi --routing brain-update --limit 5 | xargs llm_context.rb -i
519
+
520
+ # Metadata pipeline (direct to LLM — no llm_context needed)
521
+ query_omi --brain paperclip --meta
522
+ ```
523
+
524
+ #### 10. Bank Reconciliation (`bin/bank_reconciliation.rb`) 🗄️ DEPRECATED
438
525
  Bank transaction reconciliation tool - **DEPRECATED, DO NOT USE**
439
526
 
440
527
  **WARNING:** This tool contains deprecated code and should not be used for new work. Code has been moved to `lib/appydave/tools/deprecated/bank_reconciliation/`
data/bin/query_brain.rb CHANGED
@@ -10,26 +10,20 @@ def setup_options(options)
10
10
  OptionParser.new do |opts| # rubocop:disable Metrics/BlockLength
11
11
  opts.banner = 'Usage: query_brain [options]'
12
12
 
13
- opts.on('--brain NAME', 'Query brain by name, alias, or fuzzy match') do |name|
14
- options.brain_names << name
13
+ opts.on('--find TERM', 'Find brain by name, tag, or alias (repeatable)') do |term|
14
+ options.brain_names << term
15
15
  end
16
16
 
17
- opts.on('--tag TAG', 'Query brains by tag') do |tag|
18
- options.tags << tag
19
- end
20
-
21
- opts.on('--category CAT', 'Query all brains in category') do |cat|
17
+ opts.on('--category CAT', 'Find all brains in category (repeatable)') do |cat|
22
18
  options.categories << cat
23
19
  end
24
20
 
25
- opts.on('--activity-min LEVEL', %w[high medium low none],
26
- 'Filter brains by minimum activity level') do |level|
27
- options.activity_levels << level
21
+ opts.on('--active', 'Return all high-activity brains') do
22
+ options.active = true
28
23
  end
29
24
 
30
- opts.on('--status STATUS', %w[active stable deprecated],
31
- 'Filter brains by status (default: exclude deprecated)') do |status|
32
- options.status = status
25
+ opts.on('--meta', 'Return metadata as JSON instead of file paths') do
26
+ options.meta = true
33
27
  end
34
28
 
35
29
  opts.on('--files-only', 'Exclude INDEX.md, only include content files') do
@@ -57,9 +51,12 @@ setup_options(options)
57
51
 
58
52
  # Query
59
53
  finder = Appydave::Tools::BrainQuery.new(options)
60
- paths = finder.find
61
54
 
62
- # Output file paths, one per line
63
- paths.each { |p| puts p }
55
+ if options.meta
56
+ require 'json'
57
+ puts JSON.pretty_generate(finder.find_meta)
58
+ else
59
+ finder.find.each { |p| puts p }
60
+ end
64
61
 
65
62
  exit 0
data/bin/query_omi.rb CHANGED
@@ -11,9 +11,8 @@ def setup_options(options)
11
11
  OptionParser.new do |opts| # rubocop:disable Metrics/BlockLength
12
12
  opts.banner = 'Usage: query_omi [options]'
13
13
 
14
- opts.on('--signal SIGNAL', %w[work life ambient],
15
- 'Filter by signal') do |signal|
16
- options.omi_signals << signal
14
+ opts.on('--brain NAME', 'Find OMI sessions mentioning this brain') do |name|
15
+ options.brain_names << name
17
16
  end
18
17
 
19
18
  opts.on('--routing ROUTING',
@@ -26,20 +25,16 @@ def setup_options(options)
26
25
  options.omi_activities.concat(activity.split('|').map(&:strip))
27
26
  end
28
27
 
29
- opts.on('--date-from DATE', 'Include files from date (YYYY-MM-DD)') do |date|
30
- options.date_from = date
28
+ opts.on('--days N', Integer, 'Include sessions from the last N days') do |n|
29
+ options.days = n
31
30
  end
32
31
 
33
- opts.on('--date-to DATE', 'Include files up to date (YYYY-MM-DD)') do |date|
34
- options.date_to = date
32
+ opts.on('--meta', 'Return metadata as JSON instead of file paths') do
33
+ options.meta = true
35
34
  end
36
35
 
37
- opts.on('--enriched-only', 'Skip raw (non-enriched) transcripts') do
38
- options.enriched_only = true
39
- end
40
-
41
- opts.on('--brain NAME', 'Find OMI files mentioning this brain') do |name|
42
- options.brain_names << name
36
+ opts.on('--limit N', Integer, 'Return at most N results (most recent)') do |n|
37
+ options.limit = n
43
38
  end
44
39
 
45
40
  opts.on('-d', '--debug [MODE]', %w[none info params debug],
@@ -63,9 +58,12 @@ setup_options(options)
63
58
 
64
59
  # Query
65
60
  finder = Appydave::Tools::OmiQuery.new(options)
66
- paths = finder.find
67
61
 
68
- # Output file paths, one per line
69
- paths.each { |p| puts p }
62
+ if options.meta
63
+ require 'json'
64
+ puts JSON.pretty_generate(finder.find_meta)
65
+ else
66
+ finder.find.each { |p| puts p }
67
+ end
70
68
 
71
69
  exit 0
@@ -0,0 +1,58 @@
1
+ ---
2
+ title: Handover — Query Tools Session (2026-04-04)
3
+ type: handover
4
+ ---
5
+
6
+ # Handover — Query Tools Session (2026-04-04)
7
+
8
+ ## What Was Built
9
+
10
+ Three tools in `appydave-tools` now work as a unified query pipeline:
11
+
12
+ - **`query_brain`** — queries the brains knowledge index
13
+ - **`query_omi`** — queries OMI conversation transcripts by frontmatter
14
+ - **`llm_context`** — assembles file content for LLM consumption (pre-existing, unchanged)
15
+
16
+ Full documentation: `/Users/davidcruwys/dev/ad/appydave-tools/docs/guides/query-tools.md`
17
+
18
+ ---
19
+
20
+ ## What Changed Today
21
+
22
+ ### API Simplification
23
+ Both query tools had their APIs simplified — fewer flags, unified search:
24
+
25
+ **query_brain**: `--find` replaces separate `--brain` + `--tag`. `--active` replaces broken `--activity-min`. Removed: `--status` (dead code), `--tag`, `--activity-min`.
26
+
27
+ **query_omi**: Added `--days N` and `--limit N`. Removed: `--signal`, `--date-from`, `--date-to`, `--enriched-only` (enriched is now default).
28
+
29
+ ### New --meta Mode
30
+ Both tools now support `--meta` — returns JSON metadata instead of file paths. This is a **separate pipeline** from llm_context, used when you want summaries without loading full file content.
31
+
32
+ ### Bug Fixed
33
+ `query_brain --active` was silently returning nothing. Fixed — now correctly returns all 29 high-activity brains.
34
+
35
+ ---
36
+
37
+ ## Relevant Skills That May Want This Context
38
+
39
+ ### OMI Skill (`/Users/davidcruwys/dev/ad/appydave-plugins/appydave/skills/omi/`)
40
+ The `query_omi` tool is the programmatic interface to the same OMI data that the OMI skill works with. The frontmatter fields (`routing`, `matched_brains`, `extraction_summary`, etc.) that `query_omi` filters on are produced by the OMI enrichment pipeline. The skill should know:
41
+ - `--routing brain-update` surfaces the backlog of conversations that should feed into brains
42
+ - `--meta` gives extraction summaries without loading full transcripts
43
+
44
+ ### Brain Librarian (wherever it lives)
45
+ The `query_brain` tool consumes `brains-index.json` built by brain-librarian. The librarian should know:
46
+ - Index must be at `~/dev/ad/brains/audit/brains-index.json`
47
+ - Fields used: `activity_level`, `tags`, `category`, `status`, `file_count`, `index_path`, `files[]`
48
+ - `files[]` array is currently empty for most brains — only `INDEX.md` is returned. Populating this would make `query_brain --find X` return actual content files, not just index files.
49
+
50
+ ### LLM Context Skill (if one exists)
51
+ The pipeline pattern is: `query_brain --find X | xargs llm_context.rb -i -f content`. The query tools are the **selector layer** feeding into llm_context as the **assembler layer**.
52
+
53
+ ---
54
+
55
+ ## What Is Not Done Yet (Intentionally Deferred)
56
+
57
+ - **Randomizer** — a discovery tool that pre-validates queries against result counts and randomly surfaces one. Concept is clear, not yet implemented. Would live as `/Users/davidcruwys/dev/ad/appydave-tools/bin/random_context.rb`.
58
+ - **Markdown format for --meta** — decided against. JSON is sufficient for LLM consumption and adding a format flag adds complexity back that was just removed.
@@ -0,0 +1,255 @@
1
+ ---
2
+ title: Query Tools — brain, OMI, and LLM Context Pipeline
3
+ category: guides
4
+ tools: [query_brain, query_omi, llm_context]
5
+ status: active
6
+ created: 2026-04-04
7
+ ---
8
+
9
+ # Query Tools — Brain, OMI, and LLM Context Pipeline
10
+
11
+ ## Purpose
12
+
13
+ Three tools work together as a **file selection and context assembly pipeline** for AI-assisted workflows:
14
+
15
+ | Tool | Role | Output |
16
+ |------|------|--------|
17
+ | `query_brain` | Select brain knowledge files | File paths or JSON metadata |
18
+ | `query_omi` | Select OMI conversation files | File paths or JSON metadata |
19
+ | `llm_context` | Assemble file content for LLM | Tree listing or full content |
20
+
21
+ The tools are **composable**: query tools select files, `llm_context` loads them.
22
+
23
+ ---
24
+
25
+ ## What Is Being Queried
26
+
27
+ ### query_brain
28
+ Reads `~/dev/ad/brains/audit/brains-index.json` — a pre-built index of all brain folders. Does **not** scan brain files at query time. The index contains per-brain metadata: name, category, activity_level, tags, status, file_count.
29
+
30
+ Brain folders live at `~/dev/ad/brains/<brain-name>/`. Each has an `INDEX.md` and optional content files.
31
+
32
+ ### query_omi
33
+ Scans `~/dev/raw-intake/omi/*.md` and reads YAML frontmatter from each file. Enriched files (processed by Gemini extraction) have rich frontmatter. Raw files (unprocessed transcripts) have minimal frontmatter. Default behaviour: **enriched files only**.
34
+
35
+ ### llm_context
36
+ Takes file paths (from stdin or arguments) and assembles content for LLM consumption. Two formats: `tree` (file listing) and `content` (file listing + full file content).
37
+
38
+ ---
39
+
40
+ ## query_brain API
41
+
42
+ ```bash
43
+ query_brain [options]
44
+ ```
45
+
46
+ | Flag | Description |
47
+ |------|-------------|
48
+ | `--find TERM` | Find brain by name, alias, or tag — unified search (repeatable) |
49
+ | `--category CAT` | All brains in a category (repeatable) |
50
+ | `--active` | All high-activity brains |
51
+ | `--files-only` | Exclude INDEX.md, return content files only |
52
+ | `--meta` | Return JSON metadata instead of file paths |
53
+
54
+ ### Categories (as of 2026-04)
55
+ `claude-core`, `agent-frameworks`, `agent-systems`, `infrastructure`, `content-production`, `brand-strategy`, `knowledge-capture`, `client-infrastructure`, `lifestyle`, `private`
56
+
57
+ ### Activity Levels
58
+ `high` (29 brains), `medium`, `low`, `none`
59
+
60
+ ### Search Resolution Order (--find)
61
+ 1. Exact brain name match
62
+ 2. Alias match (from alias_index in brains-index.json)
63
+ 3. Substring match on brain name
64
+ 4. Tag match (falls through to tag_index)
65
+
66
+ ### Examples
67
+ ```bash
68
+ # Find a specific brain (name, partial name, or tag all work)
69
+ query_brain --find paperclip
70
+ query_brain --find agentic-engineering # searches by tag
71
+
72
+ # Browse a category
73
+ query_brain --category agent-systems
74
+ query_brain --category agent-systems --category agent-frameworks
75
+
76
+ # All high-activity brains
77
+ query_brain --active
78
+
79
+ # Metadata instead of file paths
80
+ query_brain --active --meta
81
+ query_brain --find paperclip --meta
82
+ ```
83
+
84
+ ### --meta Output Structure
85
+ ```json
86
+ [
87
+ {
88
+ "name": "paperclip",
89
+ "category": "agent-systems",
90
+ "activity_level": "high",
91
+ "status": "active",
92
+ "tags": ["paperclip", "multi-agent", "orchestration"],
93
+ "file_count": 6
94
+ }
95
+ ]
96
+ ```
97
+
98
+ ---
99
+
100
+ ## query_omi API
101
+
102
+ ```bash
103
+ query_omi [options]
104
+ ```
105
+
106
+ | Flag | Description |
107
+ |------|-------------|
108
+ | `--brain NAME` | Sessions where this brain appears in matched_brains |
109
+ | `--routing TYPE` | Filter by routing tag (pipe-delimited values supported) |
110
+ | `--activity ACT` | Filter by activity type (pipe-delimited values supported) |
111
+ | `--days N` | Sessions from the last N days (based on extracted_at) |
112
+ | `--limit N` | Return at most N results, most recent first |
113
+ | `--meta` | Return JSON metadata instead of file paths |
114
+
115
+ ### Routing Values
116
+ `brain-update`, `til`, `todo-item`, `personal`, `archive`
117
+
118
+ ### Activity Values
119
+ `planning`, `meeting`, `learning`, `debugging`, `reviewing`, `building`, `teaching`
120
+
121
+ ### Enriched Frontmatter Structure
122
+ ```yaml
123
+ signal: work
124
+ extraction_summary: "One-sentence summary of the conversation"
125
+ extracted_at: 2026-04-03
126
+ matched_brains: [agentic-os, anthropic-claude, paperclip]
127
+ activity: meeting|planning|learning
128
+ routing: brain-update
129
+ people_present: [david, nick]
130
+ people_mentioned: [boris]
131
+ entities_tools: [Claude, Gemini, Archon]
132
+ entities_projects: [Agent Workflow Builder]
133
+ entities_concepts: [token economics, RAG, prompt caching]
134
+ overflow_topics: [Thai chocolate, mask hardware]
135
+ ```
136
+
137
+ ### Examples
138
+ ```bash
139
+ # Sessions flagged for brain updates (your backlog)
140
+ query_omi --routing brain-update
141
+ query_omi --routing brain-update --limit 10
142
+
143
+ # Recent planning sessions
144
+ query_omi --activity planning --days 7
145
+
146
+ # Everything related to a specific brain
147
+ query_omi --brain paperclip
148
+
149
+ # Metadata view — summaries without loading full files
150
+ query_omi --routing brain-update --limit 5 --meta
151
+ query_omi --brain paperclip --days 14 --meta
152
+ ```
153
+
154
+ ### --meta Output Structure
155
+ ```json
156
+ [
157
+ {
158
+ "file": "2026-04-03-1705-group-debates.md",
159
+ "extracted_at": "2026-04-03",
160
+ "extraction_summary": "A group discusses LLM usage and agentic workflows...",
161
+ "matched_brains": ["agentic-os", "anthropic-claude", "paperclip"],
162
+ "activity": "meeting|planning",
163
+ "routing": "brain-update",
164
+ "entities_tools": ["Claude", "Gemini", "Archon"],
165
+ "entities_projects": ["Archon"],
166
+ "entities_concepts": ["token economics", "RAG"]
167
+ }
168
+ ]
169
+ ```
170
+
171
+ ---
172
+
173
+ ## Pipeline Patterns
174
+
175
+ ### Content pipeline — load files into LLM context
176
+ ```bash
177
+ # Brain knowledge files → LLM
178
+ query_brain --find paperclip | xargs llm_context.rb -i -f content
179
+
180
+ # OMI sessions → LLM
181
+ query_omi --brain paperclip --limit 5 | xargs llm_context.rb -i -f content
182
+
183
+ # Mixed: brain + OMI for a topic
184
+ { query_brain --find paperclip; query_omi --brain paperclip --limit 5; } | sort -u | xargs llm_context.rb -i -f content
185
+ ```
186
+
187
+ ### Metadata pipeline — summaries direct to LLM (no llm_context needed)
188
+ ```bash
189
+ # What's in my brain-update backlog?
190
+ query_omi --routing brain-update --meta
191
+
192
+ # What are all my active brains?
193
+ query_brain --active --meta
194
+
195
+ # What OMI sessions touched paperclip recently?
196
+ query_omi --brain paperclip --days 14 --meta
197
+ ```
198
+
199
+ ### Discovery pattern — bounded queries for randomizer
200
+ ```bash
201
+ # These return 1–20 results — good for random surfacing
202
+ query_brain --find paperclip # 1 brain
203
+ query_brain --category agent-systems # ~10 brains
204
+ query_omi --brain paperclip # ~10 sessions
205
+ query_omi --routing til --limit 5 # 5 things-I-learned
206
+ ```
207
+
208
+ ---
209
+
210
+ ## Two Different Data Shapes
211
+
212
+ **Brain files** are **curated knowledge** — processed, structured, human-maintained. High signal density. Use when you want what is known and confirmed.
213
+
214
+ **OMI files** are **conversation transcripts** — raw or AI-enriched recordings of spoken work sessions. Variable quality. Use when you want recent context, planning discussions, or to find what should be promoted into a brain.
215
+
216
+ These are intentionally separate query tools. Do not combine them by default.
217
+
218
+ ---
219
+
220
+ ## Key Files
221
+
222
+ | File | Purpose |
223
+ |------|---------|
224
+ | `/Users/davidcruwys/dev/ad/brains/audit/brains-index.json` | Brain index — built by brain-librarian |
225
+ | `/Users/davidcruwys/dev/raw-intake/omi/*.md` | OMI conversation transcripts |
226
+ | `/Users/davidcruwys/dev/ad/appydave-tools/bin/query_brain.rb` | Brain query CLI |
227
+ | `/Users/davidcruwys/dev/ad/appydave-tools/bin/query_omi.rb` | OMI query CLI |
228
+ | `/Users/davidcruwys/dev/ad/appydave-tools/bin/llm_context.rb` | File content assembler |
229
+ | `/Users/davidcruwys/dev/ad/appydave-tools/exe/query_brain` | Gem-installed wrapper |
230
+ | `/Users/davidcruwys/dev/ad/appydave-tools/exe/query_omi` | Gem-installed wrapper |
231
+ | `/Users/davidcruwys/dev/ad/appydave-tools/lib/appydave/tools/brain_context/brain_finder.rb` | BrainQuery implementation |
232
+ | `/Users/davidcruwys/dev/ad/appydave-tools/lib/appydave/tools/brain_context/omi_finder.rb` | OmiQuery implementation |
233
+ | `/Users/davidcruwys/dev/ad/appydave-tools/lib/appydave/tools/brain_context/options.rb` | Shared options struct |
234
+
235
+ ---
236
+
237
+ ## Rebuilding the Brain Index
238
+
239
+ The `brains-index.json` is not auto-updated. When brain folders change, rebuild it:
240
+
241
+ ```bash
242
+ python /Users/davidcruwys/dev/ad/brains/.claude/skills/brain-librarian/scripts/build_brain_index.py build --all /Users/davidcruwys/dev/ad/brains
243
+ ```
244
+
245
+ OMI files are queried directly — no index rebuild needed.
246
+
247
+ ---
248
+
249
+ ## Design Decisions
250
+
251
+ - **query_brain and query_omi are separate tools** — brains are confirmed knowledge, OMI is conversation. Different trust levels.
252
+ - **`--meta` bypasses llm_context** — metadata is already summarised; loading full file content adds tokens without value for discovery use cases.
253
+ - **enriched_only defaults to true** in query_omi — raw transcripts have no frontmatter to filter on; they're noise in most query contexts.
254
+ - **`--find` unifies name/alias/tag** — users shouldn't need to know whether something is a name or a tag.
255
+ - **`--active` standalone** — returns all 29 high-activity brains without needing to enumerate categories.
@@ -18,28 +18,35 @@ module Appydave
18
18
  load_index!
19
19
  paths = []
20
20
 
21
- # Handle brain name queries
21
+ # Active brains: return all high-activity brains
22
+ paths.concat(find_active) if @options.active
23
+
24
+ # Handle brain name/tag/alias queries (unified)
22
25
  @options.brain_names.each do |name|
23
26
  paths.concat(find_by_name(name))
24
27
  end
25
28
 
26
- # Handle tag queries
27
- @options.tags.each do |tag|
28
- paths.concat(find_by_tag(tag))
29
- end
30
-
31
29
  # Handle category queries
32
30
  @options.categories.each do |category|
33
31
  paths.concat(find_by_category(category))
34
32
  end
35
33
 
36
- # Handle activity level filters
37
- paths.select! { |p| matches_activity_level?(p) } if @options.activity_levels.any?
38
-
39
- # Remove duplicates and return
40
34
  paths.uniq.sort
41
35
  end
42
36
 
37
+ def find_meta
38
+ return [] unless @options.brain_query?
39
+
40
+ load_index!
41
+ entries = []
42
+
43
+ entries.concat(active_meta_entries) if @options.active
44
+ @options.brain_names.each { |name| entries.concat(meta_entries_by_name(name)) }
45
+ @options.categories.each { |cat| entries.concat(meta_entries_by_category(cat)) }
46
+
47
+ entries.uniq { |e| e['name'] }.sort_by { |e| e['name'] }
48
+ end
49
+
43
50
  private
44
51
 
45
52
  def load_index!
@@ -80,11 +87,10 @@ module Appydave
80
87
  matches << brain_data if brain_name.downcase.include?(name.downcase)
81
88
  end
82
89
  end
83
- return brain_entries_to_paths(matches) if matches.length == 1
84
90
  return brain_entries_to_paths(matches) if matches.any?
85
91
 
86
- # Not found
87
- []
92
+ # Step 4: Tag match (so --find works for tags too)
93
+ find_by_tag(name)
88
94
  end
89
95
 
90
96
  def find_by_tag(tag)
@@ -148,17 +154,82 @@ module Appydave
148
154
  entry['index_path'].split('/')[0]
149
155
  end
150
156
 
151
- def matches_activity_level?(file_path)
152
- # Extract brain name from path
153
- brain_name = file_path.match(%r{#{Regexp.escape(@options.brains_root)}/([^/]+)})&.[](1)
154
- return false unless brain_name
157
+ def find_active
158
+ brain_entries = []
159
+ @index['categories'].each_value do |category_data|
160
+ category_data['brains'].each_value do |brain_data|
161
+ brain_entries << brain_data if brain_data['activity_level'] == 'high'
162
+ end
163
+ end
164
+ brain_entries_to_paths(brain_entries)
165
+ end
166
+
167
+ # --- find_meta helpers ---
155
168
 
156
- # Find the brain entry
157
- entry = find_brain_in_index(brain_name)
158
- return false unless entry
169
+ def active_meta_entries
170
+ result = []
171
+ @index['categories'].each do |category_name, category_data|
172
+ category_data['brains'].each do |brain_name, brain_data|
173
+ result << build_meta_entry(brain_name, category_name, brain_data) if brain_data['activity_level'] == 'high'
174
+ end
175
+ end
176
+ result
177
+ end
178
+
179
+ def meta_entries_by_category(category)
180
+ category_key = @index['categories'].keys.find { |k| k.casecmp(category).zero? }
181
+ return [] unless category_key
182
+
183
+ @index['categories'][category_key]['brains'].map do |brain_name, brain_data|
184
+ build_meta_entry(brain_name, category_key, brain_data)
185
+ end
186
+ end
187
+
188
+ def meta_entries_by_name(name)
189
+ # Exact match
190
+ brain_name, category, data = find_brain_with_context(name)
191
+ return [build_meta_entry(brain_name, category, data)] if data
192
+
193
+ # Alias match
194
+ if @alias_map&.[](name.downcase)
195
+ brain_name, category, data = find_brain_with_context(@alias_map[name.downcase])
196
+ return [build_meta_entry(brain_name, category, data)] if data
197
+ end
198
+
199
+ # Substring match
200
+ matches = []
201
+ @index['categories'].each do |category_name, category_data|
202
+ category_data['brains'].each do |bname, bdata|
203
+ matches << build_meta_entry(bname, category_name, bdata) if bname.downcase.include?(name.downcase)
204
+ end
205
+ end
206
+ return matches if matches.any?
207
+
208
+ # Tag match
209
+ tag = name.downcase.gsub('_', '-')
210
+ (@index['tag_index']&.[](tag) || []).filter_map do |bname|
211
+ brain_name, category, data = find_brain_with_context(bname)
212
+ build_meta_entry(brain_name, category, data) if data
213
+ end
214
+ end
215
+
216
+ def find_brain_with_context(brain_name)
217
+ @index['categories'].each do |category_name, category_data|
218
+ data = category_data['brains'][brain_name]
219
+ return [brain_name, category_name, data] if data
220
+ end
221
+ [nil, nil, nil]
222
+ end
159
223
 
160
- # Check if activity level matches filter
161
- @options.activity_levels.include?(entry['activity_level'])
224
+ def build_meta_entry(name, category, data)
225
+ {
226
+ 'name' => name,
227
+ 'category' => category,
228
+ 'activity_level' => data['activity_level'],
229
+ 'status' => data['status'],
230
+ 'tags' => data['tags'] || [],
231
+ 'file_count' => data['file_count'] || 0
232
+ }
162
233
  end
163
234
  end
164
235
  end
@@ -13,28 +13,39 @@ module Appydave
13
13
  def find
14
14
  return [] unless @options.omi_query?
15
15
 
16
- paths = []
16
+ resolve_days!
17
+ paths = each_matching.map { |file_path, _frontmatter| file_path }
18
+ paths = paths.last(@options.limit) if @options.limit
19
+ paths
20
+ end
17
21
 
18
- Dir.glob(File.join(@options.omi_dir, '*.md')).each do |file_path|
19
- next unless include_file?(file_path)
22
+ def find_meta
23
+ return [] unless @options.omi_query?
20
24
 
21
- paths << file_path
25
+ resolve_days!
26
+ entries = each_matching.map do |file_path, frontmatter|
27
+ build_omi_meta(file_path, frontmatter)
22
28
  end
23
-
24
- paths.sort
29
+ entries = entries.last(@options.limit) if @options.limit
30
+ entries
25
31
  end
26
32
 
27
33
  private
28
34
 
29
- def include_file?(file_path)
30
- frontmatter = extract_frontmatter(file_path)
31
- return false unless frontmatter
35
+ def each_matching
36
+ results = []
37
+ Dir.glob(File.join(@options.omi_dir, '*.md')).sort.each do |file_path|
38
+ frontmatter = extract_frontmatter(file_path)
39
+ next unless frontmatter
40
+ next unless passes_filters?(frontmatter)
32
41
 
33
- # If enriched-only requested, skip raw files
34
- return false if @options.enriched_only && (!frontmatter['signal'] || !frontmatter['extraction_summary'])
42
+ results << [file_path, frontmatter]
43
+ end
44
+ results
45
+ end
35
46
 
36
- # Apply filters
37
- return false unless signal_matches?(frontmatter)
47
+ def passes_filters?(frontmatter)
48
+ return false if @options.enriched_only && (!frontmatter['signal'] || !frontmatter['extraction_summary'])
38
49
  return false unless routing_matches?(frontmatter)
39
50
  return false unless activity_matches?(frontmatter)
40
51
  return false unless date_matches?(frontmatter)
@@ -43,6 +54,20 @@ module Appydave
43
54
  true
44
55
  end
45
56
 
57
+ def build_omi_meta(file_path, frontmatter)
58
+ {
59
+ 'file' => File.basename(file_path),
60
+ 'extracted_at' => frontmatter['extracted_at'],
61
+ 'extraction_summary' => frontmatter['extraction_summary'],
62
+ 'matched_brains' => frontmatter['matched_brains'] || [],
63
+ 'activity' => frontmatter['activity'],
64
+ 'routing' => frontmatter['routing'],
65
+ 'entities_tools' => frontmatter['entities_tools'] || [],
66
+ 'entities_projects' => frontmatter['entities_projects'] || [],
67
+ 'entities_concepts' => frontmatter['entities_concepts'] || []
68
+ }
69
+ end
70
+
46
71
  def extract_frontmatter(file_path)
47
72
  content = File.read(file_path, encoding: 'utf-8')
48
73
  lines = content.split("\n")
@@ -91,13 +116,10 @@ module Appydave
91
116
  [key, value]
92
117
  end
93
118
 
94
- def signal_matches?(frontmatter)
95
- return true if @options.omi_signals.empty?
96
-
97
- signal = frontmatter['signal']
98
- return false unless signal
119
+ def resolve_days!
120
+ return unless @options.days
99
121
 
100
- @options.omi_signals.include?(signal)
122
+ @options.date_from = (Date.today - @options.days).to_s
101
123
  end
102
124
 
103
125
  def routing_matches?(frontmatter)
@@ -4,26 +4,26 @@ module Appydave
4
4
  module Tools
5
5
  # Options struct for brain/OMI query tools
6
6
  class BrainContextOptions
7
- attr_accessor :brain_names, :tags, :categories, :activity_levels, :status,
8
- :omi, :omi_signals, :omi_routings, :omi_activities,
9
- :date_from, :date_to, :enriched_only,
7
+ attr_accessor :brain_names, :categories, :active, :meta,
8
+ :omi, :omi_routings, :omi_activities,
9
+ :date_from, :date_to, :enriched_only, :days, :limit,
10
10
  :include_index, :output_targets, :formats, :line_limit,
11
11
  :debug_level, :dry_run, :tokens, :base_dir, :omi_dir
12
12
 
13
13
  def initialize
14
14
  @brain_names = []
15
- @tags = []
16
15
  @categories = []
17
- @activity_levels = []
18
- @status = 'active' # default: exclude deprecated
16
+ @active = false
17
+ @meta = false
19
18
 
20
19
  @omi = false
21
- @omi_signals = []
22
20
  @omi_routings = []
23
21
  @omi_activities = []
24
22
  @date_from = nil
25
23
  @date_to = nil
26
- @enriched_only = false
24
+ @enriched_only = true
25
+ @days = nil
26
+ @limit = nil
27
27
 
28
28
  @include_index = true
29
29
  @output_targets = ['clipboard'] # default to clipboard
@@ -46,7 +46,7 @@ module Appydave
46
46
  end
47
47
 
48
48
  def brain_query?
49
- brain_names.any? || tags.any? || categories.any? || activity_levels.any?
49
+ brain_names.any? || categories.any? || active
50
50
  end
51
51
 
52
52
  def omi_query?
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Appydave
4
4
  module Tools
5
- VERSION = '0.80.0'
5
+ VERSION = '0.81.0'
6
6
  end
7
7
  end
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appydave-tools",
3
- "version": "0.80.0",
3
+ "version": "0.81.0",
4
4
  "description": "AppyDave YouTube Automation Tools",
5
5
  "scripts": {
6
6
  "release": "semantic-release"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appydave-tools
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.80.0
4
+ version: 0.81.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Cruwys
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-04-03 00:00:00.000000000 Z
11
+ date: 2026-04-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -285,6 +285,8 @@ files:
285
285
  - docs/guides/platforms/windows/README.md
286
286
  - docs/guides/platforms/windows/dam-testing-plan-windows-powershell.md
287
287
  - docs/guides/platforms/windows/installation.md
288
+ - docs/guides/query-tools-handover.md
289
+ - docs/guides/query-tools.md
288
290
  - docs/guides/tools/bank-reconciliation.md
289
291
  - docs/guides/tools/cli-actions.md
290
292
  - docs/guides/tools/configuration.md