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 +4 -4
- data/CHANGELOG.md +12 -0
- data/CLAUDE.md +88 -1
- data/bin/query_brain.rb +13 -16
- data/bin/query_omi.rb +14 -16
- data/docs/guides/query-tools-handover.md +58 -0
- data/docs/guides/query-tools.md +255 -0
- data/lib/appydave/tools/brain_context/brain_finder.rb +93 -22
- data/lib/appydave/tools/brain_context/omi_finder.rb +41 -19
- data/lib/appydave/tools/brain_context/options.rb +9 -9
- data/lib/appydave/tools/version.rb +1 -1
- data/package.json +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '09f48a7490c924291dff958e3df8ba53c28c2dae599cae0ab8581ac3e4ad3ee2'
|
|
4
|
+
data.tar.gz: f1e55198dd31bb3b2b61b61d4f929fc3bda799ecd4cedb96e5f810c994edae4a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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.
|
|
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('--
|
|
14
|
-
options.brain_names <<
|
|
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('--
|
|
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('--
|
|
26
|
-
|
|
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('--
|
|
31
|
-
|
|
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
|
-
|
|
63
|
-
|
|
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('--
|
|
15
|
-
|
|
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('--
|
|
30
|
-
options.
|
|
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('--
|
|
34
|
-
options.
|
|
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('--
|
|
38
|
-
options.
|
|
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
|
-
|
|
69
|
-
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
-
|
|
157
|
-
|
|
158
|
-
|
|
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
|
-
|
|
161
|
-
|
|
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
|
-
|
|
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
|
-
|
|
19
|
-
|
|
22
|
+
def find_meta
|
|
23
|
+
return [] unless @options.omi_query?
|
|
20
24
|
|
|
21
|
-
|
|
25
|
+
resolve_days!
|
|
26
|
+
entries = each_matching.map do |file_path, frontmatter|
|
|
27
|
+
build_omi_meta(file_path, frontmatter)
|
|
22
28
|
end
|
|
23
|
-
|
|
24
|
-
|
|
29
|
+
entries = entries.last(@options.limit) if @options.limit
|
|
30
|
+
entries
|
|
25
31
|
end
|
|
26
32
|
|
|
27
33
|
private
|
|
28
34
|
|
|
29
|
-
def
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
|
|
34
|
-
|
|
42
|
+
results << [file_path, frontmatter]
|
|
43
|
+
end
|
|
44
|
+
results
|
|
45
|
+
end
|
|
35
46
|
|
|
36
|
-
|
|
37
|
-
return false
|
|
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
|
|
95
|
-
return
|
|
96
|
-
|
|
97
|
-
signal = frontmatter['signal']
|
|
98
|
-
return false unless signal
|
|
119
|
+
def resolve_days!
|
|
120
|
+
return unless @options.days
|
|
99
121
|
|
|
100
|
-
@options.
|
|
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, :
|
|
8
|
-
:omi, :
|
|
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
|
-
@
|
|
18
|
-
@
|
|
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 =
|
|
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? ||
|
|
49
|
+
brain_names.any? || categories.any? || active
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
def omi_query?
|
data/package.json
CHANGED
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.
|
|
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-
|
|
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
|