@probelabs/visor 0.1.149 → 0.1.150

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 (123) hide show
  1. package/README.md +52 -1
  2. package/dist/909.index.js +27117 -0
  3. package/dist/ai-review-service.d.ts.map +1 -1
  4. package/dist/config.d.ts.map +1 -1
  5. package/dist/docs/assistant-workflows.md +805 -0
  6. package/dist/docs/event-triggers.md +25 -0
  7. package/dist/docs/scheduler.md +156 -0
  8. package/dist/docs/slack-integration.md +48 -0
  9. package/dist/enterprise/scheduler/knex-store.d.ts +7 -1
  10. package/dist/enterprise/scheduler/knex-store.d.ts.map +1 -1
  11. package/dist/examples/code-talk-as-tool.yaml +76 -0
  12. package/dist/examples/code-talk-workflow.yaml +68 -0
  13. package/dist/examples/intent-router-workflow.yaml +66 -0
  14. package/dist/examples/slack-message-triggers.yaml +270 -0
  15. package/dist/generated/config-schema.d.ts +102 -7
  16. package/dist/generated/config-schema.d.ts.map +1 -1
  17. package/dist/generated/config-schema.json +116 -7
  18. package/dist/git-repository-analyzer.d.ts +8 -0
  19. package/dist/git-repository-analyzer.d.ts.map +1 -1
  20. package/dist/index.js +4030 -4735
  21. package/dist/output/traces/{run-2026-03-03T07-19-07-543Z.ndjson → run-2026-03-03T20-21-24-501Z.ndjson} +84 -84
  22. package/dist/{traces/run-2026-03-03T07-19-50-933Z.ndjson → output/traces/run-2026-03-03T20-22-08-701Z.ndjson} +1806 -1730
  23. package/dist/scheduler/message-trigger.d.ts +47 -0
  24. package/dist/scheduler/message-trigger.d.ts.map +1 -0
  25. package/dist/scheduler/schedule-store.d.ts +31 -1
  26. package/dist/scheduler/schedule-store.d.ts.map +1 -1
  27. package/dist/scheduler/schedule-tool.d.ts +17 -1
  28. package/dist/scheduler/schedule-tool.d.ts.map +1 -1
  29. package/dist/scheduler/store/sqlite-store.d.ts +7 -1
  30. package/dist/scheduler/store/sqlite-store.d.ts.map +1 -1
  31. package/dist/scheduler/store/types.d.ts +45 -0
  32. package/dist/scheduler/store/types.d.ts.map +1 -1
  33. package/dist/sdk/{check-provider-registry-LVLC4EPF.mjs → check-provider-registry-6D5CAX44.mjs} +6 -6
  34. package/dist/sdk/{check-provider-registry-X4OZJWPK.mjs → check-provider-registry-RRYBG6AU.mjs} +6 -6
  35. package/dist/sdk/{check-provider-registry-IYSUDKPB.mjs → check-provider-registry-YFC5KSJY.mjs} +6 -6
  36. package/dist/sdk/{chunk-V6GI4U2M.mjs → chunk-AADKUA6L.mjs} +585 -29
  37. package/dist/sdk/{chunk-6EXCUX7Y.mjs.map → chunk-AADKUA6L.mjs.map} +1 -1
  38. package/dist/sdk/{chunk-6EXCUX7Y.mjs → chunk-CKDFGNF4.mjs} +585 -29
  39. package/dist/sdk/{chunk-GFNXX64M.mjs.map → chunk-CKDFGNF4.mjs.map} +1 -1
  40. package/dist/sdk/{chunk-YYZAN5NK.mjs → chunk-FYK2DJK6.mjs} +106 -9
  41. package/dist/sdk/chunk-FYK2DJK6.mjs.map +1 -0
  42. package/dist/sdk/{chunk-RJLJUTSU.mjs → chunk-FZEQ744M.mjs} +2 -2
  43. package/dist/sdk/{chunk-Q6EPAJ6Z.mjs → chunk-GIAN7HCT.mjs} +3 -3
  44. package/dist/sdk/{chunk-CISJ6DJW.mjs → chunk-GLROSEYJ.mjs} +3 -3
  45. package/dist/sdk/{chunk-VLUGLWLA.mjs → chunk-H4HFH7HH.mjs} +3 -3
  46. package/dist/sdk/{chunk-VLUGLWLA.mjs.map → chunk-H4HFH7HH.mjs.map} +1 -1
  47. package/dist/sdk/{chunk-62TNF5PJ.mjs → chunk-PETLPNRA.mjs} +2 -2
  48. package/dist/sdk/{chunk-62TNF5PJ.mjs.map → chunk-PETLPNRA.mjs.map} +1 -1
  49. package/dist/sdk/{chunk-BR7DYA3S.mjs → chunk-SWO4W57C.mjs} +2 -2
  50. package/dist/sdk/{chunk-GFNXX64M.mjs → chunk-YY3KADY2.mjs} +585 -29
  51. package/dist/sdk/{chunk-V6GI4U2M.mjs.map → chunk-YY3KADY2.mjs.map} +1 -1
  52. package/dist/sdk/{config-KQH254CA.mjs → config-MTEIGCOQ.mjs} +2 -2
  53. package/dist/sdk/{failure-condition-evaluator-IVCTD4BZ.mjs → failure-condition-evaluator-P6QUFLIN.mjs} +3 -3
  54. package/dist/sdk/{failure-condition-evaluator-LZ2AG5PY.mjs → failure-condition-evaluator-XV2ZMFFY.mjs} +3 -3
  55. package/dist/sdk/{git-repository-analyzer-QFMW6WIS.mjs → git-repository-analyzer-TWNJUN42.mjs} +34 -3
  56. package/dist/sdk/git-repository-analyzer-TWNJUN42.mjs.map +1 -0
  57. package/dist/sdk/{github-frontend-DFT5G32K.mjs → github-frontend-A2R7D4N6.mjs} +3 -3
  58. package/dist/sdk/{github-frontend-S523EEJB.mjs → github-frontend-GSB2P5PE.mjs} +3 -3
  59. package/dist/sdk/{host-7YKRMOUJ.mjs → host-CLPM2WVQ.mjs} +2 -2
  60. package/dist/sdk/{host-H7IX4GBK.mjs → host-MR7L57QI.mjs} +2 -2
  61. package/dist/sdk/{routing-LU5PAREW.mjs → routing-KLVK2MJZ.mjs} +4 -4
  62. package/dist/sdk/{routing-ZMBKWMVI.mjs → routing-V3MYZAOH.mjs} +4 -4
  63. package/dist/sdk/{schedule-tool-EOMZFICZ.mjs → schedule-tool-HYM55K3H.mjs} +6 -6
  64. package/dist/sdk/{schedule-tool-NX75VKGA.mjs → schedule-tool-NYLNJUEW.mjs} +6 -6
  65. package/dist/sdk/{schedule-tool-CDVUSZEG.mjs → schedule-tool-PRXFAV4K.mjs} +6 -6
  66. package/dist/sdk/{schedule-tool-handler-3FJHDIPG.mjs → schedule-tool-handler-EFQIYD3W.mjs} +6 -6
  67. package/dist/sdk/{schedule-tool-handler-KKN7XJYT.mjs → schedule-tool-handler-HVWCEGQ6.mjs} +6 -6
  68. package/dist/sdk/{schedule-tool-handler-QNZG55DX.mjs → schedule-tool-handler-M5YI573R.mjs} +6 -6
  69. package/dist/sdk/sdk.d.mts +38 -1
  70. package/dist/sdk/sdk.d.ts +38 -1
  71. package/dist/sdk/sdk.js +706 -22
  72. package/dist/sdk/sdk.js.map +1 -1
  73. package/dist/sdk/sdk.mjs +5 -5
  74. package/dist/sdk/{trace-helpers-EJUIOP6L.mjs → trace-helpers-6NSZBC35.mjs} +2 -2
  75. package/dist/sdk/{trace-helpers-6ROJR7N3.mjs → trace-helpers-TORF3JD5.mjs} +2 -2
  76. package/dist/sdk/{workflow-check-provider-AGZ5JY2I.mjs → workflow-check-provider-3F6CBHVD.mjs} +6 -6
  77. package/dist/sdk/{workflow-check-provider-PTNUWM5W.mjs → workflow-check-provider-OXHMLICJ.mjs} +6 -6
  78. package/dist/sdk/{workflow-check-provider-6ERNNCNA.mjs → workflow-check-provider-XLH7N4FV.mjs} +6 -6
  79. package/dist/slack/socket-runner.d.ts +14 -0
  80. package/dist/slack/socket-runner.d.ts.map +1 -1
  81. package/dist/test-runner/core/flow-stage.d.ts.map +1 -1
  82. package/dist/test-runner/fixture-loader.d.ts +1 -1
  83. package/dist/test-runner/fixture-loader.d.ts.map +1 -1
  84. package/dist/test-runner/index.d.ts.map +1 -1
  85. package/dist/test-runner/validator.d.ts.map +1 -1
  86. package/dist/traces/{run-2026-03-03T07-19-07-543Z.ndjson → run-2026-03-03T20-21-24-501Z.ndjson} +84 -84
  87. package/dist/{output/traces/run-2026-03-03T07-19-50-933Z.ndjson → traces/run-2026-03-03T20-22-08-701Z.ndjson} +1806 -1730
  88. package/dist/types/config.d.ts +38 -1
  89. package/dist/types/config.d.ts.map +1 -1
  90. package/dist/utils/workspace-manager.d.ts +4 -0
  91. package/dist/utils/workspace-manager.d.ts.map +1 -1
  92. package/dist/utils/worktree-manager.d.ts +15 -1
  93. package/dist/utils/worktree-manager.d.ts.map +1 -1
  94. package/package.json +2 -2
  95. package/dist/sdk/chunk-YYZAN5NK.mjs.map +0 -1
  96. package/dist/sdk/git-repository-analyzer-QFMW6WIS.mjs.map +0 -1
  97. /package/dist/sdk/{check-provider-registry-IYSUDKPB.mjs.map → check-provider-registry-6D5CAX44.mjs.map} +0 -0
  98. /package/dist/sdk/{check-provider-registry-LVLC4EPF.mjs.map → check-provider-registry-RRYBG6AU.mjs.map} +0 -0
  99. /package/dist/sdk/{check-provider-registry-X4OZJWPK.mjs.map → check-provider-registry-YFC5KSJY.mjs.map} +0 -0
  100. /package/dist/sdk/{chunk-BR7DYA3S.mjs.map → chunk-FZEQ744M.mjs.map} +0 -0
  101. /package/dist/sdk/{chunk-CISJ6DJW.mjs.map → chunk-GIAN7HCT.mjs.map} +0 -0
  102. /package/dist/sdk/{chunk-Q6EPAJ6Z.mjs.map → chunk-GLROSEYJ.mjs.map} +0 -0
  103. /package/dist/sdk/{chunk-RJLJUTSU.mjs.map → chunk-SWO4W57C.mjs.map} +0 -0
  104. /package/dist/sdk/{config-KQH254CA.mjs.map → config-MTEIGCOQ.mjs.map} +0 -0
  105. /package/dist/sdk/{failure-condition-evaluator-IVCTD4BZ.mjs.map → failure-condition-evaluator-P6QUFLIN.mjs.map} +0 -0
  106. /package/dist/sdk/{failure-condition-evaluator-LZ2AG5PY.mjs.map → failure-condition-evaluator-XV2ZMFFY.mjs.map} +0 -0
  107. /package/dist/sdk/{github-frontend-DFT5G32K.mjs.map → github-frontend-A2R7D4N6.mjs.map} +0 -0
  108. /package/dist/sdk/{github-frontend-S523EEJB.mjs.map → github-frontend-GSB2P5PE.mjs.map} +0 -0
  109. /package/dist/sdk/{host-7YKRMOUJ.mjs.map → host-CLPM2WVQ.mjs.map} +0 -0
  110. /package/dist/sdk/{host-H7IX4GBK.mjs.map → host-MR7L57QI.mjs.map} +0 -0
  111. /package/dist/sdk/{routing-LU5PAREW.mjs.map → routing-KLVK2MJZ.mjs.map} +0 -0
  112. /package/dist/sdk/{routing-ZMBKWMVI.mjs.map → routing-V3MYZAOH.mjs.map} +0 -0
  113. /package/dist/sdk/{schedule-tool-CDVUSZEG.mjs.map → schedule-tool-HYM55K3H.mjs.map} +0 -0
  114. /package/dist/sdk/{schedule-tool-EOMZFICZ.mjs.map → schedule-tool-NYLNJUEW.mjs.map} +0 -0
  115. /package/dist/sdk/{schedule-tool-NX75VKGA.mjs.map → schedule-tool-PRXFAV4K.mjs.map} +0 -0
  116. /package/dist/sdk/{schedule-tool-handler-3FJHDIPG.mjs.map → schedule-tool-handler-EFQIYD3W.mjs.map} +0 -0
  117. /package/dist/sdk/{schedule-tool-handler-KKN7XJYT.mjs.map → schedule-tool-handler-HVWCEGQ6.mjs.map} +0 -0
  118. /package/dist/sdk/{schedule-tool-handler-QNZG55DX.mjs.map → schedule-tool-handler-M5YI573R.mjs.map} +0 -0
  119. /package/dist/sdk/{trace-helpers-6ROJR7N3.mjs.map → trace-helpers-6NSZBC35.mjs.map} +0 -0
  120. /package/dist/sdk/{trace-helpers-EJUIOP6L.mjs.map → trace-helpers-TORF3JD5.mjs.map} +0 -0
  121. /package/dist/sdk/{workflow-check-provider-6ERNNCNA.mjs.map → workflow-check-provider-3F6CBHVD.mjs.map} +0 -0
  122. /package/dist/sdk/{workflow-check-provider-AGZ5JY2I.mjs.map → workflow-check-provider-OXHMLICJ.mjs.map} +0 -0
  123. /package/dist/sdk/{workflow-check-provider-PTNUWM5W.mjs.map → workflow-check-provider-XLH7N4FV.mjs.map} +0 -0
@@ -0,0 +1,805 @@
1
+ # Assistant Workflows
2
+
3
+ Three composable workflows for building AI-powered assistants, bundled with Visor:
4
+
5
+ | Workflow | Purpose |
6
+ |----------|---------|
7
+ | [**assistant**](#assistant) | Full AI assistant with skills, tools, knowledge, and bash commands |
8
+ | [**code-talk**](#code-talk) | Multi-project code exploration with references and confidence scoring |
9
+ | [**intent-router**](#intent-router) | Intent classification and skill/tag selection |
10
+
11
+ Import them using the `visor://` protocol:
12
+
13
+ ```yaml
14
+ imports:
15
+ - visor://assistant.yaml
16
+ ```
17
+
18
+ ## Quick Start
19
+
20
+ ```yaml
21
+ version: "1.0"
22
+
23
+ imports:
24
+ - visor://assistant.yaml
25
+
26
+ checks:
27
+ ask:
28
+ type: human-input
29
+ prompt: "How can I help?"
30
+
31
+ chat:
32
+ type: workflow
33
+ depends_on: [ask]
34
+ workflow: assistant
35
+ args:
36
+ question: "{{ outputs['ask'].text }}"
37
+ system_prompt: "You are a helpful engineering assistant."
38
+ intents:
39
+ - id: chat
40
+ description: general Q&A or small talk
41
+ - id: code_help
42
+ description: questions about code or architecture
43
+ default_skills: [code-explorer]
44
+ skills:
45
+ - id: code-explorer
46
+ description: needs codebase exploration or code search
47
+ tools:
48
+ code-talk:
49
+ workflow: code-talk
50
+ inputs:
51
+ projects:
52
+ - id: backend
53
+ repo: my-org/backend
54
+ description: Backend API service
55
+ allowed_commands: ['git:log:*', 'git:diff:*']
56
+ on_success:
57
+ goto: ask
58
+ ```
59
+
60
+ Run it:
61
+ ```bash
62
+ visor run config.yaml --tui
63
+ # or
64
+ visor run config.yaml --message "How does authentication work?"
65
+ ```
66
+
67
+ ---
68
+
69
+ ## assistant
70
+
71
+ High-level AI assistant workflow. Combines intent routing, dynamic skill activation, tool orchestration, knowledge injection, and bash command control into a single declarative configuration.
72
+
73
+ ### How It Works
74
+
75
+ ```
76
+ User message
77
+ |
78
+ v
79
+ [1. route-intent] -- classify intent + select skills
80
+ |
81
+ v
82
+ [2. build-config] -- add intent default skills, expand dependencies, collect tools/knowledge/bash
83
+ |
84
+ v
85
+ [3. generate-response] -- AI generates response with dynamic tools + knowledge
86
+ |
87
+ v
88
+ Output: { text, intent, tags, topic }
89
+ ```
90
+
91
+ ### Inputs
92
+
93
+ | Parameter | Type | Required | Default | Description |
94
+ |-----------|------|----------|---------|-------------|
95
+ | `question` | string | yes | | The user's message |
96
+ | `intents` | array | yes | | Intent definitions for routing (`[{id, description, default_skills?}]`) |
97
+ | `skills` | array | no | `[]` | Skill definitions (recommended over tags) |
98
+ | `tags` | array | no | `[]` | Tag definitions (legacy, use skills instead) |
99
+ | `knowledge` | array | no | `[]` | Standalone knowledge blocks (legacy) |
100
+ | `mcp_servers` | array | no | `[]` | Standalone MCP servers (legacy) |
101
+ | `system_prompt` | string | no | `"You are a helpful AI assistant..."` | System prompt for the AI |
102
+ | `guidelines` | string | no | `""` | Additional guidelines appended to the prompt |
103
+ | `routing_instructions` | string | no | `""` | Extra instructions for the intent classifier |
104
+ | `history` | array | no | `[]` | Conversation history (`[{role, text}]`) |
105
+ | `max_iterations` | number | no | `30` | Maximum AI tool-use iterations |
106
+
107
+ ### Outputs
108
+
109
+ | Field | Type | Description |
110
+ |-------|------|-------------|
111
+ | `text` | string | The AI's response |
112
+ | `intent` | string | Classified intent ID |
113
+ | `tags` | array | Classified tag/skill IDs |
114
+ | `topic` | string | Rewritten question (1-2 sentences) |
115
+
116
+ ### Skills
117
+
118
+ Skills are the core building block. Each skill bundles a description (for classification), knowledge (for context), tools (for capabilities), and bash permissions (for command access) into a single unit.
119
+
120
+ ```yaml
121
+ skills:
122
+ - id: code-explorer
123
+ description: needs codebase exploration or implementation details
124
+ knowledge: |
125
+ You can explore code across multiple repositories.
126
+ Always cite file paths and line numbers.
127
+ tools:
128
+ code-talk:
129
+ workflow: code-talk
130
+ inputs:
131
+ projects:
132
+ - id: backend
133
+ repo: my-org/backend
134
+ description: Backend API
135
+ allowed_commands: ['git:log:*', 'git:show:*', 'git:diff:*']
136
+
137
+ - id: engineer
138
+ description: user wants code changes, a PR, or a feature implemented
139
+ requires: [code-explorer] # auto-activates code-explorer
140
+ tools:
141
+ engineer:
142
+ workflow: engineer
143
+ inputs: {}
144
+ allowed_commands: ['git:*', 'npm:*']
145
+ disallowed_commands: ['git:push:--force', 'git:reset:--hard']
146
+ ```
147
+
148
+ #### Skill Fields
149
+
150
+ | Field | Type | Required | Description |
151
+ |-------|------|----------|-------------|
152
+ | `id` | string | yes | Unique identifier (used for classification and `requires`) |
153
+ | `description` | string | yes | When this skill should activate (the classifier reads this) |
154
+ | `knowledge` | string | no | Context injected into the AI prompt when active |
155
+ | `tools` | object | no | Tools available when active (see [Tool Types](#tool-types)) |
156
+ | `requires` | array | no | Other skill IDs to auto-activate alongside this one |
157
+ | `allowed_commands` | array | no | Bash patterns this skill can run (e.g. `['git:log:*']`) |
158
+ | `disallowed_commands` | array | no | Bash patterns this skill must not run (e.g. `['git:push:--force']`) |
159
+
160
+ #### Skill Activation
161
+
162
+ 1. The user sends a message
163
+ 2. The intent-router classifies the intent and selects relevant skills based on their `description` fields
164
+ 3. `default_skills` from the selected intent are always added
165
+ 4. `requires` dependencies are expanded recursively (cycles handled, diamonds deduplicated)
166
+ 5. For each active skill:
167
+ - Knowledge is injected into the AI prompt (wrapped in `<skill>` XML blocks)
168
+ - Tools are added to the AI's available MCP servers
169
+ - Bash allow/deny patterns are collected and applied
170
+
171
+ #### Tool Types
172
+
173
+ Skills support three types of tools:
174
+
175
+ **Workflow tools** - call another Visor workflow:
176
+ ```yaml
177
+ tools:
178
+ code-talk:
179
+ workflow: code-talk
180
+ inputs:
181
+ projects:
182
+ - id: backend
183
+ repo: my-org/backend
184
+ ```
185
+
186
+ **MCP command tools** - run an external MCP server process:
187
+ ```yaml
188
+ tools:
189
+ atlassian:
190
+ command: uvx
191
+ args: [mcp-atlassian]
192
+ env:
193
+ JIRA_URL: "${JIRA_URL}"
194
+ JIRA_API_TOKEN: "${JIRA_API_TOKEN}"
195
+ allowedMethods: [jira_get_issue, jira_search, jira_create_issue]
196
+ ```
197
+
198
+ **Built-in tools** - tools provided by the Visor runtime:
199
+ ```yaml
200
+ tools:
201
+ scheduler:
202
+ tool: schedule
203
+ ```
204
+
205
+ When multiple skills expose the same server name, their `allowedMethods` are merged (duplicates removed).
206
+
207
+ #### Bash Command Patterns
208
+
209
+ Patterns use colon-separated segments with glob support:
210
+
211
+ | Pattern | Matches |
212
+ |---------|---------|
213
+ | `git:log:*` | `git log`, `git log --oneline`, etc. |
214
+ | `git:*` | Any git command |
215
+ | `npm:test` | Only `npm test` |
216
+ | `docker:*` | Any docker command |
217
+ | `git:push:--force` | Specifically `git push --force` (for deny) |
218
+
219
+ When skills are activated, all their `allowed_commands` are collected into a single allow list and all `disallowed_commands` into a deny list. Deny takes precedence over allow.
220
+
221
+ ### Intents
222
+
223
+ Intents are broad routing categories. Keep them general (3-6 intents is typical):
224
+
225
+ ```yaml
226
+ intents:
227
+ - id: chat
228
+ description: general Q&A, follow-up questions, small talk
229
+ - id: code_help
230
+ description: questions about code, implementation, or architecture
231
+ default_skills: [code-explorer]
232
+ - id: task
233
+ description: create, update, or execute something
234
+ ```
235
+
236
+ `default_skills` ensures specific skills are always active for that intent, even if the classifier returns no skills.
237
+
238
+ ### Knowledge Injection
239
+
240
+ There are two ways to inject knowledge:
241
+
242
+ **Via skills (recommended):**
243
+ ```yaml
244
+ skills:
245
+ - id: onboarding
246
+ description: questions about onboarding, setup, or getting started
247
+ knowledge: |
248
+ ## Onboarding Guide
249
+ 1. Clone the repo: git clone ...
250
+ 2. Install deps: npm install
251
+ 3. Run tests: npm test
252
+ ```
253
+
254
+ Knowledge can be loaded from files using `{% readfile %}`:
255
+ ```yaml
256
+ skills:
257
+ - id: architecture
258
+ description: questions about system architecture or design
259
+ knowledge: |
260
+ {% readfile "docs/architecture.md" %}
261
+ ```
262
+
263
+ **Via standalone knowledge blocks (legacy):**
264
+ ```yaml
265
+ knowledge:
266
+ - tags: [onboarding]
267
+ content: |
268
+ ## Onboarding Guide
269
+ ...
270
+ - intent: code_help
271
+ content: |
272
+ ## Code Guidelines
273
+ ...
274
+ ```
275
+
276
+ ### Standalone MCP Servers (Legacy)
277
+
278
+ For tag/intent-conditional MCP servers without skills:
279
+
280
+ ```yaml
281
+ mcp_servers:
282
+ - tags: [jira]
283
+ name: atlassian
284
+ server:
285
+ command: uvx
286
+ args: [mcp-atlassian]
287
+ env:
288
+ JIRA_URL: "${JIRA_URL}"
289
+ - tags: [confluence]
290
+ name: atlassian-confluence
291
+ server:
292
+ command: uvx
293
+ args: [mcp-atlassian]
294
+ env:
295
+ CONFLUENCE_URL: "${CONFLUENCE_URL}"
296
+ ```
297
+
298
+ ### Explicit Markers
299
+
300
+ Users can override classification with markers in their message:
301
+
302
+ - **`#skill`** - force a skill to activate: `"Deploy the app #devops"`
303
+ - **`%intent`** - force an intent: `"What is this? %code_help"`
304
+
305
+ Markers are stripped from the rewritten topic.
306
+
307
+ ### Full Example
308
+
309
+ ```yaml
310
+ version: "1.0"
311
+
312
+ imports:
313
+ - visor://assistant.yaml
314
+
315
+ slack:
316
+ version: "v1"
317
+ mentions: all
318
+ threads: required
319
+
320
+ checks:
321
+ chat:
322
+ type: workflow
323
+ workflow: assistant
324
+ assume: ["true"]
325
+ args:
326
+ question: "{{ conversation.current.text }}"
327
+
328
+ system_prompt: |
329
+ You are an engineering assistant for Acme Corp.
330
+ You can explore code, manage Jira tickets, and help with deployments.
331
+
332
+ intents:
333
+ - id: chat
334
+ description: general Q&A, follow-up questions, small talk
335
+ - id: code_help
336
+ description: questions about code, architecture, or implementation
337
+ default_skills: [code-explorer]
338
+ - id: task
339
+ description: create, update, or execute something
340
+
341
+ skills:
342
+ - id: capabilities
343
+ description: user asks what this assistant can do
344
+ knowledge: |
345
+ I can explore code across repos, search Jira tickets,
346
+ and help with code changes via PRs.
347
+
348
+ - id: code-explorer
349
+ description: needs codebase exploration or code search
350
+ tools:
351
+ code-talk:
352
+ workflow: code-talk
353
+ inputs:
354
+ projects:
355
+ - id: backend
356
+ repo: acme/backend
357
+ description: Go backend API
358
+ - id: frontend
359
+ repo: acme/frontend
360
+ description: React frontend
361
+ allowed_commands: ['git:log:*', 'git:show:*', 'git:diff:*']
362
+
363
+ - id: engineer
364
+ description: user wants code changes, a PR, or a feature
365
+ requires: [code-explorer]
366
+ tools:
367
+ engineer:
368
+ workflow: engineer
369
+ inputs: {}
370
+ allowed_commands: ['git:*', 'npm:*']
371
+ disallowed_commands: ['git:push:--force', 'git:reset:--hard']
372
+
373
+ - id: jira
374
+ description: mentions Jira, ticket IDs like PROJ-123, or needs ticket info
375
+ tools:
376
+ atlassian:
377
+ command: uvx
378
+ args: [mcp-atlassian]
379
+ env:
380
+ JIRA_URL: "${JIRA_URL}"
381
+ JIRA_API_TOKEN: "${JIRA_API_TOKEN}"
382
+ allowedMethods: [jira_get_issue, jira_search, jira_create_issue]
383
+ on_success:
384
+ goto: chat
385
+ ```
386
+
387
+ ---
388
+
389
+ ## code-talk
390
+
391
+ AI-powered code exploration workflow. Routes questions to relevant repositories, checks out code, explores it with specialized tools (search, extract, delegate), and returns answers with file references and confidence scoring.
392
+
393
+ ### How It Works
394
+
395
+ ```
396
+ Question + project list
397
+ |
398
+ v
399
+ [1. checkout-docs] -- shallow-clone documentation repo
400
+ |
401
+ v
402
+ [2. route-projects] -- AI selects which projects to explore
403
+ |
404
+ v
405
+ [3. checkout-projects] -- shallow-clone selected repos (parallel)
406
+ |
407
+ v
408
+ [4. explore-code] -- AI explores code with tools + bash
409
+ |
410
+ v
411
+ Output: { answer, references, confidence, projects_explored }
412
+ ```
413
+
414
+ ### Inputs
415
+
416
+ | Parameter | Type | Required | Default | Description |
417
+ |-----------|------|----------|---------|-------------|
418
+ | `question` | string | yes | | The code question to answer |
419
+ | `architecture` | string | yes | | Architecture description (file path or inline markdown) |
420
+ | `docs_repo` | string | yes | | Documentation repo (`owner/name`) |
421
+ | `projects` | array | yes | | Available projects (`[{id, repo, description}]`) |
422
+ | `docs_ref` | string | no | `"main"` | Git ref for the docs repository |
423
+ | `max_projects` | number | no | `3` | Maximum code repos to checkout (excludes docs) |
424
+ | `routing_prompt` | string | no | `""` | Additional instructions for project routing |
425
+ | `exploration_prompt` | string | no | `""` | Additional instructions for code exploration |
426
+ | `ai_model` | string | no | | Override AI model for exploration |
427
+
428
+ ### Outputs
429
+
430
+ | Field | Type | Description |
431
+ |-------|------|-------------|
432
+ | `answer` | object | `{text: string, summary?: string}` - the answer with references |
433
+ | `references` | array | Code references with file, lines, URL, snippet |
434
+ | `confidence` | string | `"high"`, `"medium"`, or `"low"` |
435
+ | `confidence_reason` | string | Why confidence is not high (empty when high) |
436
+ | `projects_explored` | array | List of explored project IDs |
437
+ | `projects_explored_details` | array | `[{id, repo, description, reason}]` |
438
+
439
+ #### Reference Format
440
+
441
+ Each reference in the `references` array:
442
+
443
+ ```json
444
+ {
445
+ "project": "backend",
446
+ "file": "src/auth/jwt.go",
447
+ "lines": [42, 50],
448
+ "url": "https://github.com/org/repo/blob/main/src/auth/jwt.go#L42-L50",
449
+ "snippet": "JWT validation middleware"
450
+ }
451
+ ```
452
+
453
+ The `answer.text` always ends with a `## References` section containing clickable links.
454
+
455
+ #### Confidence Scoring
456
+
457
+ | Level | Meaning |
458
+ |-------|---------|
459
+ | `high` | Claims directly backed by code/documentation evidence |
460
+ | `medium` | Some evidence found but investigation has gaps |
461
+ | `low` | Insufficient evidence or significant ambiguity |
462
+
463
+ `confidence_reason` explains what's missing when confidence is not high.
464
+
465
+ ### Exploration Capabilities
466
+
467
+ The AI has access to:
468
+
469
+ - **Code tools**: search, extract, query, listFiles, searchFiles
470
+ - **Delegate tool**: spawn sub-agents for deep investigation of specific components
471
+ - **Git commands**: `log`, `diff`, `show`, `blame`, `checkout`, `branch`, `tag`, `fetch`, `status`, `ls-files`
472
+ - **GitHub CLI**: `gh pr view`, `gh pr diff`, `gh pr checks`, `gh issue view`, `gh run view --log`, `gh api`
473
+ - **File tools**: `ls`, `find`, `cat`, `head`, `tail`, `wc`, `grep`
474
+
475
+ Shallow clones are handled automatically - the AI fetches specific branches/tags as needed.
476
+
477
+ ### Usage
478
+
479
+ #### As a Standalone Workflow
480
+
481
+ ```yaml
482
+ imports:
483
+ - visor://code-talk.yaml
484
+
485
+ checks:
486
+ explore:
487
+ type: workflow
488
+ workflow: code-talk
489
+ args:
490
+ question: "How does the rate limiter work?"
491
+ architecture: |
492
+ # Architecture
493
+ ## Projects
494
+ | ID | Description |
495
+ |----|-------------|
496
+ | gateway | API gateway with rate limiting |
497
+ | backend | Core business logic |
498
+ docs_repo: my-org/docs
499
+ projects:
500
+ - id: gateway
501
+ repo: my-org/gateway
502
+ description: API gateway with middleware, rate limiting, auth
503
+ - id: backend
504
+ repo: my-org/backend
505
+ description: Core business logic and data layer
506
+ max_projects: 2
507
+ ```
508
+
509
+ #### As a Skill Tool in Assistant
510
+
511
+ ```yaml
512
+ skills:
513
+ - id: code-explorer
514
+ description: needs codebase exploration or code search
515
+ tools:
516
+ code-talk:
517
+ workflow: code-talk
518
+ inputs:
519
+ architecture: |
520
+ # Project Architecture
521
+ ...
522
+ docs_repo: my-org/docs
523
+ projects:
524
+ - id: backend
525
+ repo: my-org/backend
526
+ description: Backend API
527
+ ```
528
+
529
+ #### As an AI Custom Tool
530
+
531
+ ```yaml
532
+ checks:
533
+ assistant:
534
+ type: ai
535
+ prompt: "Help the user with technical questions."
536
+ ai_custom_tools:
537
+ - workflow: code-talk
538
+ args:
539
+ architecture: "# Architecture description"
540
+ projects:
541
+ - id: my-project
542
+ repo: my-org/my-repo
543
+ description: Main codebase
544
+ max_projects: 1
545
+ ```
546
+
547
+ See `examples/code-talk-workflow.yaml` and `examples/code-talk-as-tool.yaml`.
548
+
549
+ ---
550
+
551
+ ## intent-router
552
+
553
+ Lightweight intent classification workflow. Classifies the user's intent, rewrites the request as a short question, and selects relevant skills or tags. Used internally by the assistant workflow, but can also be used standalone for custom routing.
554
+
555
+ ### How It Works
556
+
557
+ ```
558
+ User message + intent/skill catalog
559
+ |
560
+ v
561
+ [1. classify] -- AI picks intent, rewrites question, selects skills
562
+ |
563
+ v
564
+ Output: { intent, topic, skills/tags }
565
+ ```
566
+
567
+ ### Inputs
568
+
569
+ | Parameter | Type | Required | Default | Description |
570
+ |-----------|------|----------|---------|-------------|
571
+ | `question` | string | yes | | The user's message to classify |
572
+ | `intents` | array | yes | | Intent definitions (`[{id, description}]`) |
573
+ | `skills` | array | no | `[]` | Skill definitions (`[{id, description, requires?}]`) |
574
+ | `tags` | array | no | `[]` | Tag definitions (`[{id, description}]`) - legacy |
575
+ | `routing_instructions` | string | no | `""` | Additional routing rules |
576
+
577
+ When both `skills` and `tags` are provided, `skills` takes precedence.
578
+
579
+ ### Outputs
580
+
581
+ | Field | Type | Description |
582
+ |-------|------|-------------|
583
+ | `intent` | string | Selected intent ID |
584
+ | `topic` | string | Short rewritten question (ends with `?`) |
585
+ | `skills` | array | Selected skill IDs (when using skills mode) |
586
+ | `tags` | array | Selected tag IDs (when using tags mode) |
587
+ | `raw` | object | Full classifier output |
588
+ | `error` | string\|null | Error if explicit `%intent` marker was invalid |
589
+
590
+ ### Skills vs Tags
591
+
592
+ **Skills (recommended)** support a `requires` array for dependency chains. When a skill is selected, the assistant workflow automatically expands its dependencies.
593
+
594
+ ```yaml
595
+ skills:
596
+ - id: engineer
597
+ description: user wants code changes or a PR
598
+ requires: [code-explorer] # auto-activates code-explorer too
599
+ - id: code-explorer
600
+ description: needs codebase exploration
601
+ ```
602
+
603
+ **Tags (legacy)** are flat identifiers with no dependency support:
604
+
605
+ ```yaml
606
+ tags:
607
+ - id: codebase
608
+ description: needs code context
609
+ - id: jira
610
+ description: needs Jira access
611
+ ```
612
+
613
+ ### Explicit Markers
614
+
615
+ Users can force classification with markers in their message:
616
+
617
+ | Marker | Effect | Example |
618
+ |--------|--------|---------|
619
+ | `#skill_id` | Forces that skill to be selected | `"Deploy it #devops"` |
620
+ | `%intent_id` | Forces that intent to be used | `"Help me %code_help"` |
621
+
622
+ Markers are stripped from the topic output. Invalid `%intent` markers produce an error in the `error` output field.
623
+
624
+ ### Conversation Context
625
+
626
+ The router respects Slack/GitHub thread context:
627
+ - Short follow-ups ("ok", "do it", "yes") are understood as continuations
628
+ - Pronoun references ("it", "this", "that") are connected to recent context
629
+ - The topic is reconstructed with full context from the thread
630
+
631
+ ### Usage
632
+
633
+ #### Standalone Routing
634
+
635
+ ```yaml
636
+ imports:
637
+ - visor://intent-router.yaml
638
+
639
+ checks:
640
+ route:
641
+ type: workflow
642
+ workflow: intent-router
643
+ args:
644
+ question: "{{ outputs['ask'].text }}"
645
+ intents:
646
+ - id: chat
647
+ description: general Q&A or small talk
648
+ - id: code_help
649
+ description: questions about code, debugging, or architecture
650
+ - id: task
651
+ description: create, update, or execute something
652
+ skills:
653
+ - id: jira
654
+ description: request references Jira tickets or needs Jira data
655
+ - id: code-explorer
656
+ description: needs codebase exploration or implementation details
657
+
658
+ # Route to different handlers based on intent
659
+ handle-chat:
660
+ type: ai
661
+ depends_on: [route]
662
+ if: "outputs.route.intent === 'chat'"
663
+ prompt: "Answer: {{ outputs.route.topic }}"
664
+
665
+ handle-code:
666
+ type: workflow
667
+ depends_on: [route]
668
+ if: "outputs.route.intent === 'code_help'"
669
+ workflow: code-talk
670
+ args:
671
+ question: "{{ outputs.route.topic }}"
672
+ ...
673
+ ```
674
+
675
+ See `examples/intent-router-workflow.yaml`.
676
+
677
+ ---
678
+
679
+ ## Composition Patterns
680
+
681
+ ### Pattern 1: Assistant with Multiple Skills
682
+
683
+ The most common pattern. The assistant workflow handles routing, skill activation, and response generation internally:
684
+
685
+ ```yaml
686
+ workflow: assistant
687
+ args:
688
+ question: "{{ message }}"
689
+ intents:
690
+ - id: chat
691
+ description: general Q&A
692
+ - id: code_help
693
+ description: code questions
694
+ default_skills: [code-explorer]
695
+ - id: task
696
+ description: create or execute something
697
+ skills:
698
+ - id: code-explorer
699
+ description: needs code exploration
700
+ tools:
701
+ code-talk:
702
+ workflow: code-talk
703
+ inputs: { projects: [...] }
704
+ allowed_commands: ['git:log:*', 'git:diff:*']
705
+
706
+ - id: jira
707
+ description: needs Jira access
708
+ tools:
709
+ atlassian:
710
+ command: uvx
711
+ args: [mcp-atlassian]
712
+ env: { JIRA_URL: "${JIRA_URL}" }
713
+
714
+ - id: engineer
715
+ description: wants code changes
716
+ requires: [code-explorer]
717
+ tools:
718
+ engineer:
719
+ workflow: engineer
720
+ inputs: {}
721
+ allowed_commands: ['git:*', 'npm:*']
722
+ disallowed_commands: ['git:push:--force']
723
+ ```
724
+
725
+ ### Pattern 2: Custom Routing with intent-router
726
+
727
+ Use intent-router directly when you need custom post-routing logic:
728
+
729
+ ```yaml
730
+ checks:
731
+ route:
732
+ type: workflow
733
+ workflow: intent-router
734
+ args:
735
+ question: "{{ message }}"
736
+ intents:
737
+ - id: summarize
738
+ description: summarize a thread
739
+ - id: code_help
740
+ description: code questions
741
+ skills:
742
+ - id: jira
743
+ description: needs Jira
744
+ - id: codebase
745
+ description: needs code context
746
+
747
+ # Different workflows per intent
748
+ summarize:
749
+ depends_on: [route]
750
+ if: "outputs.route.intent === 'summarize'"
751
+ type: ai
752
+ prompt: "Summarize the thread."
753
+
754
+ explore:
755
+ depends_on: [route]
756
+ if: "outputs.route.intent === 'code_help'"
757
+ type: workflow
758
+ workflow: code-talk
759
+ args:
760
+ question: "{{ outputs.route.topic }}"
761
+ ...
762
+ ```
763
+
764
+ ### Pattern 3: Code Exploration as an On-Demand Tool
765
+
766
+ Let the AI decide when to explore code:
767
+
768
+ ```yaml
769
+ checks:
770
+ assistant:
771
+ type: ai
772
+ prompt: "Help the user with their question: {{ message }}"
773
+ ai_custom_tools:
774
+ - workflow: code-talk
775
+ args:
776
+ projects:
777
+ - id: backend
778
+ repo: my-org/backend
779
+ description: Backend API
780
+ ```
781
+
782
+ The AI calls the code-talk tool only when it needs code context, rather than exploring on every message.
783
+
784
+ ---
785
+
786
+ ## Deployment Modes
787
+
788
+ All workflows support:
789
+
790
+ | Mode | Command |
791
+ |------|---------|
792
+ | **CLI (single message)** | `visor run config.yaml --message "Hello"` |
793
+ | **CLI (interactive TUI)** | `visor run config.yaml --tui` |
794
+ | **Slack bot** | `visor run config.yaml --slack` |
795
+ | **GitHub Action** | Use `@probelabs/visor-action` |
796
+
797
+ ---
798
+
799
+ ## Examples
800
+
801
+ | File | Description |
802
+ |------|-------------|
803
+ | `examples/code-talk-workflow.yaml` | Standalone code exploration |
804
+ | `examples/code-talk-as-tool.yaml` | Code exploration as an AI tool |
805
+ | `examples/intent-router-workflow.yaml` | Intent routing with conditional handlers |