@probelabs/visor 0.1.179-ee → 0.1.180-ee

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 (175) hide show
  1. package/README.md +6 -4
  2. package/defaults/assistant.yaml +29 -1
  3. package/defaults/code-talk.yaml +331 -441
  4. package/defaults/engineer.yaml +608 -0
  5. package/defaults/project-setup.yaml +489 -0
  6. package/defaults/skills/engineer.yaml +41 -0
  7. package/dist/{560.index.js → 736.index.js} +359 -3132
  8. package/dist/agent-protocol/task-store.d.ts +3 -0
  9. package/dist/agent-protocol/task-store.d.ts.map +1 -1
  10. package/dist/agent-protocol/track-execution.d.ts.map +1 -1
  11. package/dist/ai-review-service.d.ts +6 -0
  12. package/dist/ai-review-service.d.ts.map +1 -1
  13. package/dist/cli-main.d.ts.map +1 -1
  14. package/dist/cli.d.ts +5 -0
  15. package/dist/cli.d.ts.map +1 -1
  16. package/dist/config.d.ts.map +1 -1
  17. package/dist/defaults/assistant.yaml +29 -1
  18. package/dist/defaults/code-talk.yaml +331 -441
  19. package/dist/defaults/engineer.yaml +608 -0
  20. package/dist/defaults/project-setup.yaml +489 -0
  21. package/dist/defaults/skills/engineer.yaml +41 -0
  22. package/dist/docs/advanced-ai.md +39 -0
  23. package/dist/docs/ai-configuration.md +32 -0
  24. package/dist/docs/ai-custom-tools.md +25 -0
  25. package/dist/docs/architecture.md +3 -0
  26. package/dist/docs/assistant-workflows.md +395 -25
  27. package/dist/docs/configuration.md +2 -1
  28. package/dist/docs/glossary.md +27 -1
  29. package/dist/docs/guides/build-ai-agent.md +4 -0
  30. package/dist/docs/mcp.md +26 -0
  31. package/dist/docs/migration.md +2 -0
  32. package/dist/docs/pluggable.md +28 -1
  33. package/dist/docs/telemetry-reference.md +41 -0
  34. package/dist/docs/timeouts.md +86 -1
  35. package/dist/docs/utcp-provider.md +343 -0
  36. package/dist/docs/workflows.md +30 -0
  37. package/dist/examples/negotiated-timeout.yaml +65 -0
  38. package/dist/examples/screenshot-tool.yaml +100 -0
  39. package/dist/examples/utcp-provider-example.yaml +290 -0
  40. package/dist/examples/workflows/helper-workflow.yaml +15 -0
  41. package/dist/frontends/slack-frontend.d.ts.map +1 -1
  42. package/dist/generated/config-schema.d.ts +75 -8
  43. package/dist/generated/config-schema.d.ts.map +1 -1
  44. package/dist/generated/config-schema.json +86 -8
  45. package/dist/index.js +42497 -33912
  46. package/dist/providers/ai-check-provider.d.ts.map +1 -1
  47. package/dist/providers/check-provider-registry.d.ts.map +1 -1
  48. package/dist/providers/check-provider.interface.d.ts +6 -0
  49. package/dist/providers/check-provider.interface.d.ts.map +1 -1
  50. package/dist/providers/http-client-provider.d.ts.map +1 -1
  51. package/dist/providers/index.d.ts +1 -0
  52. package/dist/providers/index.d.ts.map +1 -1
  53. package/dist/providers/mcp-check-provider.d.ts +0 -8
  54. package/dist/providers/mcp-check-provider.d.ts.map +1 -1
  55. package/dist/providers/mcp-custom-sse-server.d.ts +5 -0
  56. package/dist/providers/mcp-custom-sse-server.d.ts.map +1 -1
  57. package/dist/providers/utcp-check-provider.d.ts +81 -0
  58. package/dist/providers/utcp-check-provider.d.ts.map +1 -0
  59. package/dist/providers/workflow-check-provider.d.ts.map +1 -1
  60. package/dist/sandbox/check-runner.d.ts +1 -1
  61. package/dist/sandbox/check-runner.d.ts.map +1 -1
  62. package/dist/sandbox/compose-generator.d.ts +45 -0
  63. package/dist/sandbox/compose-generator.d.ts.map +1 -0
  64. package/dist/sandbox/index.d.ts +2 -1
  65. package/dist/sandbox/index.d.ts.map +1 -1
  66. package/dist/sandbox/sandbox-manager.d.ts +21 -1
  67. package/dist/sandbox/sandbox-manager.d.ts.map +1 -1
  68. package/dist/sandbox/types.d.ts +40 -0
  69. package/dist/sandbox/types.d.ts.map +1 -1
  70. package/dist/sdk/{a2a-frontend-KJFLIZJT.mjs → a2a-frontend-6FNPD53G.mjs} +20 -2
  71. package/dist/sdk/a2a-frontend-6FNPD53G.mjs.map +1 -0
  72. package/dist/sdk/{check-provider-registry-SYAHJMWJ.mjs → check-provider-registry-T4HIUBMT.mjs} +8 -7
  73. package/dist/sdk/{check-provider-registry-J27YX4IT.mjs → check-provider-registry-Z4MVXFLJ.mjs} +9 -8
  74. package/dist/sdk/{chunk-ZJYQMNPA.mjs → chunk-3ZKBUWDB.mjs} +3 -3
  75. package/dist/sdk/{chunk-OYHDBTKY.mjs → chunk-5DQY4LTK.mjs} +2 -2
  76. package/dist/sdk/chunk-ANCIFGQH.mjs +825 -0
  77. package/dist/sdk/chunk-ANCIFGQH.mjs.map +1 -0
  78. package/dist/sdk/chunk-F25U4YWJ.mjs +825 -0
  79. package/dist/sdk/chunk-F25U4YWJ.mjs.map +1 -0
  80. package/dist/sdk/{chunk-UBTZE3FO.mjs → chunk-J27D43HS.mjs} +51 -8
  81. package/dist/sdk/chunk-J27D43HS.mjs.map +1 -0
  82. package/dist/sdk/{chunk-BMXVAJ2M.mjs → chunk-KAVOGMLR.mjs} +90 -15
  83. package/dist/sdk/chunk-KAVOGMLR.mjs.map +1 -0
  84. package/dist/sdk/{chunk-FTPLYUQ3.mjs → chunk-MWUQFSEK.mjs} +6981 -6461
  85. package/dist/sdk/chunk-MWUQFSEK.mjs.map +1 -0
  86. package/dist/sdk/{chunk-CHARL3TY.mjs → chunk-NBUN22ZG.mjs} +12 -2
  87. package/dist/sdk/chunk-NBUN22ZG.mjs.map +1 -0
  88. package/dist/sdk/{chunk-KWHLB5E3.mjs → chunk-STAAKOPU.mjs} +6516 -5996
  89. package/dist/sdk/chunk-STAAKOPU.mjs.map +1 -0
  90. package/dist/sdk/{config-DFOF7LP4.mjs → config-ZZKC47SV.mjs} +2 -2
  91. package/dist/sdk/dist-X4HSBKSA.mjs +5716 -0
  92. package/dist/sdk/dist-X4HSBKSA.mjs.map +1 -0
  93. package/dist/sdk/dist-XF2FTM6E.mjs +5716 -0
  94. package/dist/sdk/dist-XF2FTM6E.mjs.map +1 -0
  95. package/dist/sdk/{failure-condition-evaluator-V2YGFRKO.mjs → failure-condition-evaluator-WNCCIP6N.mjs} +3 -3
  96. package/dist/sdk/{github-frontend-4LM4NAZK.mjs → github-frontend-QVMVUL3Y.mjs} +3 -3
  97. package/dist/sdk/{host-GBXJKNHL.mjs → host-5TJBWGGH.mjs} +4 -4
  98. package/dist/sdk/{host-XXPPPC76.mjs → host-RVLIZMTE.mjs} +4 -4
  99. package/dist/sdk/{loader-Q7K76ZIY.mjs → loader-ZNKKJEZ3.mjs} +1 -1
  100. package/dist/sdk/{routing-YAYBIVPL.mjs → routing-5DHNS7IW.mjs} +4 -4
  101. package/dist/sdk/{schedule-tool-OIVJDIDK.mjs → schedule-tool-25CFKVOI.mjs} +8 -7
  102. package/dist/sdk/{schedule-tool-WACIV77L.mjs → schedule-tool-UGWYLGJK.mjs} +9 -8
  103. package/dist/sdk/{schedule-tool-handler-ODKY57FO.mjs → schedule-tool-handler-VWBX4JEF.mjs} +8 -7
  104. package/dist/sdk/{schedule-tool-handler-SJF4ZKSB.mjs → schedule-tool-handler-WK22RO3M.mjs} +9 -8
  105. package/dist/sdk/sdk.d.mts +42 -2
  106. package/dist/sdk/sdk.d.ts +42 -2
  107. package/dist/sdk/sdk.js +28250 -21090
  108. package/dist/sdk/sdk.js.map +1 -1
  109. package/dist/sdk/sdk.mjs +8 -7
  110. package/dist/sdk/sdk.mjs.map +1 -1
  111. package/dist/sdk/{slack-frontend-OWD7BSWF.mjs → slack-frontend-BPWXNIHE.mjs} +3 -3
  112. package/dist/sdk/slack-frontend-BPWXNIHE.mjs.map +1 -0
  113. package/dist/sdk/{trace-helpers-QL2B75AK.mjs → trace-helpers-GCLQ3YKO.mjs} +2 -2
  114. package/dist/sdk/{track-execution-2Q66SXBZ.mjs → track-execution-GCGJKMAO.mjs} +6 -4
  115. package/dist/sdk/track-execution-GCGJKMAO.mjs.map +1 -0
  116. package/dist/sdk/utcp-check-provider-6YTBN5WQ.mjs +16 -0
  117. package/dist/sdk/utcp-check-provider-HT2MA5SS.mjs +16 -0
  118. package/dist/sdk/{workflow-check-provider-IXW6BMQA.mjs → workflow-check-provider-I732XE7D.mjs} +8 -7
  119. package/dist/sdk/{workflow-check-provider-UZQZYPOE.mjs → workflow-check-provider-T4PFK2EG.mjs} +9 -8
  120. package/dist/sdk/workflow-check-provider-T4PFK2EG.mjs.map +1 -0
  121. package/dist/sdk/{workflow-registry-LRSRWUM5.mjs → workflow-registry-X2IPY35M.mjs} +2 -2
  122. package/dist/sdk/workflow-registry-X2IPY35M.mjs.map +1 -0
  123. package/dist/slack/adapter.d.ts +8 -0
  124. package/dist/slack/adapter.d.ts.map +1 -1
  125. package/dist/slack/client.d.ts +1 -0
  126. package/dist/slack/client.d.ts.map +1 -1
  127. package/dist/slack/socket-runner.d.ts +1 -0
  128. package/dist/slack/socket-runner.d.ts.map +1 -1
  129. package/dist/state-machine/dispatch/execution-invoker.d.ts.map +1 -1
  130. package/dist/state-machine/dispatch/sandbox-routing.d.ts +25 -1
  131. package/dist/state-machine/dispatch/sandbox-routing.d.ts.map +1 -1
  132. package/dist/state-machine-execution-engine.d.ts.map +1 -1
  133. package/dist/telemetry/opentelemetry.d.ts +6 -0
  134. package/dist/telemetry/opentelemetry.d.ts.map +1 -1
  135. package/dist/test-runner/core/flow-stage.d.ts +1 -2
  136. package/dist/test-runner/core/flow-stage.d.ts.map +1 -1
  137. package/dist/test-runner/index.d.ts +0 -3
  138. package/dist/test-runner/index.d.ts.map +1 -1
  139. package/dist/test-runner/validator.d.ts.map +1 -1
  140. package/dist/types/config.d.ts +36 -2
  141. package/dist/types/config.d.ts.map +1 -1
  142. package/dist/utils/issue-normalizer.d.ts +27 -0
  143. package/dist/utils/issue-normalizer.d.ts.map +1 -0
  144. package/dist/utils/worktree-manager.d.ts +9 -2
  145. package/dist/utils/worktree-manager.d.ts.map +1 -1
  146. package/dist/workflow-registry.d.ts +5 -0
  147. package/dist/workflow-registry.d.ts.map +1 -1
  148. package/package.json +12 -2
  149. package/dist/sdk/a2a-frontend-KJFLIZJT.mjs.map +0 -1
  150. package/dist/sdk/chunk-BMXVAJ2M.mjs.map +0 -1
  151. package/dist/sdk/chunk-CHARL3TY.mjs.map +0 -1
  152. package/dist/sdk/chunk-FTPLYUQ3.mjs.map +0 -1
  153. package/dist/sdk/chunk-KWHLB5E3.mjs.map +0 -1
  154. package/dist/sdk/chunk-UBTZE3FO.mjs.map +0 -1
  155. package/dist/sdk/slack-frontend-OWD7BSWF.mjs.map +0 -1
  156. package/dist/sdk/track-execution-2Q66SXBZ.mjs.map +0 -1
  157. /package/dist/sdk/{check-provider-registry-J27YX4IT.mjs.map → check-provider-registry-T4HIUBMT.mjs.map} +0 -0
  158. /package/dist/sdk/{check-provider-registry-SYAHJMWJ.mjs.map → check-provider-registry-Z4MVXFLJ.mjs.map} +0 -0
  159. /package/dist/sdk/{chunk-ZJYQMNPA.mjs.map → chunk-3ZKBUWDB.mjs.map} +0 -0
  160. /package/dist/sdk/{chunk-OYHDBTKY.mjs.map → chunk-5DQY4LTK.mjs.map} +0 -0
  161. /package/dist/sdk/{config-DFOF7LP4.mjs.map → config-ZZKC47SV.mjs.map} +0 -0
  162. /package/dist/sdk/{failure-condition-evaluator-V2YGFRKO.mjs.map → failure-condition-evaluator-WNCCIP6N.mjs.map} +0 -0
  163. /package/dist/sdk/{github-frontend-4LM4NAZK.mjs.map → github-frontend-QVMVUL3Y.mjs.map} +0 -0
  164. /package/dist/sdk/{host-GBXJKNHL.mjs.map → host-5TJBWGGH.mjs.map} +0 -0
  165. /package/dist/sdk/{host-XXPPPC76.mjs.map → host-RVLIZMTE.mjs.map} +0 -0
  166. /package/dist/sdk/{loader-Q7K76ZIY.mjs.map → loader-ZNKKJEZ3.mjs.map} +0 -0
  167. /package/dist/sdk/{routing-YAYBIVPL.mjs.map → routing-5DHNS7IW.mjs.map} +0 -0
  168. /package/dist/sdk/{schedule-tool-OIVJDIDK.mjs.map → schedule-tool-25CFKVOI.mjs.map} +0 -0
  169. /package/dist/sdk/{schedule-tool-WACIV77L.mjs.map → schedule-tool-UGWYLGJK.mjs.map} +0 -0
  170. /package/dist/sdk/{schedule-tool-handler-ODKY57FO.mjs.map → schedule-tool-handler-VWBX4JEF.mjs.map} +0 -0
  171. /package/dist/sdk/{schedule-tool-handler-SJF4ZKSB.mjs.map → schedule-tool-handler-WK22RO3M.mjs.map} +0 -0
  172. /package/dist/sdk/{trace-helpers-QL2B75AK.mjs.map → trace-helpers-GCLQ3YKO.mjs.map} +0 -0
  173. /package/dist/sdk/{workflow-check-provider-IXW6BMQA.mjs.map → utcp-check-provider-6YTBN5WQ.mjs.map} +0 -0
  174. /package/dist/sdk/{workflow-check-provider-UZQZYPOE.mjs.map → utcp-check-provider-HT2MA5SS.mjs.map} +0 -0
  175. /package/dist/sdk/{workflow-registry-LRSRWUM5.mjs.map → workflow-check-provider-I732XE7D.mjs.map} +0 -0
@@ -0,0 +1,608 @@
1
+ # =============================================================================
2
+ # engineer: Built-in workflow for AI-driven code modification
3
+ # =============================================================================
4
+ #
5
+ # Two-path flow:
6
+ # 1. Pre-resolved mode: caller already checked out projects (e.g., from
7
+ # code-explorer), skips routing and checkout entirely.
8
+ # 2. Standalone mode: runs project-setup sub-workflow for routing + checkout.
9
+ #
10
+ # Usage (standalone):
11
+ # imports:
12
+ # - visor://engineer.yaml
13
+ #
14
+ # checks:
15
+ # modify:
16
+ # type: workflow
17
+ # workflow: engineer
18
+ # args:
19
+ # task: "Add rate limiting to the API"
20
+ # architecture: ./ARCHITECTURE.md
21
+ # docs_repo: my-org/docs
22
+ # project_definitions:
23
+ # - id: backend
24
+ # repo: my-org/backend
25
+ # description: Backend API
26
+ #
27
+ # Usage (pre-resolved, from code-explorer):
28
+ # checks:
29
+ # modify:
30
+ # type: workflow
31
+ # workflow: engineer
32
+ # args:
33
+ # task: "Add rate limiting to the API"
34
+ # projects:
35
+ # - project_id: backend
36
+ # repository: my-org/backend
37
+ # path: /tmp/visor/workspace/backend
38
+ #
39
+ # =============================================================================
40
+
41
+ id: engineer
42
+ name: Engineer
43
+ description: AI-driven code modification workflow with project routing or pre-resolved paths
44
+ version: "1.0.0"
45
+
46
+ imports:
47
+ - project-setup.yaml
48
+
49
+ inputs:
50
+ - name: task
51
+ required: true
52
+ description: The engineering task to accomplish
53
+ schema:
54
+ type: string
55
+
56
+ - name: context
57
+ required: false
58
+ description: Additional context for the task (e.g., conversation thread, ticket details)
59
+ default: ""
60
+ schema:
61
+ type: string
62
+
63
+ # Projects — accepts EITHER format:
64
+ # 1. Pre-resolved (from code-explorer): { project_id, repository, path, ... }
65
+ # → skips routing/checkout, uses paths directly
66
+ # 2. Definitions (for standalone routing): { id, repo, description, ... }
67
+ # → runs project-setup sub-workflow for routing + checkout
68
+ # Same schema as code-talk's projects input, so both skills can share
69
+ # a single loadConfig('projects.yaml') source.
70
+ - name: projects
71
+ required: false
72
+ description: |
73
+ Project list — either pre-resolved paths or definitions for routing.
74
+ Pre-resolved (has path): skips routing, uses checkout paths directly.
75
+ Definitions (has id/repo): runs project-setup for AI routing + checkout.
76
+ default: []
77
+ schema:
78
+ type: array
79
+ items:
80
+ type: object
81
+ properties:
82
+ # Pre-resolved fields
83
+ project_id: { type: string }
84
+ repository: { type: string }
85
+ path: { type: string }
86
+ # Definition fields (same as code-talk projects)
87
+ id: { type: string }
88
+ repo: { type: string }
89
+ description: { type: string }
90
+ sandbox: { type: string }
91
+ services:
92
+ type: object
93
+ setup:
94
+ type: array
95
+ items: { type: string }
96
+ knowledge: { type: string }
97
+
98
+ - name: architecture
99
+ required: false
100
+ description: Architecture model for project routing (standalone mode)
101
+ default: ""
102
+ schema:
103
+ type: string
104
+
105
+ - name: docs_repo
106
+ required: false
107
+ description: Documentation repository for standalone mode
108
+ default: ""
109
+ schema:
110
+ type: string
111
+
112
+ - name: docs_ref
113
+ required: false
114
+ description: Git ref for docs repository
115
+ default: main
116
+ schema:
117
+ type: string
118
+
119
+ - name: max_projects
120
+ required: false
121
+ description: Maximum projects for standalone routing
122
+ default: 3
123
+ schema:
124
+ type: number
125
+
126
+ - name: routing_prompt
127
+ required: false
128
+ description: Additional routing instructions for standalone mode
129
+ default: ""
130
+ schema:
131
+ type: string
132
+
133
+ - name: custom_instructions
134
+ required: false
135
+ description: |
136
+ Additional instructions injected into the engineer AI prompt.
137
+ Use this to customize engineering behavior per-assistant:
138
+ - Coding conventions (e.g., "Always use Go table-driven tests")
139
+ - PR conventions (e.g., "Prefix branch names with ticket ID")
140
+ - Tool preferences (e.g., "Use pnpm instead of npm")
141
+ - Domain-specific guidance
142
+ default: ""
143
+ schema:
144
+ type: string
145
+
146
+ - name: trace_id
147
+ required: false
148
+ description: Trace ID for telemetry correlation
149
+ default: ""
150
+ schema:
151
+ type: string
152
+
153
+ - name: slack_user_id
154
+ required: false
155
+ description: Slack user ID for notifications
156
+ default: ""
157
+ schema:
158
+ type: string
159
+
160
+ - name: sandbox
161
+ required: false
162
+ description: |
163
+ Sandbox name for the engineer-task step (e.g., "bwrap", "docker").
164
+ Must match a sandbox defined in the parent config's sandboxes block.
165
+ When empty, engineer-task runs on the host.
166
+ default: ""
167
+ schema:
168
+ type: string
169
+
170
+ outputs:
171
+ - name: summary
172
+ description: The engineer's response/summary
173
+ value_js: |
174
+ return outputs?.['engineer-task']?.summary ?? outputs?.['engineer-task']?.text ?? null;
175
+
176
+ - name: pr_urls
177
+ description: List of pull request URLs created
178
+ value_js: |
179
+ return outputs?.['engineer-task']?.pr_urls ?? [];
180
+
181
+ - name: files_changed
182
+ description: List of files that were created or modified
183
+ value_js: |
184
+ return outputs?.['engineer-task']?.files_changed ?? [];
185
+
186
+ - name: error
187
+ description: Error details if PR creation failed
188
+ value_js: |
189
+ return outputs?.['engineer-task']?.error ?? null;
190
+
191
+ - name: result
192
+ description: Full engineer output
193
+ value_js: |
194
+ return outputs?.['engineer-task'] ?? null;
195
+
196
+ - name: projects_used
197
+ description: Which projects were used
198
+ value_js: |
199
+ const merged = outputs?.['merge-projects'];
200
+ if (!Array.isArray(merged)) return [];
201
+ return merged.map(function(p) { return p.project_id; }).filter(Boolean);
202
+
203
+ steps:
204
+ # ===========================================================================
205
+ # Step 1: Check if projects are pre-resolved
206
+ # Returns pre-resolved projects or null (triggers standalone flow)
207
+ # ===========================================================================
208
+ prepare-projects:
209
+ type: script
210
+ criticality: internal
211
+ assume:
212
+ - "true"
213
+ guarantee: "output === null || Array.isArray(output)"
214
+ content: |
215
+ const projects = inputs?.projects;
216
+ if (Array.isArray(projects) && projects.length > 0 && projects[0]?.path) {
217
+ return projects;
218
+ }
219
+ return null;
220
+
221
+ # ===========================================================================
222
+ # Step 2: Standalone mode — run project-setup for routing + checkout
223
+ # Only runs when prepare-projects returns null
224
+ # ===========================================================================
225
+ setup-projects:
226
+ type: workflow
227
+ workflow: project-setup
228
+ criticality: internal
229
+ depends_on: [prepare-projects]
230
+ assume:
231
+ - "true"
232
+ if: "outputs['prepare-projects'] === null"
233
+ args:
234
+ question: "{{ inputs.task }}"
235
+ architecture: "{{ inputs.architecture }}"
236
+ docs_repo: "{{ inputs.docs_repo }}"
237
+ docs_ref: "{{ inputs.docs_ref }}"
238
+ projects:
239
+ expression: "inputs.projects"
240
+ max_projects:
241
+ expression: "inputs.max_projects ?? 3"
242
+ routing_prompt: "{{ inputs.routing_prompt }}"
243
+
244
+ # ===========================================================================
245
+ # Step 3: Merge project sources (OR dependency — runs when EITHER completes)
246
+ # ===========================================================================
247
+ merge-projects:
248
+ type: script
249
+ criticality: internal
250
+ depends_on: ["prepare-projects|setup-projects"]
251
+ assume:
252
+ - "true"
253
+ guarantee: "Array.isArray(output)"
254
+ content: |
255
+ const prepared = outputs?.['prepare-projects'];
256
+ if (Array.isArray(prepared) && prepared.length > 0) {
257
+ return prepared;
258
+ }
259
+ return outputs?.['setup-projects']?.checkout_projects ?? [];
260
+
261
+ # ===========================================================================
262
+ # Step 4: Main AI engineering task
263
+ # Setup commands (if any) are exposed via <setup> tags in the prompt —
264
+ # the AI runs them in each project directory before coding.
265
+ # ===========================================================================
266
+ engineer-task:
267
+ type: ai
268
+ criticality: policy
269
+ depends_on: [merge-projects]
270
+ sandbox: "{{ inputs.sandbox }}"
271
+ guarantee: "(output?.pr_urls?.length > 0) || (output?.error != null && output?.error != '')"
272
+ timeout: 3000000
273
+ ai:
274
+ skip_code_context: true
275
+ prompt_type: engineer
276
+ allowBash: true
277
+ allowEdit: true
278
+ enableDelegate: true
279
+ enableTasks: true
280
+ max_iterations: 100
281
+ bashConfig:
282
+ disableDefaultAllow: true
283
+ disableDefaultDeny: true
284
+ allow:
285
+ - "*"
286
+ deny:
287
+ # Destructive git operations
288
+ - "git:push:--force"
289
+ - "git:push:-f"
290
+ - "git:push:--force-with-lease"
291
+ # Destructive GitHub operations
292
+ - "gh:repo:delete"
293
+ - "gh:repo:archive"
294
+ - "gh:repo:rename"
295
+ - "gh:release:delete"
296
+ - "gh:secret:set"
297
+ - "gh:secret:delete"
298
+ - "gh:variable:set"
299
+ - "gh:variable:delete"
300
+ - "gh:ssh-key:add"
301
+ - "gh:ssh-key:delete"
302
+ - "gh:workflow:run"
303
+ - "gh:workflow:enable"
304
+ - "gh:workflow:disable"
305
+ # No sudo
306
+ - "sudo:*"
307
+ timeout: 300000
308
+ schema:
309
+ type: object
310
+ additionalProperties: false
311
+ properties:
312
+ summary:
313
+ type: string
314
+ description: "Detailed summary of what was implemented, files changed, and why"
315
+ pr_urls:
316
+ type: array
317
+ items: { type: string }
318
+ description: "List of pull request URLs created. MUST NOT be empty if files were edited."
319
+ files_changed:
320
+ type: array
321
+ items: { type: string }
322
+ description: "List of files that were created or modified"
323
+ error:
324
+ type: string
325
+ description: "Error details if PR creation failed. Only set if pr_urls is empty."
326
+ required: [summary, pr_urls, files_changed]
327
+ prompt: |
328
+ You are a software engineer. Multi-repo tasks must ALL be completed —
329
+ use delegate tool to work on repos in parallel.
330
+
331
+ {% assign has_custom_instructions = inputs.custom_instructions | size %}
332
+ {% if has_custom_instructions > 0 %}
333
+ <custom_instructions>
334
+ {{ inputs.custom_instructions }}
335
+ </custom_instructions>
336
+ {% endif %}
337
+
338
+ <delegation>
339
+ Use the delegate tool for parallel work, plan validation, and build discovery.
340
+
341
+ MANDATORY FIRST STEP — delegate "Discover build system" for each repository:
342
+ - Check: Makefile, package.json (scripts), Cargo.toml, go.mod, pyproject.toml
343
+ - Check: CI config (.github/workflows/, .gitlab-ci.yml, Jenkinsfile)
344
+ - Check: README for build/test/lint instructions
345
+ - Return the EXACT commands for: build, test, lint/format, and any pre-commit hooks
346
+ - Example output: "build: make, test: make test, lint: gofmt -l . && golangci-lint run"
347
+ Use these commands throughout the session. Do NOT guess — use what the delegate found.
348
+
349
+ MANDATORY BEFORE IMPLEMENTATION — delegate "Plan validation":
350
+ - Describe: files to change, approach, patterns to follow
351
+ - Ask the delegate to verify: do these files exist? Are there existing tests?
352
+ Are there related utilities or patterns to reuse? Any API contracts to respect?
353
+ - Wait for the response before writing code
354
+
355
+ Also delegate for:
356
+ - Multi-repo changes (one delegate per repo, in parallel)
357
+ - Independent sub-tasks (e.g., "update tests" + "update docs")
358
+ - Exploring unfamiliar code before making changes
359
+
360
+ Do NOT delegate:
361
+ - Sequential dependent work (step B needs step A's output)
362
+ - Simple single-file edits (fewer than 5 iterations)
363
+ - Git operations (commit, push, PR) — always do these yourself
364
+
365
+ Delegates have fewer iterations and no access to your conversation.
366
+ Provide all necessary context in the delegate prompt.
367
+ </delegation>
368
+
369
+ <git-workflow>
370
+ This workspace is TEMPORARY — uncommitted changes are DELETED after the session.
371
+ Complete ALL git operations via tool calls before outputting your final response.
372
+
373
+ Before your final response, verify:
374
+ □ Build passes (using exact commands from "Discover build system" delegate)
375
+ □ Tests pass (run the full test suite, not just your new tests)
376
+ □ Lint/format passes (if the project has a linter)
377
+ □ git add <files>
378
+ □ git commit -m "descriptive message"
379
+ □ git push -u origin <branch-name>
380
+ □ gh pr create (for new PRs) or update existing PR
381
+ No PR URL = failed task. Report errors honestly, never claim false success.
382
+
383
+ If build/test/lint fails, fix the issue before committing. If you cannot fix it,
384
+ report exactly what failed and why in your final answer and in the PR description.
385
+ </git-workflow>
386
+
387
+ <structured-output>
388
+ Your JSON output fields must match reality:
389
+ - pr_urls: ONLY URLs from PRs you created/updated via `gh pr create` or `git push`.
390
+ Checking out an existing PR does NOT count — only include it if you pushed to it.
391
+ - summary: What you ACTUALLY did, not what you planned.
392
+ - files_changed: Only files you modified AND committed.
393
+ - error: Set this with the real reason if pr_urls is empty (ran out of iterations,
394
+ tests failed, build broken, push rejected). Leave pr_urls empty in this case.
395
+ </structured-output>
396
+
397
+ <efficiency>
398
+ - Use context data directly — don't re-read files or re-run searches for
399
+ information already provided by code-explorer.
400
+ - If a project has <setup> commands listed, run them FIRST (in the project's
401
+ directory) before any other work. These are prerequisites (e.g., `npm install`,
402
+ `make deps`, database migrations).
403
+ - Use tasks to track multi-step work. Create these tasks at minimum:
404
+ 1. "Run setup commands" — execute <setup> commands for each project (if any)
405
+ 2. "Discover build system" (delegate) — find exact build/test/lint commands
406
+ 3. "Plan validation" (delegate) — verify approach before coding
407
+ 4. "Implement changes" — the actual code/file changes
408
+ 5. "Verify build" — run build, test, and lint commands; fix any failures
409
+ 6. "Create pull request" — git branch, add, commit, push, gh pr create
410
+ Mark in_progress/completed as you go. Do NOT skip "Verify build".
411
+ - If a bash command fails, try a different approach. Don't retry the same
412
+ command or get stuck in loops.
413
+ </efficiency>
414
+ {% assign has_trace = inputs.trace_id | size %}
415
+ {% assign has_slack_user = inputs.slack_user_id | size %}
416
+ {% if has_trace > 0 or has_slack_user > 0 %}
417
+
418
+ <pr-footer>
419
+ Add this footer to the PR body:
420
+ ---
421
+ {% if has_slack_user > 0 %}Requested by: <@{{ inputs.slack_user_id }}>{% endif %}
422
+ {% if has_trace > 0 %}Trace: {{ inputs.trace_id }}{% endif %}
423
+ Generated with Visor AI Assistant
424
+ </pr-footer>
425
+ {% endif %}
426
+
427
+ <task>
428
+ {{ inputs.task }}
429
+ </task>
430
+
431
+ {% assign has_context = inputs.context | size %}
432
+ {% if has_context > 0 %}
433
+ <context>
434
+ {{ inputs.context }}
435
+ </context>
436
+ {% endif %}
437
+
438
+ <projects count="{{ outputs['merge-projects'].size }}">
439
+ {% for p in outputs['merge-projects'] %}
440
+ <project>
441
+ <id>{{ p.project_id }}</id>
442
+ <repo>{{ p.repository }}</repo>
443
+ <path>{{ p.path }}</path>
444
+ <description>{{ p.description }}</description>
445
+ {% if p.sandbox %}<sandbox>{{ p.sandbox }}</sandbox>{% endif %}
446
+ {% if p.knowledge %}<knowledge>{{ p.knowledge }}</knowledge>{% endif %}
447
+ {% if p.services %}<services>{{ p.services | json }}</services>{% endif %}
448
+ {% if p.setup %}<setup>{{ p.setup | json }}</setup>{% endif %}
449
+ </project>
450
+ {% endfor %}
451
+ </projects>
452
+
453
+ # =============================================================================
454
+ # Tests
455
+ # =============================================================================
456
+ tests:
457
+ defaults:
458
+ strict: true
459
+ ai_provider: mock
460
+
461
+ cases:
462
+ - name: pre-resolved-projects
463
+ description: Uses pre-resolved project paths (skips routing)
464
+ event: manual
465
+ fixture: local.minimal
466
+ workflow_input:
467
+ task: "Add rate limiting to the API"
468
+ custom_instructions: "Always use table-driven tests in Go"
469
+ projects:
470
+ - project_id: backend
471
+ repository: org/backend
472
+ path: /tmp/visor/workspace/backend
473
+ description: Backend API
474
+ mocks:
475
+ engineer-task:
476
+ summary: "Added rate limiting middleware"
477
+ pr_urls: ["https://github.com/org/backend/pull/1"]
478
+ files_changed: ["src/middleware/rate-limit.ts"]
479
+ expect:
480
+ calls:
481
+ - step: prepare-projects
482
+ exactly: 1
483
+ - step: setup-projects
484
+ exactly: 0
485
+ - step: merge-projects
486
+ exactly: 1
487
+ - step: engineer-task
488
+ exactly: 1
489
+ prompts:
490
+ - step: engineer-task
491
+ contains:
492
+ - "table-driven tests in Go"
493
+ workflow_output:
494
+ - path: summary
495
+ equals: "Added rate limiting middleware"
496
+ - path: pr_urls[0]
497
+ equals: "https://github.com/org/backend/pull/1"
498
+
499
+ - name: standalone-with-routing
500
+ description: Standalone mode with full project routing
501
+ event: manual
502
+ fixture: local.minimal
503
+ workflow_input:
504
+ task: "Fix the login bug"
505
+ architecture: "# Arch\n- backend: Backend services"
506
+ docs_repo: org/docs
507
+ projects:
508
+ - id: backend
509
+ repo: org/backend
510
+ description: Backend services
511
+ mocks:
512
+ setup-projects:
513
+ docs_path: "/tmp/visor/docs"
514
+ routing_decision:
515
+ projects:
516
+ - project_id: "backend"
517
+ reason: "Login is in backend"
518
+ checkout_projects:
519
+ - project_id: "backend"
520
+ repository: "org/backend"
521
+ description: "Backend services"
522
+ path: "/tmp/visor/workspace/backend"
523
+ sandbox: null
524
+ services: null
525
+ setup: null
526
+ knowledge: null
527
+ engineer-task:
528
+ summary: "Fixed login validation bug"
529
+ pr_urls: ["https://github.com/org/backend/pull/2"]
530
+ files_changed: ["src/auth/login.ts"]
531
+ expect:
532
+ calls:
533
+ - step: prepare-projects
534
+ exactly: 1
535
+ - step: setup-projects
536
+ exactly: 1
537
+ - step: merge-projects
538
+ exactly: 1
539
+ - step: engineer-task
540
+ exactly: 1
541
+ workflow_output:
542
+ - path: summary
543
+ equals: "Fixed login validation bug"
544
+ - path: pr_urls[0]
545
+ equals: "https://github.com/org/backend/pull/2"
546
+
547
+ - name: pre-resolved-with-services-and-setup
548
+ description: Verifies sandbox, services, setup, knowledge appear in prompt
549
+ event: manual
550
+ fixture: local.minimal
551
+ workflow_input:
552
+ task: "Add integration test for auth"
553
+ projects:
554
+ - project_id: gateway
555
+ repository: org/gateway
556
+ path: /tmp/visor/workspace/gateway
557
+ description: API Gateway
558
+ sandbox: go-env
559
+ services:
560
+ redis:
561
+ image: redis:7-alpine
562
+ ports: [6379]
563
+ mongo:
564
+ image: mongo:7
565
+ ports: [27017]
566
+ setup:
567
+ - make deps
568
+ - make generate
569
+ knowledge: |
570
+ Gateway uses Go 1.22 and requires Redis for session storage.
571
+ mocks:
572
+ engineer-task:
573
+ summary: "Added auth integration tests"
574
+ pr_urls: ["https://github.com/org/gateway/pull/5"]
575
+ files_changed: ["tests/auth_test.go"]
576
+ expect:
577
+ calls:
578
+ - step: prepare-projects
579
+ exactly: 1
580
+ - step: setup-projects
581
+ exactly: 0
582
+ - step: merge-projects
583
+ exactly: 1
584
+ - step: engineer-task
585
+ exactly: 1
586
+ outputs:
587
+ # Verify merge-projects passes through project metadata
588
+ - step: merge-projects
589
+ index: last
590
+ path: "[0].project_id"
591
+ equals: "gateway"
592
+ - step: merge-projects
593
+ index: last
594
+ path: "[0].sandbox"
595
+ equals: "go-env"
596
+ - step: merge-projects
597
+ index: last
598
+ path: "[0].services.redis.image"
599
+ equals: "redis:7-alpine"
600
+ prompts:
601
+ - step: engineer-task
602
+ contains:
603
+ - "<sandbox>go-env</sandbox>"
604
+ - "redis"
605
+ - "mongo"
606
+ - "make deps"
607
+ - "make generate"
608
+ - "Gateway uses Go 1.22"