pi-vault-mind 0.8.0 → 0.8.3

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 (119) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +44 -44
  3. package/agents/broadcaster.agent.md +30 -0
  4. package/agents/heavy-lifter.agent.md +30 -0
  5. package/agents/manager.agent.md +29 -0
  6. package/agents/miner.agent.md +29 -0
  7. package/dist/src/agent-bus/Agent.d.ts +49 -0
  8. package/dist/src/agent-bus/Agent.js +97 -0
  9. package/dist/src/agent-bus/AgentLoader.d.ts +33 -0
  10. package/dist/src/agent-bus/AgentLoader.js +102 -0
  11. package/dist/src/agent-bus/AgentRegistry.d.ts +17 -0
  12. package/dist/src/agent-bus/AgentRegistry.js +20 -0
  13. package/dist/src/agent-bus/LLMProvider.d.ts +36 -0
  14. package/dist/src/agent-bus/LLMProvider.js +125 -0
  15. package/dist/src/agent-bus/MessageBus.d.ts +47 -0
  16. package/dist/src/agent-bus/MessageBus.js +81 -0
  17. package/dist/src/agent-bus/TaskQueue.d.ts +27 -0
  18. package/dist/src/agent-bus/TaskQueue.js +57 -0
  19. package/dist/src/agent-bus/index.d.ts +6 -0
  20. package/dist/src/agent-bus/index.js +6 -0
  21. package/dist/src/agents/BroadcasterAgent.d.ts +19 -0
  22. package/dist/src/agents/BroadcasterAgent.js +70 -0
  23. package/dist/src/agents/HeavyLifterAgent.d.ts +26 -0
  24. package/dist/src/agents/HeavyLifterAgent.js +73 -0
  25. package/dist/src/agents/ManagerAgent.d.ts +20 -0
  26. package/dist/src/agents/ManagerAgent.js +71 -0
  27. package/dist/src/agents/MinerAgent.d.ts +19 -0
  28. package/dist/src/agents/MinerAgent.js +70 -0
  29. package/dist/src/agents/index.d.ts +4 -0
  30. package/dist/src/agents/index.js +4 -0
  31. package/dist/src/auth.d.ts +49 -2
  32. package/dist/src/auth.js +149 -7
  33. package/dist/src/autosync.d.ts +1 -1
  34. package/dist/src/autosync.js +3 -3
  35. package/dist/src/bridge.d.ts +45 -0
  36. package/dist/src/bridge.js +189 -0
  37. package/dist/src/commands.d.ts +1 -1
  38. package/dist/src/commands.js +419 -295
  39. package/dist/src/context-capture.d.ts +22 -0
  40. package/dist/src/context-capture.js +41 -0
  41. package/dist/src/discover-schema.d.ts +1 -1
  42. package/dist/src/discover-schema.js +4 -4
  43. package/dist/src/embed-queue.d.ts +1 -1
  44. package/dist/src/embed-queue.js +1 -1
  45. package/dist/src/engine.d.ts +65 -0
  46. package/dist/src/engine.js +244 -0
  47. package/dist/src/events.js +1 -1
  48. package/dist/src/graph.d.ts +3 -3
  49. package/dist/src/identity-injector.d.ts +15 -0
  50. package/dist/src/identity-injector.js +102 -0
  51. package/dist/src/index.js +88 -49
  52. package/dist/src/intake.js +4 -4
  53. package/dist/src/lance.d.ts +11 -37
  54. package/dist/src/lance.js +183 -240
  55. package/dist/src/modal-client.d.ts +14 -4
  56. package/dist/src/modal-client.js +50 -34
  57. package/dist/src/modal-config.d.ts +26 -10
  58. package/dist/src/modal-config.js +36 -5
  59. package/dist/src/personalize.d.ts +47 -0
  60. package/dist/src/personalize.js +352 -0
  61. package/dist/src/server.d.ts +30 -4
  62. package/dist/src/server.js +146 -64
  63. package/dist/src/settings-ui.d.ts +3 -1
  64. package/dist/src/settings-ui.js +84 -77
  65. package/dist/src/status.d.ts +25 -0
  66. package/dist/src/status.js +49 -0
  67. package/dist/src/sync.d.ts +1 -1
  68. package/dist/src/sync.js +19 -19
  69. package/dist/src/tombstone.js +2 -2
  70. package/dist/src/tools.js +112 -130
  71. package/dist/src/types.d.ts +86 -18
  72. package/dist/src/types.js +7 -4
  73. package/dist/src/utils.d.ts +5 -1
  74. package/dist/src/utils.js +24 -8
  75. package/dist/src/vault-tools.d.ts +29 -0
  76. package/dist/src/vault-tools.js +314 -0
  77. package/dist/src/vault-writer.d.ts +4 -5
  78. package/dist/src/vault-writer.js +13 -13
  79. package/dist/src/vm-handlers.d.ts +15 -0
  80. package/dist/src/vm-handlers.js +469 -0
  81. package/dist/src/watcher.d.ts +18 -4
  82. package/dist/src/watcher.js +109 -98
  83. package/dist/test/auth.test.js +57 -7
  84. package/dist/test/bridge-identity.test.js +388 -0
  85. package/dist/test/discover-schema.test.js +2 -2
  86. package/dist/test/engine-identity.test.js +119 -0
  87. package/dist/test/index.test.js +5 -6
  88. package/dist/test/lance-modal.test.js +7 -7
  89. package/dist/test/modal-config.test.js +51 -29
  90. package/dist/test/personalize.test.js +212 -0
  91. package/dist/test/rest-queue.test.js +1 -1
  92. package/dist/test/rest-setup.test.js +21 -21
  93. package/dist/test/{rest-wiki.test.js → rest-vm.test.js} +27 -23
  94. package/dist/test/server-ws.test.js +4 -4
  95. package/dist/test/sync.test.js +2 -2
  96. package/dist/test/tombstone.test.js +1 -1
  97. package/dist/test/vault-tools.test.js +224 -0
  98. package/package.json +2 -1
  99. package/scripts/check-deps.sh +207 -0
  100. package/scripts/e2e-ws.mjs +4 -4
  101. package/scripts/modal-e2e-smoke.mjs +1 -1
  102. package/scripts/setup-test-config.sh +1 -5
  103. package/scripts/test-slash-commands.mjs +197 -0
  104. package/skills/.agents/broadcaster.agent.md +31 -0
  105. package/skills/.agents/heavy-lifter.agent.md +31 -0
  106. package/skills/.agents/manager.agent.md +30 -0
  107. package/skills/.agents/miner.agent.md +30 -0
  108. package/skills/vault-mind/SKILL.md +50 -50
  109. package/skills/vault-mind/references/tool-reference.md +25 -25
  110. package/skills/vault-mind-broadcaster/SKILL.md +1 -1
  111. package/skills/vault-mind-heavy-lifter/SKILL.md +3 -3
  112. package/skills/vault-mind-manager/SKILL.md +7 -7
  113. package/skills/vault-mind-miner/SKILL.md +11 -11
  114. package/skills/vault-mind-setup/SKILL.md +65 -265
  115. package/skills/vault-mind-setup/references/obsidian-vault-structure.md +6 -6
  116. package/skills/vault-mind-setup/references/pi-extension-wiring.md +24 -33
  117. package/skills/vault-mind-setup/references/troubleshooting-tree.md +25 -26
  118. package/dist/src/auto-index.d.ts +0 -47
  119. package/dist/src/auto-index.js +0 -122
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.8.0 - 2026-06-24
4
+
5
+ ### Added
6
+
7
+ - `discover_schema` tool and `/vm discover-schema` command — infer schema from a `.jsonl` file and register it as a collection.
8
+ - `tombstone_entry` tool and `/vm tombstone` command — redact a JSONL entry in place while preserving the append-only log format.
9
+ - `/vm query` command — hybrid semantic + FTS search over a collection from the slash command tree.
10
+ - `/vm collection list` command — list configured collections without opening the TUI selector.
11
+ - `ask_intake` interactive questionnaire tool with optional persistence to the ledger, vault, or both.
12
+ - Advanced deduping options (`dedupMode`, `dedupThreshold`) and background auto-indexing hooks for collection directories.
13
+ - Always-on capture **Tier A** recipe in `docs/getting-started/CAPTURE_SETUP.md` (iOS Shortcut + Actions for Obsidian, voice memo → Shortcut, desktop Templater hotkey).
14
+ - Vault-specific pi config + TUI launcher in the Obsidian plugin: reads `<vault>/.pi/agent/system.md` and launches pi from setup/status views.
15
+ - Published `pi-vault-mind@0.8.0` and `obsidian-pi-vault-mind@0.1.0` to npm.
16
+
17
+ ### Fixed
18
+
19
+ - HOME capture path bug: `expandHome()` now falls back to `process.env.USERPROFILE` on Windows and handles bare `~` correctly.
20
+ - Broken internal markdown links after the 0.7.6 docs reorganization.
21
+ - Removed stale `site/` MkDocs build output from git tracking.
22
+
3
23
  ## 0.7.1 - 2026-06-14
4
24
 
5
25
  ### Fixed
package/README.md CHANGED
@@ -10,17 +10,17 @@ Passive Obsidian vault extension for the [pi](https://github.com/mariozechner/pi
10
10
 
11
11
  > Looking for the legacy ledger-first extension (predecessor project)?
12
12
  > See [kylebrodeur/pi-qmd-ledger](https://github.com/kylebrodeur/pi-qmd-ledger).
13
- > This project was renamed twice: `pi-qmd-ledger` → `pi-llm-wiki` (intermediate) → `pi-vault-mind` (current).
13
+ > This project was renamed twice: `pi-qmd-ledger` → `pi-knowledge-store` (intermediate) → `pi-vault-mind` (current).
14
14
 
15
15
  ## Features
16
16
 
17
17
  - **Passive File Watcher** — drop `@agent-Miner`, `@agent-Broadcaster`, etc. in any Obsidian note. Save the file. The watcher detects the marker, groups by role, and dispatches isolated subagent forks (`vault-mind-{role}` agents). No chat pollution, no manual triggers.
18
18
  - **Multi-Agent Architecture** — five specialist agents under the `vault-mind-{role}` skill naming: **Manager** (interactive orchestrator), **Miner** (research + entity extraction), **Broadcaster** (NotebookLM artifacts), **Heavy-Lifter** (external delegation), **Watcher** (passive file observer).
19
19
  - **LanceDB Vector + FTS + Graph** — hybrid semantic + keyword search with automatic entity extraction and BFS graph traversal. All local, no external binaries.
20
- - **JSONL Source-of-Truth + LanceDB Index** — every fact lives in a durable, human-readable, version-control-friendly `collections/*.jsonl` file. The LanceDB index is derived and rebuildable via `/wiki reindex --all --reembed`.
20
+ - **JSONL Source-of-Truth + LanceDB Index** — every fact lives in a durable, human-readable, version-control-friendly `collections/*.jsonl` file. The LanceDB index is derived and rebuildable via `/vm reindex --all --reembed`.
21
21
  - **Bidirectional Obsidian Sync** — substantial entries (`>200 chars` or tagged `decision`/`insight`/`requirement`) auto-write to `Vault/Agent/Inbox/`. Graph entities render as Obsidian Canvas files.
22
22
  - **Two-Layer Config** — global (`~/.pi/agent/vault-mind.config.json`) for shared settings, project (`./pi-vault-mind.config.json`) for project-specific knowledge. Works across all projects from any directory.
23
- - **Interactive Setup Wizard** — `/wiki setup` walks through vault path, embedding provider, and model selection. CLI mode: `--vault`, `--provider`, `--model` flags for scripting.
23
+ - **Interactive Setup Wizard** — `/vm setup` walks through vault path, embedding provider, and model selection. CLI mode: `--vault`, `--provider`, `--model` flags for scripting.
24
24
 
25
25
  ## Architecture
26
26
 
@@ -70,7 +70,7 @@ See [`docs/architecture/index.md`](docs/architecture/index.md) for the full agen
70
70
  pi-vault-mind works on any directory, but for the **full Obsidian experience**, you need a few things in Obsidian itself:
71
71
 
72
72
  ### Required: An Obsidian vault
73
- Just point `/wiki setup` at any directory used as an Obsidian vault. pi-vault-mind auto-detects `.obsidian/` and respects `.obsidian/`, `.git/`, `.trash/`.
73
+ Just point `/vm setup` at any directory used as an Obsidian vault. pi-vault-mind auto-detects `.obsidian/` and respects `.obsidian/`, `.git/`, `.trash/`.
74
74
 
75
75
  ### Recommended: Official Obsidian CLI (1.12+)
76
76
 
@@ -165,7 +165,7 @@ These skills let the **Miner, Broadcaster, and Heavy-Lifter agents** produce val
165
165
  | **Callouts** | `> [!info]`, `> [!warning]` for syntheses and contradictions |
166
166
  | **Embeds** | `![[Note]]` to transclude summaries into synthesis docs |
167
167
  | **Obsidian Bases (`.base`)** | Agent-generated dynamic tables/boards/kanbans in `Agent/Tasks/` |
168
- | **JSON Canvas (`.canvas`)** | `wiki_sync(format="canvas")` writes entity graph as Canvas JSON |
168
+ | **JSON Canvas (`.canvas`)** | `vm_sync(format="canvas")` writes entity graph as Canvas JSON |
169
169
  | **Obsidian Sync** | Primary sync mechanism across devices |
170
170
 
171
171
  ### Optional: NotebookLM integration (Broadcaster)
@@ -209,7 +209,7 @@ pi install git:git@github.com:kylebrodeur/pi-vault-mind
209
209
  ### 2. Configure (interactive wizard)
210
210
 
211
211
  ```
212
- /wiki setup
212
+ /vm setup
213
213
  ```
214
214
 
215
215
  This walks you through: vault path → embedding provider → Ollama model (if applicable).
@@ -217,20 +217,20 @@ This walks you through: vault path → embedding provider → Ollama model (if a
217
217
  Or via CLI for scripting:
218
218
 
219
219
  ```bash
220
- /wiki setup --vault /home/you/Obsidian/MyVault --provider transformers
221
- /wiki setup --vault /home/you/Obsidian/MyVault --provider ollama --model embeddinggemma
220
+ /vm setup --vault /home/you/Obsidian/MyVault --provider transformers
221
+ /vm setup --vault /home/you/Obsidian/MyVault --provider ollama --model embeddinggemma
222
222
  ```
223
223
 
224
224
  Config is written to `~/.pi/agent/vault-mind.config.json` — it applies globally
225
225
  no matter which project directory you open pi from.
226
226
 
227
- You can re-run `/wiki setup` anytime to view or change settings.
227
+ You can re-run `/vm setup` anytime to view or change settings.
228
228
 
229
229
  ### 3. Start using
230
230
 
231
231
  ```
232
- append_wiki(collection="main", mode="autopilot", entry={"id":"1","domain":"auth","fact":"JWT tokens expire after 1 hour","tag":"security"})
233
- wiki_search(collection="main", query="token expiry")
232
+ vm_append(collection="main", mode="autopilot", entry={"id":"1","domain":"auth","fact":"JWT tokens expire after 1 hour","tag":"security"})
233
+ vm_search(collection="main", query="token expiry")
234
234
  ```
235
235
 
236
236
  Entries are automatically embedded and stored in LanceDB. If graph is enabled, entities and relations are also extracted.
@@ -257,7 +257,7 @@ Edit `pi-vault-mind.config.json` to match your domain:
257
257
  "filterField": "tag"
258
258
  }
259
259
  ],
260
- "wiki": {
260
+ "vaultMind": {
261
261
  "dataDir": ".lancedb",
262
262
  "embedding": {
263
263
  "provider": "transformers",
@@ -329,38 +329,38 @@ Edit `pi-vault-mind.config.json` to match your domain:
329
329
 
330
330
  | Tool | Purpose |
331
331
  | ------------------ | ------------------------------------------------------- |
332
- | `wiki_search` | Semantic search via LanceDB (vector + FTS) |
333
- | `wiki_fts_search` | Exact keyword full-text search (Tantivy BM25) |
334
- | `wiki_graph_query` | Traverse entity connections in the graph layer |
335
- | `wiki_status` | Show LanceDB table sizes and health |
336
- | `query_wiki` | Deterministic JSONL search by collection name |
337
- | `append_wiki` | Append with strict/gated/autopilot modes + dual-write |
338
- | `configure_wiki` | Read or update config at runtime |
339
- | `describe_wiki` | Introspect schema, count, and sample entries |
340
- | `wiki_stats` | Dashboard: counts, sizes, LanceDB status |
341
- | `wiki_export` | Export to JSON, CSV, or Markdown |
342
- | `promote_wiki` | Promote entries between collections via pending queue |
332
+ | `vm_search` | Semantic search via LanceDB (vector + FTS) |
333
+ | `vm_fts_search` | Exact keyword full-text search (Tantivy BM25) |
334
+ | `vm_graph_query` | Traverse entity connections in the graph layer |
335
+ | `vm_status` | Show LanceDB table sizes and health |
336
+ | `vm_query` | Deterministic JSONL search by collection name |
337
+ | `vm_append` | Append with strict/gated/autopilot modes + dual-write |
338
+ | `vm_configure` | Read or update config at runtime |
339
+ | `vm_describe` | Introspect schema, count, and sample entries |
340
+ | `vm_stats` | Dashboard: counts, sizes, LanceDB status |
341
+ | `vm_export` | Export to JSON, CSV, or Markdown |
342
+ | `vm_promote` | Promote entries between collections via pending queue |
343
343
 
344
344
  ## Commands
345
345
 
346
346
  | Command | Purpose |
347
347
  | ------------------------------ | -------------------------------------------------------- |
348
- | `/wiki help` | Show usage help |
349
- | `/wiki setup` | **Interactive global config wizard** (vault, embedding) |
350
- | `/wiki init` | Scaffold project config + collections |
351
- | `/wiki validate` | Health check LanceDB, config, and all collection paths |
352
- | `/wiki approve [collection]` | Batch-review pending entries |
353
- | `/wiki settings` | Open interactive settings dashboard |
354
- | `/wiki audit` | Audit config for missing defaults |
355
- | `/wiki reindex [--all] [--reembed] [--remote]` | Rebuild FTS + vector indexes; `--remote` offloads to Modal |
356
- | `/wiki collection select` | Select active collection (shortcut: ctrl+alt+l) |
357
- | `/wiki collection create` | Interactive wizard to create a new collection |
358
- | `/wiki injector create` | Interactive wizard to create a new injector |
359
- | `/wiki context enable \| disable \| status` | Manage pi-context integration |
360
- | `/wiki embedding status \| use \| model \| models \| pull` | Manage embedding provider |
361
- | `/wiki modal status \| config \| sync \| jobs \| migrate` | Manage Modal embedding + vector sync |
362
- | `/wiki watcher start \| stop \| status` | Manage the passive file watcher |
363
- | `/wiki server status` | Show HTTP server status, port, and uptime |
348
+ | `/vm help` | Show usage help |
349
+ | `/vm setup` | **Interactive global config wizard** (vault, embedding) |
350
+ | `/vm init` | Scaffold project config + collections |
351
+ | `/vm validate` | Health check LanceDB, config, and all collection paths |
352
+ | `/vm approve [collection]` | Batch-review pending entries |
353
+ | `/vm settings` | Open interactive settings dashboard |
354
+ | `/vm audit` | Audit config for missing defaults |
355
+ | `/vm reindex [--all] [--reembed] [--remote]` | Rebuild FTS + vector indexes; `--remote` offloads to Modal |
356
+ | `/vm collection select` | Select active collection (shortcut: ctrl+alt+l) |
357
+ | `/vm collection create` | Interactive wizard to create a new collection |
358
+ | `/vm injector create` | Interactive wizard to create a new injector |
359
+ | `/vm context enable \| disable \| status` | Manage pi-context integration |
360
+ | `/vm embedding status \| use \| model \| models \| pull` | Manage embedding provider |
361
+ | `/vm modal status \| config \| sync \| jobs \| migrate` | Manage Modal embedding + vector sync |
362
+ | `/vm watcher start \| stop \| status` | Manage the passive file watcher |
363
+ | `/vm server status` | Show HTTP server status, port, and uptime |
364
364
 
365
365
  ## Documentation
366
366
 
@@ -393,7 +393,7 @@ The local extension now integrates the Modal embedding service as a fully
393
393
  configurable embedding provider: on-demand `/embed` for search (with an offline
394
394
  fallback that degrades to FTS, never crashes), a sync-down path that pulls
395
395
  server-side vectors into the local LanceDB with a monotonic `seq` watermark,
396
- remote bulk re-index (`/wiki reindex --all --reembed --remote`), and debounced +
396
+ remote bulk re-index (`/vm reindex --all --reembed --remote`), and debounced +
397
397
  batched append embedding via the coalescer. Existing non-modal users see no
398
398
  behavior change. See [docs/integrations/MODAL_EMBEDDING.md](docs/integrations/MODAL_EMBEDDING.md) for the
399
399
  full design.
@@ -411,9 +411,9 @@ full design.
411
411
  | Doc | Description |
412
412
  |---|---|
413
413
  | [skills/vault-mind/SKILL.md](skills/vault-mind/SKILL.md) | The Manager skill — what pi auto-loads about this extension |
414
- | [docs/CHANGELOG.md](docs/CHANGELOG.md) | Version history (rename from `pi-llm-wiki` to `pi-vault-mind` was v0.7.0) |
415
- | [docs/reference/tools.md](docs/reference/tools.md) | The 11 `wiki_*` and `query_wiki`/`append_wiki`/etc. tools — parameters, return shapes |
416
- | [docs/reference/commands.md](docs/reference/commands.md) | Full `/wiki` slash command tree |
414
+ | [docs/CHANGELOG.md](docs/CHANGELOG.md) | Version history (rename from `pi-knowledge-store` to `pi-vault-mind` was v0.7.0) |
415
+ | [docs/reference/tools.md](docs/reference/tools.md) | The 11 `vm_*` and `vm_query`/`vm_append`/etc. tools — parameters, return shapes |
416
+ | [docs/reference/commands.md](docs/reference/commands.md) | Full `/vm` slash command tree |
417
417
  | [docs/reference/configuration.md](docs/reference/configuration.md) | The complete `pi-vault-mind.config.json` schema |
418
418
  | [docs/reference/skill.md](docs/reference/skill.md) | Manifest of all bundled skills and their trigger phrases |
419
419
 
@@ -444,7 +444,7 @@ full design.
444
444
 
445
445
  | Doc | Description |
446
446
  |---|---|
447
- | [docs/_archive/](docs/_archive/) | Historical docs kept for context (e.g. the `pi-llm-wiki` → `pi-vault-mind` rename audit) |
447
+ | [docs/_archive/](docs/_archive/) | Historical docs kept for context (e.g. the `pi-knowledge-store` → `pi-vault-mind` rename audit) |
448
448
  | [docs/_archive/legacy-audit.md](docs/_archive/legacy-audit.md) | The 2026-06-08 legacy-terminology audit (139 findings, 13 blockers) and its resolution log. Resolved 2026-06-09; archived 2026-06-16 (in the repo, not on the docs site) |
449
449
 
450
450
  ## Contributing
@@ -0,0 +1,30 @@
1
+ ---
2
+ type: BroadcasterAgent
3
+ role: broadcaster
4
+ capabilities: [read, write, edit]
5
+ allowed_tools: [read, write, edit, vm_search, vm_fts_search]
6
+ write_collections: []
7
+ can_publish: false
8
+ llm_provider: ollama
9
+ ---
10
+
11
+ # Broadcaster Agent
12
+
13
+ Content distribution agent for pi-vault-mind. Creates presentations, summaries,
14
+ and external-facing content from vault knowledge.
15
+
16
+ ## Capability Boundary
17
+
18
+ - **MAY**: read files, write files, edit files
19
+ - **MAY**: search collections via vm_search, vm_fts_search
20
+ - **MUST NOT**: run bash commands, grep, or find
21
+ - **MUST NOT**: write to the durable knowledge store
22
+ - **MUST NOT**: publish or spawn sub-agents
23
+ - Write output only under Agent/Presentations/
24
+
25
+ ## Tool Calling Convention
26
+
27
+ When calling pi-vault-mind tools, always include your role:
28
+ ```
29
+ vm_search({ query: "...", role: "broadcaster" })
30
+ ```
@@ -0,0 +1,30 @@
1
+ ---
2
+ type: HeavyLifterAgent
3
+ role: heavy-lifter
4
+ capabilities: [read, write, edit, grep, find, ls, bash]
5
+ allowed_tools: [read, write, edit, grep, find, ls, bash, vm_search, vm_fts_search]
6
+ write_collections: []
7
+ can_publish: false
8
+ llm_provider: ollama
9
+ ---
10
+
11
+ # Heavy-Lifter Agent
12
+
13
+ External CLI execution agent for pi-vault-mind. Runs bash commands in an isolated
14
+ worktree. Cannot write to the durable knowledge store — all findings must be
15
+ routed to the Miner for storage.
16
+
17
+ ## Capability Boundary
18
+
19
+ - **MAY**: read files, write files, edit files, run bash commands, search with grep/find/ls
20
+ - **MUST NOT**: write to the durable store (vm_append, vm_sync disabled)
21
+ - **MUST NOT**: spawn sub-agents
22
+ - **MUST NOT**: publish to the human-facing vault
23
+ - All bash commands run in an isolated worktree. Do not modify files outside it.
24
+
25
+ ## Tool Calling Convention
26
+
27
+ When calling pi-vault-mind tools, always include your role:
28
+ ```
29
+ vm_search({ query: "...", role: "heavy-lifter" })
30
+ ```
@@ -0,0 +1,29 @@
1
+ ---
2
+ type: ManagerAgent
3
+ role: manager
4
+ capabilities: [read, write, edit, grep, find, ls]
5
+ allowed_tools: [read, write, edit, grep, find, ls, vm_search, vm_fts_search, vm_append, vm_sync, vm_promote, vm_query, vm_configure, vm_describe, vm_stats, vm_export, vm_ingest, vm_status, vm_graph_query]
6
+ write_collections: [main, research, presentations]
7
+ can_publish: true
8
+ llm_provider: ollama
9
+ ---
10
+
11
+ # Manager Agent
12
+
13
+ Final gate and publishing agent for pi-vault-mind. The only role authorized to
14
+ publish to the human-facing vault and dispatch sub-agents.
15
+
16
+ ## Capability Boundary
17
+
18
+ - **MAY**: all vm_* tools, read, write, edit, grep, find, ls
19
+ - **MAY**: write to any collection
20
+ - **MAY**: publish to the human-facing vault via vm_sync
21
+ - **MAY**: dispatch sub-agents
22
+ - **MUST NOT**: run bash commands
23
+
24
+ ## Tool Calling Convention
25
+
26
+ When calling pi-vault-mind tools, always include your role:
27
+ ```
28
+ vm_sync({ collection: "main", role: "manager" })
29
+ ```
@@ -0,0 +1,29 @@
1
+ ---
2
+ type: MinerAgent
3
+ role: miner
4
+ capabilities: [read, write, edit, grep, find, ls]
5
+ allowed_tools: [read, write, edit, grep, find, ls, vm_search, vm_fts_search, vm_append]
6
+ write_collections: [main, research]
7
+ can_publish: false
8
+ llm_provider: ollama
9
+ ---
10
+
11
+ # Miner Agent
12
+
13
+ Knowledge extraction and storage agent for pi-vault-mind. Extracts entities and
14
+ relationships from vault content and stores them in the durable knowledge store.
15
+
16
+ ## Capability Boundary
17
+
18
+ - **MAY**: read files, write files, edit files, search with grep/find/ls
19
+ - **MAY**: append to collections 'main' and 'research' via vm_append
20
+ - **MUST NOT**: run bash commands
21
+ - **MUST NOT**: publish to the human-facing vault (vm_sync disabled)
22
+ - **MUST NOT**: spawn sub-agents
23
+
24
+ ## Tool Calling Convention
25
+
26
+ When calling pi-vault-mind tools, always include your role:
27
+ ```
28
+ vm_append({ collection: "main", entry: {...}, role: "miner" })
29
+ ```
@@ -0,0 +1,49 @@
1
+ import type { LLMProvider } from "./LLMProvider.js";
2
+ import type { Message, MessageBus } from "./MessageBus.js";
3
+ export interface AgentConfig {
4
+ id: string;
5
+ role: string;
6
+ capabilities: string[];
7
+ }
8
+ /**
9
+ * Base Agent
10
+ *
11
+ * Agnostic agent that sits on the MessageBus.
12
+ * Can be extended for Coding Tasks or Physical Manufacturing Tasks.
13
+ */
14
+ export declare abstract class Agent {
15
+ config: AgentConfig;
16
+ protected bus: MessageBus;
17
+ protected llm?: LLMProvider;
18
+ constructor(config: AgentConfig, bus: MessageBus, llm?: LLMProvider);
19
+ /**
20
+ * Broadcast a message to the environment
21
+ */
22
+ broadcast(topic: string, payload: Record<string, unknown>): Promise<void>;
23
+ /**
24
+ * Direct message another agent
25
+ */
26
+ sendDirect(targetAgentId: string, payload: Record<string, unknown>): Promise<void>;
27
+ /**
28
+ * Hook for handling incoming messages. To be overridden by implementations.
29
+ */
30
+ protected handleMessage(message: Message): Promise<void>;
31
+ /**
32
+ * Perform an LLM-driven decision in JSON mode
33
+ */
34
+ protected askLLM<T = unknown>(promptText: string, jsonMode?: true): Promise<T | null>;
35
+ protected askLLM(promptText: string, jsonMode: false): Promise<string>;
36
+ /**
37
+ * The main tick or tick-equivalent.
38
+ * If running in an event loop (e.g. manufacturing), override this.
39
+ */
40
+ abstract tick(): Promise<void>;
41
+ /**
42
+ * Helper to invoke a Pi tool via the Pi Tool Bridge.
43
+ * Agent publishes a request and awaits a response on a unique topic.
44
+ * @param toolName The name of the pi.tool to invoke (e.g., 'append_ledger').
45
+ * @param args The arguments to pass to the pi.tool.
46
+ * @param timeoutMs Maximum time to wait for a response from the bridge.
47
+ */
48
+ protected invokePiTool(toolName: string, args: Record<string, unknown>, timeoutMs?: number): Promise<unknown>;
49
+ }
@@ -0,0 +1,97 @@
1
+ import { randomUUID } from "node:crypto";
2
+ /**
3
+ * Base Agent
4
+ *
5
+ * Agnostic agent that sits on the MessageBus.
6
+ * Can be extended for Coding Tasks or Physical Manufacturing Tasks.
7
+ */
8
+ export class Agent {
9
+ config;
10
+ bus;
11
+ llm;
12
+ constructor(config, bus, llm) {
13
+ this.config = config;
14
+ this.bus = bus;
15
+ this.llm = llm;
16
+ // Subscribe to direct messages and broadcasts
17
+ this.bus.subscribe(`direct:${this.config.id}`, this.handleMessage.bind(this));
18
+ this.bus.subscribe("broadcast", this.handleMessage.bind(this));
19
+ }
20
+ /**
21
+ * Broadcast a message to the environment
22
+ */
23
+ async broadcast(topic, payload) {
24
+ await this.bus.publish(topic, this.config.id, payload);
25
+ }
26
+ /**
27
+ * Direct message another agent
28
+ */
29
+ async sendDirect(targetAgentId, payload) {
30
+ await this.bus.publish(`direct:${targetAgentId}`, this.config.id, payload);
31
+ }
32
+ /**
33
+ * Hook for handling incoming messages. To be overridden by implementations.
34
+ */
35
+ async handleMessage(message) {
36
+ // Default: Do nothing
37
+ }
38
+ async askLLM(promptText, jsonMode = true) {
39
+ if (!this.llm) {
40
+ throw new Error(`Agent ${this.config.id} has no LLM provider attached.`);
41
+ }
42
+ const response = await this.llm.prompt(promptText, { jsonMode });
43
+ if (jsonMode) {
44
+ try {
45
+ return JSON.parse(response);
46
+ }
47
+ catch {
48
+ console.error(`Agent ${this.config.id} failed to parse JSON from LLM:`, response);
49
+ return null;
50
+ }
51
+ }
52
+ return response;
53
+ }
54
+ /**
55
+ * Helper to invoke a Pi tool via the Pi Tool Bridge.
56
+ * Agent publishes a request and awaits a response on a unique topic.
57
+ * @param toolName The name of the pi.tool to invoke (e.g., 'append_ledger').
58
+ * @param args The arguments to pass to the pi.tool.
59
+ * @param timeoutMs Maximum time to wait for a response from the bridge.
60
+ */
61
+ async invokePiTool(toolName, args, timeoutMs = 30000) {
62
+ const requestId = randomUUID();
63
+ const requestTopic = "pi_tool_bridge_requests";
64
+ const responseTopic = `pi_tool_bridge_responses:${this.config.id}:${requestId}`;
65
+ return new Promise((resolve, reject) => {
66
+ // biome-ignore lint/style/useConst: assigned after handler/subscribe setup
67
+ let timeout;
68
+ const cleanup = () => {
69
+ clearTimeout(timeout);
70
+ this.bus.unsubscribe(responseTopic, handler);
71
+ };
72
+ const handler = (message) => {
73
+ if (message.payload.requestId === requestId) {
74
+ cleanup();
75
+ if (message.payload.error) {
76
+ reject(new Error(String(message.payload.error)));
77
+ }
78
+ else {
79
+ resolve(message.payload.result);
80
+ }
81
+ }
82
+ };
83
+ this.bus.subscribe(responseTopic, handler);
84
+ timeout = setTimeout(() => {
85
+ cleanup();
86
+ reject(new Error(`Pi tool invocation timed out for tool: '${toolName}', requestId: ${requestId}`));
87
+ }, timeoutMs);
88
+ void this.broadcast(requestTopic, {
89
+ requestId,
90
+ agentId: this.config.id,
91
+ toolName,
92
+ args,
93
+ responseTopic,
94
+ });
95
+ });
96
+ }
97
+ }
@@ -0,0 +1,33 @@
1
+ import type { Agent } from "./Agent.js";
2
+ import type { LLMProvider } from "./LLMProvider.js";
3
+ import type { MessageBus } from "./MessageBus.js";
4
+ export interface AgentFileDefinition {
5
+ type: string;
6
+ role: string;
7
+ capabilities: string[];
8
+ llm_provider: string;
9
+ llm_model: string;
10
+ allowed_tools?: string[];
11
+ write_collections?: string[];
12
+ can_publish?: boolean;
13
+ config_dir?: string;
14
+ [key: string]: unknown;
15
+ }
16
+ export interface AgentLoaderConfig {
17
+ agentsDirectory: string;
18
+ bus: MessageBus;
19
+ llmProviderFactory: (providerName: string, model: string) => Promise<LLMProvider | null>;
20
+ }
21
+ /**
22
+ * AgentLoader reads Markdown files with YAML frontmatter from a directory
23
+ * and instantiates agents using the AgentRegistry.
24
+ */
25
+ export declare class AgentLoader {
26
+ private config;
27
+ constructor(config: AgentLoaderConfig);
28
+ /**
29
+ * Loads all agents defined in the .agents/ directory.
30
+ */
31
+ loadAgents(): Promise<Agent[]>;
32
+ private parseMarkdownWithFrontmatter;
33
+ }
@@ -0,0 +1,102 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { AgentRegistry } from "./AgentRegistry.js";
4
+ /**
5
+ * AgentLoader reads Markdown files with YAML frontmatter from a directory
6
+ * and instantiates agents using the AgentRegistry.
7
+ */
8
+ export class AgentLoader {
9
+ config;
10
+ constructor(config) {
11
+ this.config = config;
12
+ }
13
+ /**
14
+ * Loads all agents defined in the .agents/ directory.
15
+ */
16
+ async loadAgents() {
17
+ const { agentsDirectory, bus, llmProviderFactory } = this.config;
18
+ const agents = [];
19
+ try {
20
+ if (!fs.existsSync(agentsDirectory)) {
21
+ console.warn(`[AgentLoader] Agents directory ${agentsDirectory} not found. Skipping.`);
22
+ return [];
23
+ }
24
+ const files = fs.readdirSync(agentsDirectory);
25
+ for (const file of files) {
26
+ if (file.endsWith(".agent.md")) {
27
+ const absolutePath = path.join(agentsDirectory, file);
28
+ const content = fs.readFileSync(absolutePath, "utf8");
29
+ const { frontmatter } = this.parseMarkdownWithFrontmatter(content);
30
+ if (!frontmatter || typeof frontmatter.type !== "string") {
31
+ console.error(`[AgentLoader] Agent file ${file} is missing 'type' in frontmatter. Skipping.`);
32
+ continue;
33
+ }
34
+ const agentType = frontmatter.type;
35
+ const Constructor = AgentRegistry.get(agentType);
36
+ if (!Constructor) {
37
+ console.error(`[AgentLoader] Agent file ${file} specifies type '${agentType}', but no such agent type is registered. Skipping.`);
38
+ continue;
39
+ }
40
+ const agentConfig = {
41
+ id: path.basename(file, ".agent.md"),
42
+ role: frontmatter.role || "General Purpose",
43
+ capabilities: frontmatter.capabilities || [],
44
+ };
45
+ // Create LLM Provider if specified
46
+ let llm = null;
47
+ if (typeof frontmatter.llm_provider === "string" &&
48
+ typeof frontmatter.llm_model === "string") {
49
+ llm = await llmProviderFactory(frontmatter.llm_provider, frontmatter.llm_model);
50
+ }
51
+ // Instantiate the agent
52
+ const agent = new Constructor(agentConfig, bus, llm ?? undefined);
53
+ agents.push(agent);
54
+ console.log(`[AgentLoader] Loaded agent: ${agentConfig.id} (type: ${agentType})`);
55
+ }
56
+ }
57
+ return agents;
58
+ }
59
+ catch (e) {
60
+ const msg = e instanceof Error ? e.message : String(e);
61
+ console.error(`[AgentLoader] Failed to load agents from ${agentsDirectory}: ${msg}`);
62
+ return [];
63
+ }
64
+ }
65
+ parseMarkdownWithFrontmatter(content) {
66
+ const match = content.match(/^---([\s\S]*?)---([\s\S]*)$/);
67
+ if (!match)
68
+ return { frontmatter: null, body: content };
69
+ const yamlContent = match[1];
70
+ const body = match[2];
71
+ try {
72
+ const frontmatter = {};
73
+ for (const line of yamlContent.split(/\r?\n/)) {
74
+ const trimmed = line.trim();
75
+ if (!trimmed || trimmed.startsWith("#"))
76
+ continue;
77
+ const colonIdx = trimmed.indexOf(":");
78
+ if (colonIdx === -1)
79
+ continue;
80
+ const key = trimmed.slice(0, colonIdx).trim();
81
+ let value = trimmed.slice(colonIdx + 1).trim();
82
+ // Parse arrays: [a, b, c]
83
+ if (typeof value === "string" && value.startsWith("[") && value.endsWith("]")) {
84
+ value = value
85
+ .slice(1, -1)
86
+ .split(",")
87
+ .map((s) => s.trim().replace(/^["']|["']$/g, ""))
88
+ .filter(Boolean);
89
+ }
90
+ // Unquote strings
91
+ if (typeof value === "string") {
92
+ value = value.replace(/^["']|["']$/g, "");
93
+ }
94
+ frontmatter[key] = value;
95
+ }
96
+ return { frontmatter, body: body.trim() };
97
+ }
98
+ catch {
99
+ return { frontmatter: null, body: content };
100
+ }
101
+ }
102
+ }
@@ -0,0 +1,17 @@
1
+ import type { Agent, AgentConfig } from "./Agent.js";
2
+ import type { LLMProvider } from "./LLMProvider.js";
3
+ import type { MessageBus } from "./MessageBus.js";
4
+ export type AgentConstructor = new (config: AgentConfig, bus: MessageBus, llm?: LLMProvider) => Agent;
5
+ /**
6
+ * AgentRegistry maintains a mapping of agent 'types' to their concrete class
7
+ * implementations. This allows the AgentLoader to instantiate the correct class
8
+ * based on the YAML definition.
9
+ */
10
+ export declare const AgentRegistry: {
11
+ /** Register an agent class for a given type name. */
12
+ register(type: string, agentConstructor: AgentConstructor): void;
13
+ /** Get the constructor for a given agent type. */
14
+ get(type: string): AgentConstructor | undefined;
15
+ /** List all registered agent types. */
16
+ list(): string[];
17
+ };
@@ -0,0 +1,20 @@
1
+ const registry = new Map();
2
+ /**
3
+ * AgentRegistry maintains a mapping of agent 'types' to their concrete class
4
+ * implementations. This allows the AgentLoader to instantiate the correct class
5
+ * based on the YAML definition.
6
+ */
7
+ export const AgentRegistry = {
8
+ /** Register an agent class for a given type name. */
9
+ register(type, agentConstructor) {
10
+ registry.set(type, agentConstructor);
11
+ },
12
+ /** Get the constructor for a given agent type. */
13
+ get(type) {
14
+ return registry.get(type);
15
+ },
16
+ /** List all registered agent types. */
17
+ list() {
18
+ return Array.from(registry.keys());
19
+ },
20
+ };