@probelabs/visor 0.1.124 → 0.1.126
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.
- package/dist/config.d.ts.map +1 -1
- package/dist/docs/DEPLOYMENT.md +117 -11
- package/dist/docs/GITHUB_CHECKS.md +18 -4
- package/dist/docs/NPM_USAGE.md +112 -39
- package/dist/docs/action-reference.md +63 -9
- package/dist/docs/advanced-ai.md +58 -51
- package/dist/docs/ai-configuration.md +99 -11
- package/dist/docs/ai-custom-tools-usage.md +70 -33
- package/dist/docs/ai-custom-tools.md +50 -27
- package/dist/docs/architecture.md +1232 -0
- package/dist/docs/bot-transports-rfc.md +13 -3
- package/dist/docs/ci-cli-mode.md +116 -8
- package/dist/docs/claude-code.md +111 -41
- package/dist/docs/command-provider.md +37 -15
- package/dist/docs/commands.md +252 -6
- package/dist/docs/configuration.md +138 -4
- package/dist/docs/contributing.md +737 -0
- package/dist/docs/custom-tools.md +39 -8
- package/dist/docs/dashboards/README.md +33 -19
- package/dist/docs/debug-visualizer-progress.md +14 -13
- package/dist/docs/debug-visualizer-rfc.md +14 -13
- package/dist/docs/debug-visualizer.md +30 -5
- package/dist/docs/debugging.md +73 -8
- package/dist/docs/default-output-schema.md +24 -20
- package/dist/docs/dependencies.md +75 -21
- package/dist/docs/dev-playbook.md +85 -9
- package/dist/docs/engine-pause-resume-rfc.md +11 -11
- package/dist/docs/engine-state-machine-plan.md +10 -3
- package/dist/docs/event-driven-github-integration-rfc.md +20 -11
- package/dist/docs/event-triggers.md +95 -6
- package/dist/docs/execution-statistics-rfc.md +16 -4
- package/dist/docs/fact-validator-gap-analysis.md +12 -1
- package/dist/docs/fact-validator-implementation-plan.md +19 -11
- package/dist/docs/fail-if.md +116 -11
- package/dist/docs/failure-conditions-implementation.md +40 -6
- package/dist/docs/failure-conditions-schema.md +243 -87
- package/dist/docs/failure-routing-rfc.md +43 -18
- package/dist/docs/failure-routing.md +80 -23
- package/dist/docs/faq.md +836 -0
- package/dist/docs/foreach-dependency-propagation.md +32 -15
- package/dist/docs/github-ops.md +6 -5
- package/dist/docs/glossary.md +322 -0
- package/dist/docs/goto-forward-run-plan.md +23 -10
- package/dist/docs/guides/criticality-modes.md +15 -13
- package/dist/docs/guides/fault-management-and-contracts.md +8 -5
- package/dist/docs/guides/workflow-style-guide.md +17 -8
- package/dist/docs/http.md +102 -3
- package/dist/docs/human-input-provider.md +20 -36
- package/dist/docs/index.md +206 -0
- package/dist/docs/lifecycle-hooks.md +322 -2
- package/dist/docs/limits.md +20 -5
- package/dist/docs/liquid-templates.md +86 -14
- package/dist/docs/loop-routing-refactor.md +4 -2
- package/dist/docs/mcp-provider.md +53 -19
- package/dist/docs/mcp.md +27 -1
- package/dist/docs/memory.md +7 -2
- package/dist/docs/migration.md +596 -0
- package/dist/docs/observability.md +227 -6
- package/dist/docs/output-formats.md +388 -9
- package/dist/docs/output-history.md +36 -6
- package/dist/docs/performance.md +510 -4
- package/dist/docs/pluggable.md +95 -4
- package/dist/docs/proposals/snapshot-scope-execution.md +6 -5
- package/dist/docs/providers/git-checkout.md +16 -14
- package/dist/docs/providers/noop.md +696 -0
- package/dist/docs/recipes.md +8 -9
- package/dist/docs/rfc/git-checkout-step.md +3 -1
- package/dist/docs/rfc/on_init-hook.md +18 -5
- package/dist/docs/rfc/workspace-isolation.md +16 -0
- package/dist/docs/roadmap/criticality-implementation-tasks.md +27 -27
- package/dist/docs/router-patterns.md +155 -43
- package/dist/docs/schema-templates.md +51 -15
- package/dist/docs/script.md +162 -13
- package/dist/docs/sdk.md +46 -12
- package/dist/docs/security.md +464 -5
- package/dist/docs/slack-integration.md +481 -0
- package/dist/docs/tag-filtering.md +60 -20
- package/dist/docs/telemetry-setup.md +157 -46
- package/dist/docs/test-framework-rfc.md +37 -36
- package/dist/docs/testing/assertions.md +92 -4
- package/dist/docs/testing/ci.md +56 -7
- package/dist/docs/testing/cli.md +57 -15
- package/dist/docs/testing/cookbook.md +53 -20
- package/dist/docs/testing/dsl-reference.md +110 -9
- package/dist/docs/testing/fixtures-and-mocks.md +28 -3
- package/dist/docs/testing/flows.md +59 -4
- package/dist/docs/testing/getting-started.md +14 -13
- package/dist/docs/testing/troubleshooting.md +39 -2
- package/dist/docs/timeouts.md +174 -18
- package/dist/docs/troubleshooting.md +176 -6
- package/dist/docs/workflow-creation-guide.md +101 -3
- package/dist/docs/workflows.md +138 -41
- package/dist/examples/README.md +169 -4
- package/dist/examples/ai-custom-tools-simple.yaml +2 -3
- package/dist/examples/cron-webhook-config.yaml +15 -0
- package/dist/examples/forEach-example.yaml +6 -0
- package/dist/examples/git-checkout-basic.yaml +4 -0
- package/dist/examples/git-checkout-compare.yaml +6 -0
- package/dist/examples/git-checkout-cross-repo.yaml +7 -0
- package/dist/examples/http-integration-config.yaml +30 -0
- package/dist/examples/https-server-config.yaml +15 -0
- package/dist/examples/mcp-provider-example.yaml +10 -10
- package/dist/examples/transform-example.yaml +3 -0
- package/dist/examples/webhook-pipeline-config.yaml +18 -0
- package/dist/examples/workflows/workflow-composition-example.yaml +4 -0
- package/dist/frontends/slack-frontend.d.ts +2 -0
- package/dist/frontends/slack-frontend.d.ts.map +1 -1
- package/dist/generated/config-schema.d.ts +11 -7
- package/dist/generated/config-schema.d.ts.map +1 -1
- package/dist/generated/config-schema.json +11 -7
- package/dist/index.js +3127 -974
- package/dist/output/traces/{run-2026-01-28T16-15-24-569Z.ndjson → run-2026-01-31T16-37-22-321Z.ndjson} +84 -84
- package/dist/output/traces/{run-2026-01-28T16-16-09-757Z.ndjson → run-2026-01-31T16-38-06-031Z.ndjson} +1013 -1013
- package/dist/providers/ai-check-provider.d.ts +9 -2
- package/dist/providers/ai-check-provider.d.ts.map +1 -1
- package/dist/providers/command-check-provider.d.ts.map +1 -1
- package/dist/providers/mcp-custom-sse-server.d.ts +17 -1
- package/dist/providers/mcp-custom-sse-server.d.ts.map +1 -1
- package/dist/providers/workflow-check-provider.d.ts.map +1 -1
- package/dist/providers/workflow-tool-executor.d.ts +68 -0
- package/dist/providers/workflow-tool-executor.d.ts.map +1 -0
- package/dist/sdk/{check-provider-registry-AQ3JETBG.mjs → check-provider-registry-3KI5RKXT.mjs} +6 -5
- package/dist/sdk/check-provider-registry-IYILYY35.mjs +28 -0
- package/dist/sdk/chunk-2CPMMNIX.mjs +1459 -0
- package/dist/sdk/chunk-2CPMMNIX.mjs.map +1 -0
- package/dist/sdk/chunk-5LI6T4O3.mjs +3600 -0
- package/dist/sdk/chunk-5LI6T4O3.mjs.map +1 -0
- package/dist/sdk/{chunk-YLQ4UN62.mjs → chunk-A4PGHURG.mjs} +6838 -6257
- package/dist/sdk/chunk-A4PGHURG.mjs.map +1 -0
- package/dist/sdk/chunk-EXFGO4FX.mjs +147 -0
- package/dist/sdk/chunk-EXFGO4FX.mjs.map +1 -0
- package/dist/sdk/chunk-PJ7K5UFC.mjs +17732 -0
- package/dist/sdk/chunk-PJ7K5UFC.mjs.map +1 -0
- package/dist/sdk/{chunk-BHZ4CKUS.mjs → chunk-PXFIALUH.mjs} +77 -8
- package/dist/sdk/chunk-PXFIALUH.mjs.map +1 -0
- package/dist/sdk/{chunk-PVITVJ6J.mjs → chunk-RTKJXNZS.mjs} +32 -9
- package/dist/sdk/chunk-RTKJXNZS.mjs.map +1 -0
- package/dist/sdk/chunk-VW2GBXQT.mjs +606 -0
- package/dist/sdk/chunk-VW2GBXQT.mjs.map +1 -0
- package/dist/sdk/{config-RQQPMLRD.mjs → config-5AUYQFHE.mjs} +2 -2
- package/dist/sdk/config-6CUVEH7H.mjs +16 -0
- package/dist/sdk/config-6CUVEH7H.mjs.map +1 -0
- package/dist/sdk/{github-frontend-6Q4BISZX.mjs → github-frontend-BZ4N3BFZ.mjs} +7 -3
- package/dist/sdk/github-frontend-BZ4N3BFZ.mjs.map +1 -0
- package/dist/sdk/host-4MT3EW2I.mjs +52 -0
- package/dist/sdk/{host-P5NQICP7.mjs → host-NYWXLIFC.mjs} +2 -2
- package/dist/sdk/host-NYWXLIFC.mjs.map +1 -0
- package/dist/sdk/{routing-DEY2AIXM.mjs → routing-6R42GXUO.mjs} +2 -2
- package/dist/sdk/routing-6R42GXUO.mjs.map +1 -0
- package/dist/sdk/routing-7FXPULTO.mjs +24 -0
- package/dist/sdk/routing-7FXPULTO.mjs.map +1 -0
- package/dist/sdk/sdk.d.mts +3 -1
- package/dist/sdk/sdk.d.ts +3 -1
- package/dist/sdk/sdk.js +12163 -11204
- package/dist/sdk/sdk.js.map +1 -1
- package/dist/sdk/sdk.mjs +14 -10
- package/dist/sdk/sdk.mjs.map +1 -1
- package/dist/sdk/slack-frontend-JUT3TYVC.mjs +821 -0
- package/dist/sdk/slack-frontend-JUT3TYVC.mjs.map +1 -0
- package/dist/sdk/workflow-check-provider-H3CUOLUD.mjs +28 -0
- package/dist/sdk/workflow-check-provider-H3CUOLUD.mjs.map +1 -0
- package/dist/sdk/workflow-check-provider-YUNNF4KC.mjs +28 -0
- package/dist/sdk/workflow-check-provider-YUNNF4KC.mjs.map +1 -0
- package/dist/sdk/workflow-registry-KFWSDSLM.mjs +12 -0
- package/dist/sdk/workflow-registry-KFWSDSLM.mjs.map +1 -0
- package/dist/slack/socket-runner.d.ts +2 -0
- package/dist/slack/socket-runner.d.ts.map +1 -1
- package/dist/state-machine/context/workflow-inputs.d.ts +20 -0
- package/dist/state-machine/context/workflow-inputs.d.ts.map +1 -0
- package/dist/state-machine/dispatch/execution-invoker.d.ts.map +1 -1
- package/dist/state-machine/dispatch/foreach-processor.d.ts.map +1 -1
- package/dist/state-machine/dispatch/stats-manager.d.ts.map +1 -1
- package/dist/state-machine/states/level-dispatch.d.ts.map +1 -1
- package/dist/state-machine/states/routing.d.ts +2 -1
- package/dist/state-machine/states/routing.d.ts.map +1 -1
- package/dist/traces/{run-2026-01-28T16-15-24-569Z.ndjson → run-2026-01-31T16-37-22-321Z.ndjson} +84 -84
- package/dist/traces/{run-2026-01-28T16-16-09-757Z.ndjson → run-2026-01-31T16-38-06-031Z.ndjson} +1013 -1013
- package/dist/types/config.d.ts +3 -1
- package/dist/types/config.d.ts.map +1 -1
- package/dist/utils/human-id.d.ts +12 -0
- package/dist/utils/human-id.d.ts.map +1 -0
- package/dist/utils/worktree-manager.d.ts +3 -0
- package/dist/utils/worktree-manager.d.ts.map +1 -1
- package/dist/workflow-executor.d.ts.map +1 -1
- package/dist/workflow-registry.d.ts +1 -0
- package/dist/workflow-registry.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/sdk/chunk-BHZ4CKUS.mjs.map +0 -1
- package/dist/sdk/chunk-PVITVJ6J.mjs.map +0 -1
- package/dist/sdk/chunk-YLQ4UN62.mjs.map +0 -1
- package/dist/sdk/github-frontend-6Q4BISZX.mjs.map +0 -1
- /package/dist/sdk/{check-provider-registry-AQ3JETBG.mjs.map → check-provider-registry-3KI5RKXT.mjs.map} +0 -0
- /package/dist/sdk/{config-RQQPMLRD.mjs.map → check-provider-registry-IYILYY35.mjs.map} +0 -0
- /package/dist/sdk/{routing-DEY2AIXM.mjs.map → config-5AUYQFHE.mjs.map} +0 -0
- /package/dist/sdk/{host-P5NQICP7.mjs.map → host-4MT3EW2I.mjs.map} +0 -0
package/dist/docs/faq.md
ADDED
|
@@ -0,0 +1,836 @@
|
|
|
1
|
+
# Frequently Asked Questions (FAQ)
|
|
2
|
+
|
|
3
|
+
This document answers common questions about Visor, the AI-powered workflow orchestration tool for code review, automation, and CI/CD pipelines.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
- [General Questions](#general-questions)
|
|
10
|
+
- [Configuration Questions](#configuration-questions)
|
|
11
|
+
- [GitHub Actions Questions](#github-actions-questions)
|
|
12
|
+
- [Provider Questions](#provider-questions)
|
|
13
|
+
- [Troubleshooting](#troubleshooting)
|
|
14
|
+
- [Advanced Topics](#advanced-topics)
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## General Questions
|
|
19
|
+
|
|
20
|
+
### What is Visor?
|
|
21
|
+
|
|
22
|
+
Visor is an AI-powered workflow orchestration tool that can perform intelligent code review, automate CI/CD tasks, and integrate with various services. It supports multiple AI providers (Google Gemini, Anthropic Claude, OpenAI GPT, AWS Bedrock) and can run as both a GitHub Action and a CLI tool.
|
|
23
|
+
|
|
24
|
+
Key capabilities:
|
|
25
|
+
- Automated code review for pull requests
|
|
26
|
+
- Security, performance, and style analysis
|
|
27
|
+
- Custom workflow automation with 15+ provider types
|
|
28
|
+
- MCP (Model Context Protocol) tool integration
|
|
29
|
+
- Slack and HTTP webhook integrations
|
|
30
|
+
|
|
31
|
+
### How is Visor different from other code review tools?
|
|
32
|
+
|
|
33
|
+
Unlike traditional linters that rely on static rules, Visor uses AI to understand context and provide nuanced feedback. Key differentiators:
|
|
34
|
+
|
|
35
|
+
1. **AI-powered analysis**: Uses LLMs to understand code intent and provide contextual suggestions
|
|
36
|
+
2. **Workflow orchestration**: Not just code review - supports complex multi-step workflows with routing, retries, and state management
|
|
37
|
+
3. **Pluggable architecture**: 15+ provider types (AI, command, MCP, HTTP, memory, etc.) that can be combined
|
|
38
|
+
4. **Configuration-driven**: Define workflows in YAML without writing code
|
|
39
|
+
5. **Multiple transports**: Works as GitHub Action, CLI tool, or Slack bot
|
|
40
|
+
|
|
41
|
+
### Can Visor run without AI? What happens then?
|
|
42
|
+
|
|
43
|
+
Yes. If no AI API key is configured, Visor falls back to fast, heuristic-based checks using simple pattern matching for basic style and performance issues.
|
|
44
|
+
|
|
45
|
+
To use AI-powered features, set one of these environment variables:
|
|
46
|
+
- `GOOGLE_API_KEY` for Google Gemini
|
|
47
|
+
- `ANTHROPIC_API_KEY` for Anthropic Claude
|
|
48
|
+
- `OPENAI_API_KEY` for OpenAI GPT
|
|
49
|
+
- AWS credentials for AWS Bedrock
|
|
50
|
+
|
|
51
|
+
### What are the supported AI providers?
|
|
52
|
+
|
|
53
|
+
| Provider | Environment Variable | Example Models |
|
|
54
|
+
|----------|---------------------|----------------|
|
|
55
|
+
| Google Gemini | `GOOGLE_API_KEY` | `gemini-2.0-flash-exp`, `gemini-1.5-pro` |
|
|
56
|
+
| Anthropic Claude | `ANTHROPIC_API_KEY` | `claude-3-5-sonnet-latest`, `claude-3-opus-latest` |
|
|
57
|
+
| OpenAI GPT | `OPENAI_API_KEY` | `gpt-4o`, `gpt-4-turbo` |
|
|
58
|
+
| AWS Bedrock | AWS credentials | `anthropic.claude-sonnet-4-20250514-v1:0` |
|
|
59
|
+
|
|
60
|
+
See [AI Configuration](./ai-configuration.md) for complete setup instructions.
|
|
61
|
+
|
|
62
|
+
### How do I install Visor?
|
|
63
|
+
|
|
64
|
+
**Quick start (no installation required):**
|
|
65
|
+
```bash
|
|
66
|
+
npx -y @probelabs/visor@latest --help
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Global installation:**
|
|
70
|
+
```bash
|
|
71
|
+
npm install -g @probelabs/visor
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Project dependency:**
|
|
75
|
+
```bash
|
|
76
|
+
npm install --save-dev @probelabs/visor
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
See [NPM Usage](./NPM_USAGE.md) for detailed installation options.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Configuration Questions
|
|
84
|
+
|
|
85
|
+
### Where should I put my configuration file?
|
|
86
|
+
|
|
87
|
+
Visor looks for configuration in this order:
|
|
88
|
+
1. CLI `--config` parameter
|
|
89
|
+
2. `.visor.yaml` in the project root (note the leading dot)
|
|
90
|
+
3. Default configuration
|
|
91
|
+
|
|
92
|
+
**Example:**
|
|
93
|
+
```bash
|
|
94
|
+
# Use default location (.visor.yaml)
|
|
95
|
+
visor --check all
|
|
96
|
+
|
|
97
|
+
# Use custom config file
|
|
98
|
+
visor --config path/to/my-config.yaml
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### How do I validate my configuration?
|
|
102
|
+
|
|
103
|
+
Use the `validate` command to check for errors before running:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
# Validate default config
|
|
107
|
+
visor validate
|
|
108
|
+
|
|
109
|
+
# Validate specific file
|
|
110
|
+
visor validate --config .visor.yaml
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The validator checks for:
|
|
114
|
+
- Missing required fields
|
|
115
|
+
- Invalid check types
|
|
116
|
+
- Incorrect event triggers
|
|
117
|
+
- Schema compliance
|
|
118
|
+
|
|
119
|
+
See [Configuration](./configuration.md#validating-configuration) for details.
|
|
120
|
+
|
|
121
|
+
### How do I configure multiple AI providers?
|
|
122
|
+
|
|
123
|
+
You can set a global default and override per-check:
|
|
124
|
+
|
|
125
|
+
```yaml
|
|
126
|
+
# Global default
|
|
127
|
+
ai_provider: anthropic
|
|
128
|
+
ai_model: claude-3-5-sonnet-latest
|
|
129
|
+
|
|
130
|
+
steps:
|
|
131
|
+
# This uses the global default (Anthropic)
|
|
132
|
+
security-review:
|
|
133
|
+
type: ai
|
|
134
|
+
prompt: "Analyze security vulnerabilities"
|
|
135
|
+
|
|
136
|
+
# This overrides to use Google
|
|
137
|
+
performance-review:
|
|
138
|
+
type: ai
|
|
139
|
+
ai_provider: google
|
|
140
|
+
ai_model: gemini-2.0-flash-exp
|
|
141
|
+
prompt: "Analyze performance issues"
|
|
142
|
+
|
|
143
|
+
# Alternative syntax using nested 'ai' block
|
|
144
|
+
style-review:
|
|
145
|
+
type: ai
|
|
146
|
+
ai:
|
|
147
|
+
provider: openai
|
|
148
|
+
model: gpt-4o
|
|
149
|
+
prompt: "Review code style"
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### How do I enable or disable specific checks?
|
|
153
|
+
|
|
154
|
+
Use the `on` field to control when checks run:
|
|
155
|
+
|
|
156
|
+
```yaml
|
|
157
|
+
steps:
|
|
158
|
+
# Runs on PR open and update
|
|
159
|
+
security-check:
|
|
160
|
+
type: ai
|
|
161
|
+
on: [pr_opened, pr_updated]
|
|
162
|
+
prompt: "Check for security issues"
|
|
163
|
+
|
|
164
|
+
# Disable a check by setting on to empty
|
|
165
|
+
disabled-check:
|
|
166
|
+
type: ai
|
|
167
|
+
on: [] # Never runs
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
You can also use tags and the CLI to filter checks:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
# Run only checks tagged 'security'
|
|
174
|
+
visor --tags security
|
|
175
|
+
|
|
176
|
+
# Exclude checks tagged 'experimental'
|
|
177
|
+
visor --exclude-tags experimental
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
See [Tag Filtering](./tag-filtering.md) for more options.
|
|
181
|
+
|
|
182
|
+
### How do I configure custom tools?
|
|
183
|
+
|
|
184
|
+
Define tools in the `tools` section and reference them in checks:
|
|
185
|
+
|
|
186
|
+
```yaml
|
|
187
|
+
tools:
|
|
188
|
+
my-lint-tool:
|
|
189
|
+
name: my-lint-tool
|
|
190
|
+
description: Run custom linter
|
|
191
|
+
inputSchema:
|
|
192
|
+
type: object
|
|
193
|
+
properties:
|
|
194
|
+
files:
|
|
195
|
+
type: array
|
|
196
|
+
items:
|
|
197
|
+
type: string
|
|
198
|
+
required: [files]
|
|
199
|
+
exec: 'eslint {{ args.files | join: " " }}'
|
|
200
|
+
|
|
201
|
+
steps:
|
|
202
|
+
run-linter:
|
|
203
|
+
type: mcp
|
|
204
|
+
transport: custom
|
|
205
|
+
method: my-lint-tool
|
|
206
|
+
methodArgs:
|
|
207
|
+
files: ["src/**/*.ts"]
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
See [Custom Tools](./custom-tools.md) for complete documentation.
|
|
211
|
+
|
|
212
|
+
### How do I share configuration across projects?
|
|
213
|
+
|
|
214
|
+
Use the `extends` field to inherit from base configurations:
|
|
215
|
+
|
|
216
|
+
```yaml
|
|
217
|
+
# .visor.yaml
|
|
218
|
+
extends:
|
|
219
|
+
- ./team-standards.yaml # Local file
|
|
220
|
+
- default # Built-in defaults
|
|
221
|
+
|
|
222
|
+
steps:
|
|
223
|
+
my-custom-check:
|
|
224
|
+
type: ai
|
|
225
|
+
prompt: "Project-specific analysis"
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
You can also extend remote configurations:
|
|
229
|
+
```bash
|
|
230
|
+
visor --allowed-remote-patterns "https://github.com/myorg/"
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
See [Configuration Inheritance](./configuration.md#configuration-inheritance-with-extends).
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## GitHub Actions Questions
|
|
238
|
+
|
|
239
|
+
### How do I set up Visor as a GitHub Action?
|
|
240
|
+
|
|
241
|
+
Create `.github/workflows/visor.yml`:
|
|
242
|
+
|
|
243
|
+
```yaml
|
|
244
|
+
name: Visor Code Review
|
|
245
|
+
on:
|
|
246
|
+
pull_request:
|
|
247
|
+
types: [opened, synchronize]
|
|
248
|
+
|
|
249
|
+
permissions:
|
|
250
|
+
contents: read
|
|
251
|
+
pull-requests: write
|
|
252
|
+
issues: write
|
|
253
|
+
checks: write
|
|
254
|
+
|
|
255
|
+
jobs:
|
|
256
|
+
review:
|
|
257
|
+
runs-on: ubuntu-latest
|
|
258
|
+
steps:
|
|
259
|
+
- uses: actions/checkout@v4
|
|
260
|
+
- uses: buger/visor@main
|
|
261
|
+
with:
|
|
262
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
263
|
+
env:
|
|
264
|
+
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
See [Action Reference](./action-reference.md) for all available inputs and outputs.
|
|
268
|
+
|
|
269
|
+
### What GitHub events trigger Visor?
|
|
270
|
+
|
|
271
|
+
| Event | Trigger | Use Case |
|
|
272
|
+
|-------|---------|----------|
|
|
273
|
+
| `pull_request` (opened) | `pr_opened` | New PR review |
|
|
274
|
+
| `pull_request` (synchronize) | `pr_updated` | Updated PR review |
|
|
275
|
+
| `pull_request` (closed) | `pr_closed` | PR close handling |
|
|
276
|
+
| `issues` (opened) | `issue_opened` | Issue assistants |
|
|
277
|
+
| `issue_comment` | `issue_comment` | Comment commands |
|
|
278
|
+
| `schedule` | `schedule` | Cron jobs |
|
|
279
|
+
| `workflow_dispatch` | `schedule` | Manual triggers |
|
|
280
|
+
|
|
281
|
+
See [Event Triggers](./event-triggers.md) for complete documentation.
|
|
282
|
+
|
|
283
|
+
### How do I customize what gets reviewed?
|
|
284
|
+
|
|
285
|
+
Use the `on` field and conditions:
|
|
286
|
+
|
|
287
|
+
```yaml
|
|
288
|
+
steps:
|
|
289
|
+
# Only review TypeScript files
|
|
290
|
+
ts-review:
|
|
291
|
+
type: ai
|
|
292
|
+
on: [pr_opened, pr_updated]
|
|
293
|
+
if: "files.some(f => f.filename.endsWith('.ts'))"
|
|
294
|
+
prompt: "Review TypeScript code"
|
|
295
|
+
|
|
296
|
+
# Only review on main branch PRs
|
|
297
|
+
main-review:
|
|
298
|
+
type: ai
|
|
299
|
+
on: [pr_opened]
|
|
300
|
+
if: "pr.base === 'main'"
|
|
301
|
+
prompt: "Review changes to main"
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### How do I handle large PRs?
|
|
305
|
+
|
|
306
|
+
For large PRs, consider:
|
|
307
|
+
|
|
308
|
+
1. **Increase timeout:**
|
|
309
|
+
```yaml
|
|
310
|
+
steps:
|
|
311
|
+
review:
|
|
312
|
+
type: ai
|
|
313
|
+
timeout: 300000 # 5 minutes
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
2. **Run checks in parallel:**
|
|
317
|
+
```yaml
|
|
318
|
+
max_parallelism: 5
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
3. **Split into focused checks:**
|
|
322
|
+
```yaml
|
|
323
|
+
steps:
|
|
324
|
+
security-review:
|
|
325
|
+
type: ai
|
|
326
|
+
prompt: "Focus only on security"
|
|
327
|
+
|
|
328
|
+
style-review:
|
|
329
|
+
type: ai
|
|
330
|
+
prompt: "Focus only on style"
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
4. **Filter by file type:**
|
|
334
|
+
```yaml
|
|
335
|
+
steps:
|
|
336
|
+
js-review:
|
|
337
|
+
type: ai
|
|
338
|
+
if: "files.some(f => f.filename.endsWith('.js'))"
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### Why am I getting permission errors on fork PRs?
|
|
342
|
+
|
|
343
|
+
Fork PRs have restricted permissions by default. Solutions:
|
|
344
|
+
|
|
345
|
+
1. **Accept comment-only mode**: Visor falls back to PR comments automatically
|
|
346
|
+
2. **Use `pull_request_target`**: For full check run support (requires careful security review)
|
|
347
|
+
|
|
348
|
+
See [GitHub Checks - Fork PR Support](./GITHUB_CHECKS.md#fork-pr-support).
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
## Provider Questions
|
|
353
|
+
|
|
354
|
+
### Which AI provider should I use?
|
|
355
|
+
|
|
356
|
+
| Provider | Best For | Notes |
|
|
357
|
+
|----------|----------|-------|
|
|
358
|
+
| **Anthropic Claude** | Complex code analysis, security review | Strong reasoning, good context handling |
|
|
359
|
+
| **Google Gemini** | Fast analysis, cost-effective | Good for high-volume reviews |
|
|
360
|
+
| **OpenAI GPT-4** | General-purpose analysis | Wide model availability |
|
|
361
|
+
| **AWS Bedrock** | Enterprise environments | IAM integration, private endpoints |
|
|
362
|
+
|
|
363
|
+
For most use cases, start with whichever provider you already have API access to.
|
|
364
|
+
|
|
365
|
+
### How do I add custom checks?
|
|
366
|
+
|
|
367
|
+
Several provider types support custom logic:
|
|
368
|
+
|
|
369
|
+
**Command provider (shell commands):**
|
|
370
|
+
```yaml
|
|
371
|
+
steps:
|
|
372
|
+
custom-lint:
|
|
373
|
+
type: command
|
|
374
|
+
exec: "npm run lint"
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
**Script provider (JavaScript):**
|
|
378
|
+
```yaml
|
|
379
|
+
steps:
|
|
380
|
+
custom-analysis:
|
|
381
|
+
type: script
|
|
382
|
+
content: |
|
|
383
|
+
const largeFiles = pr.files.filter(f => f.additions > 100);
|
|
384
|
+
return {
|
|
385
|
+
hasLargeChanges: largeFiles.length > 0,
|
|
386
|
+
files: largeFiles.map(f => f.filename)
|
|
387
|
+
};
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
**AI provider (custom prompts):**
|
|
391
|
+
```yaml
|
|
392
|
+
steps:
|
|
393
|
+
domain-review:
|
|
394
|
+
type: ai
|
|
395
|
+
prompt: |
|
|
396
|
+
You are an expert in our domain. Review this code for:
|
|
397
|
+
- Business logic correctness
|
|
398
|
+
- Domain model violations
|
|
399
|
+
- API contract adherence
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### How do I use MCP tools?
|
|
403
|
+
|
|
404
|
+
The MCP provider supports direct tool execution via multiple transports:
|
|
405
|
+
|
|
406
|
+
**stdio transport (local command):**
|
|
407
|
+
```yaml
|
|
408
|
+
steps:
|
|
409
|
+
probe-search:
|
|
410
|
+
type: mcp
|
|
411
|
+
transport: stdio
|
|
412
|
+
command: npx
|
|
413
|
+
command_args: ["-y", "@probelabs/probe@latest", "mcp"]
|
|
414
|
+
method: search_code
|
|
415
|
+
methodArgs:
|
|
416
|
+
query: "TODO"
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
**HTTP transport (remote server):**
|
|
420
|
+
```yaml
|
|
421
|
+
steps:
|
|
422
|
+
remote-tool:
|
|
423
|
+
type: mcp
|
|
424
|
+
transport: http
|
|
425
|
+
url: https://mcp-server.example.com/mcp
|
|
426
|
+
method: analyze
|
|
427
|
+
methodArgs:
|
|
428
|
+
data: "{{ pr.title }}"
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
**Custom transport (YAML-defined tools):**
|
|
432
|
+
```yaml
|
|
433
|
+
tools:
|
|
434
|
+
grep-tool:
|
|
435
|
+
exec: 'grep -rn "{{ args.pattern }}" src/'
|
|
436
|
+
|
|
437
|
+
steps:
|
|
438
|
+
search:
|
|
439
|
+
type: mcp
|
|
440
|
+
transport: custom
|
|
441
|
+
method: grep-tool
|
|
442
|
+
methodArgs:
|
|
443
|
+
pattern: "FIXME"
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
See [MCP Provider](./mcp-provider.md) for complete documentation.
|
|
447
|
+
|
|
448
|
+
### What's the difference between command and script providers?
|
|
449
|
+
|
|
450
|
+
| Feature | `command` | `script` |
|
|
451
|
+
|---------|-----------|----------|
|
|
452
|
+
| Execution | Shell commands | JavaScript sandbox |
|
|
453
|
+
| Use case | External tools, shell scripts | Logic, data processing |
|
|
454
|
+
| Access | File system, external commands | PR context, memory, outputs |
|
|
455
|
+
| Security | Runs with process permissions | Sandboxed environment |
|
|
456
|
+
|
|
457
|
+
**Use `command` for:**
|
|
458
|
+
```yaml
|
|
459
|
+
steps:
|
|
460
|
+
run-tests:
|
|
461
|
+
type: command
|
|
462
|
+
exec: "npm test -- --json"
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
**Use `script` for:**
|
|
466
|
+
```yaml
|
|
467
|
+
steps:
|
|
468
|
+
process-results:
|
|
469
|
+
type: script
|
|
470
|
+
depends_on: [run-tests]
|
|
471
|
+
content: |
|
|
472
|
+
const results = outputs['run-tests'];
|
|
473
|
+
return {
|
|
474
|
+
passed: results.tests.filter(t => t.passed).length,
|
|
475
|
+
failed: results.tests.filter(t => !t.passed).length
|
|
476
|
+
};
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
---
|
|
480
|
+
|
|
481
|
+
## Troubleshooting
|
|
482
|
+
|
|
483
|
+
### Why isn't my check running?
|
|
484
|
+
|
|
485
|
+
Common causes:
|
|
486
|
+
|
|
487
|
+
1. **Event filter mismatch**: Check if the `on` field matches the current event
|
|
488
|
+
```yaml
|
|
489
|
+
steps:
|
|
490
|
+
my-check:
|
|
491
|
+
on: [pr_opened] # Won't run on pr_updated
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
2. **Condition evaluated to false**: Check your `if` expression
|
|
495
|
+
```yaml
|
|
496
|
+
steps:
|
|
497
|
+
my-check:
|
|
498
|
+
if: "files.length > 0" # Won't run if no files changed
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
3. **Tag filter exclusion**: Check if tags are filtering out the check
|
|
502
|
+
```bash
|
|
503
|
+
visor --tags github # Only runs checks tagged 'github'
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
4. **Missing dependencies**: Ensure `depends_on` targets exist
|
|
507
|
+
```yaml
|
|
508
|
+
steps:
|
|
509
|
+
my-check:
|
|
510
|
+
depends_on: [nonexistent-check] # Will fail
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
Debug with:
|
|
514
|
+
```bash
|
|
515
|
+
visor --check all --debug
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
### Why is routing not working?
|
|
519
|
+
|
|
520
|
+
Common issues with `goto`, `retry`, and `run`:
|
|
521
|
+
|
|
522
|
+
1. **goto must target ancestors only**: You can only jump back to previously executed checks
|
|
523
|
+
```yaml
|
|
524
|
+
steps:
|
|
525
|
+
step-a:
|
|
526
|
+
type: command
|
|
527
|
+
step-b:
|
|
528
|
+
depends_on: [step-a]
|
|
529
|
+
on_fail:
|
|
530
|
+
goto: step-a # Valid (ancestor)
|
|
531
|
+
# goto: step-c # Invalid (not an ancestor)
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
2. **Loop limit reached**: Check `max_loops` setting
|
|
535
|
+
```yaml
|
|
536
|
+
routing:
|
|
537
|
+
max_loops: 10 # Increase if needed
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
3. **JS expression errors**: Use `log()` to debug
|
|
541
|
+
```yaml
|
|
542
|
+
on_fail:
|
|
543
|
+
goto_js: |
|
|
544
|
+
log("Current outputs:", outputs);
|
|
545
|
+
log("History:", outputs.history);
|
|
546
|
+
return null;
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
See [Failure Routing](./failure-routing.md) for complete documentation.
|
|
550
|
+
|
|
551
|
+
### How do I debug my configuration?
|
|
552
|
+
|
|
553
|
+
**Enable debug mode:**
|
|
554
|
+
```bash
|
|
555
|
+
visor --check all --debug
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
**Use the logger check type:**
|
|
559
|
+
```yaml
|
|
560
|
+
steps:
|
|
561
|
+
debug-flow:
|
|
562
|
+
type: logger
|
|
563
|
+
depends_on: [previous-check]
|
|
564
|
+
message: |
|
|
565
|
+
Outputs: {{ outputs | json }}
|
|
566
|
+
PR: {{ pr | json }}
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
**Use `log()` in JavaScript expressions:**
|
|
570
|
+
```yaml
|
|
571
|
+
steps:
|
|
572
|
+
my-check:
|
|
573
|
+
type: command
|
|
574
|
+
if: |
|
|
575
|
+
log("Files:", filesChanged);
|
|
576
|
+
log("Event:", event);
|
|
577
|
+
return filesChanged.length > 0;
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
**Enable tracing with OpenTelemetry:**
|
|
581
|
+
```bash
|
|
582
|
+
VISOR_TELEMETRY_ENABLED=true \
|
|
583
|
+
VISOR_TELEMETRY_SINK=otlp \
|
|
584
|
+
visor --check all
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
See [Debugging Guide](./debugging.md) for comprehensive techniques.
|
|
588
|
+
|
|
589
|
+
### What do the different error messages mean?
|
|
590
|
+
|
|
591
|
+
| Error | Meaning | Solution |
|
|
592
|
+
|-------|---------|----------|
|
|
593
|
+
| `Configuration not found` | No `.visor.yaml` found | Create config or use `--config` |
|
|
594
|
+
| `Invalid check type` | Unknown provider type | Use valid type: ai, command, script, etc. |
|
|
595
|
+
| `outputs is undefined` | Missing `depends_on` | Add dependency to access outputs |
|
|
596
|
+
| `Rate limit exceeded` | API quota reached | Reduce parallelism or add delays |
|
|
597
|
+
| `Command execution failed` | Shell command error | Check command syntax and permissions |
|
|
598
|
+
| `Transform error` | Invalid Liquid/JS | Debug with `log()` function |
|
|
599
|
+
|
|
600
|
+
See [Troubleshooting](./troubleshooting.md) for more error resolutions.
|
|
601
|
+
|
|
602
|
+
### Why are my AI responses incomplete or truncated?
|
|
603
|
+
|
|
604
|
+
Possible causes:
|
|
605
|
+
|
|
606
|
+
1. **Timeout too short**: Increase step timeout
|
|
607
|
+
```yaml
|
|
608
|
+
steps:
|
|
609
|
+
analysis:
|
|
610
|
+
type: ai
|
|
611
|
+
timeout: 120000 # 2 minutes
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
2. **Model token limits**: Switch to a model with larger context
|
|
615
|
+
```yaml
|
|
616
|
+
steps:
|
|
617
|
+
analysis:
|
|
618
|
+
type: ai
|
|
619
|
+
ai_model: gpt-4-turbo # 128k context
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
3. **Prompt too complex**: Split into smaller, focused prompts
|
|
623
|
+
|
|
624
|
+
---
|
|
625
|
+
|
|
626
|
+
## Advanced Topics
|
|
627
|
+
|
|
628
|
+
### How do I implement retry logic?
|
|
629
|
+
|
|
630
|
+
Use `on_fail.retry` with optional backoff:
|
|
631
|
+
|
|
632
|
+
```yaml
|
|
633
|
+
steps:
|
|
634
|
+
api-call:
|
|
635
|
+
type: http_client
|
|
636
|
+
url: https://api.example.com/data
|
|
637
|
+
on_fail:
|
|
638
|
+
retry:
|
|
639
|
+
max: 3
|
|
640
|
+
backoff:
|
|
641
|
+
mode: exponential
|
|
642
|
+
delay_ms: 1000 # 1s, 2s, 4s
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
You can also configure retries at the AI provider level:
|
|
646
|
+
|
|
647
|
+
```yaml
|
|
648
|
+
steps:
|
|
649
|
+
analysis:
|
|
650
|
+
type: ai
|
|
651
|
+
ai:
|
|
652
|
+
retry:
|
|
653
|
+
maxRetries: 3
|
|
654
|
+
initialDelay: 1000
|
|
655
|
+
backoffFactor: 2
|
|
656
|
+
```
|
|
657
|
+
|
|
658
|
+
See [Failure Routing](./failure-routing.md) for complete retry options.
|
|
659
|
+
|
|
660
|
+
### How do I share state between checks?
|
|
661
|
+
|
|
662
|
+
Use the memory provider for persistent key-value storage:
|
|
663
|
+
|
|
664
|
+
```yaml
|
|
665
|
+
steps:
|
|
666
|
+
store-value:
|
|
667
|
+
type: memory
|
|
668
|
+
operation: set
|
|
669
|
+
key: my-key
|
|
670
|
+
value: "{{ outputs['previous-check'].result }}"
|
|
671
|
+
namespace: my-workflow
|
|
672
|
+
|
|
673
|
+
read-value:
|
|
674
|
+
type: script
|
|
675
|
+
content: |
|
|
676
|
+
const value = memory.get('my-key', 'my-workflow');
|
|
677
|
+
return { retrieved: value };
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
In script and routing expressions, use the `memory` object:
|
|
681
|
+
```javascript
|
|
682
|
+
// Read
|
|
683
|
+
const value = memory.get('key', 'namespace');
|
|
684
|
+
|
|
685
|
+
// Write
|
|
686
|
+
memory.set('key', 'value', 'namespace');
|
|
687
|
+
|
|
688
|
+
// Increment
|
|
689
|
+
memory.increment('counter', 1, 'namespace');
|
|
690
|
+
```
|
|
691
|
+
|
|
692
|
+
See [Memory Provider](./memory.md) for complete documentation.
|
|
693
|
+
|
|
694
|
+
### How do I create conditional workflows?
|
|
695
|
+
|
|
696
|
+
Use `if` conditions and routing:
|
|
697
|
+
|
|
698
|
+
**Simple conditions:**
|
|
699
|
+
```yaml
|
|
700
|
+
steps:
|
|
701
|
+
security-scan:
|
|
702
|
+
type: ai
|
|
703
|
+
if: "files.some(f => f.filename.includes('security'))"
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
**Branch by output:**
|
|
707
|
+
```yaml
|
|
708
|
+
steps:
|
|
709
|
+
check-type:
|
|
710
|
+
type: script
|
|
711
|
+
content: |
|
|
712
|
+
return { type: pr.title.startsWith('fix:') ? 'bugfix' : 'feature' };
|
|
713
|
+
|
|
714
|
+
bugfix-review:
|
|
715
|
+
type: ai
|
|
716
|
+
depends_on: [check-type]
|
|
717
|
+
if: "outputs['check-type'].type === 'bugfix'"
|
|
718
|
+
prompt: "Review this bug fix"
|
|
719
|
+
|
|
720
|
+
feature-review:
|
|
721
|
+
type: ai
|
|
722
|
+
depends_on: [check-type]
|
|
723
|
+
if: "outputs['check-type'].type === 'feature'"
|
|
724
|
+
prompt: "Review this feature"
|
|
725
|
+
```
|
|
726
|
+
|
|
727
|
+
**Declarative routing with transitions:**
|
|
728
|
+
```yaml
|
|
729
|
+
steps:
|
|
730
|
+
validate:
|
|
731
|
+
type: ai
|
|
732
|
+
on_success:
|
|
733
|
+
transitions:
|
|
734
|
+
- when: "outputs['validate'].score >= 90"
|
|
735
|
+
to: publish
|
|
736
|
+
- when: "outputs['validate'].score >= 70"
|
|
737
|
+
to: review
|
|
738
|
+
- when: "true"
|
|
739
|
+
to: reject
|
|
740
|
+
```
|
|
741
|
+
|
|
742
|
+
See [Router Patterns](./router-patterns.md) for best practices.
|
|
743
|
+
|
|
744
|
+
### How do I test my Visor configuration?
|
|
745
|
+
|
|
746
|
+
Use the built-in test framework with YAML test files:
|
|
747
|
+
|
|
748
|
+
```yaml
|
|
749
|
+
# visor.tests.yaml
|
|
750
|
+
version: "1.0"
|
|
751
|
+
extends: ".visor.yaml"
|
|
752
|
+
|
|
753
|
+
tests:
|
|
754
|
+
defaults:
|
|
755
|
+
strict: true
|
|
756
|
+
ai_provider: mock
|
|
757
|
+
|
|
758
|
+
cases:
|
|
759
|
+
- name: security-check-runs
|
|
760
|
+
event: pr_opened
|
|
761
|
+
fixture: gh.pr_open.minimal
|
|
762
|
+
mocks:
|
|
763
|
+
security-review:
|
|
764
|
+
text: "No security issues found"
|
|
765
|
+
expect:
|
|
766
|
+
calls:
|
|
767
|
+
- step: security-review
|
|
768
|
+
exactly: 1
|
|
769
|
+
```
|
|
770
|
+
|
|
771
|
+
Run tests:
|
|
772
|
+
```bash
|
|
773
|
+
# Run all tests
|
|
774
|
+
visor test
|
|
775
|
+
|
|
776
|
+
# Run specific test case
|
|
777
|
+
visor test --only security-check-runs
|
|
778
|
+
|
|
779
|
+
# Validate test file only
|
|
780
|
+
visor test --validate
|
|
781
|
+
```
|
|
782
|
+
|
|
783
|
+
See [Testing Guide](./testing/getting-started.md) for complete documentation.
|
|
784
|
+
|
|
785
|
+
### How do I use workflows for reusable components?
|
|
786
|
+
|
|
787
|
+
Define reusable workflows in separate files:
|
|
788
|
+
|
|
789
|
+
```yaml
|
|
790
|
+
# workflows/security-scan.yaml
|
|
791
|
+
id: security-scan
|
|
792
|
+
name: Security Scanner
|
|
793
|
+
inputs:
|
|
794
|
+
- name: severity_threshold
|
|
795
|
+
schema:
|
|
796
|
+
type: string
|
|
797
|
+
enum: [low, medium, high]
|
|
798
|
+
default: medium
|
|
799
|
+
|
|
800
|
+
steps:
|
|
801
|
+
scan:
|
|
802
|
+
type: ai
|
|
803
|
+
prompt: |
|
|
804
|
+
Scan for security issues with threshold: {{ inputs.severity_threshold }}
|
|
805
|
+
|
|
806
|
+
outputs:
|
|
807
|
+
- name: vulnerabilities
|
|
808
|
+
value_js: steps.scan.output.issues
|
|
809
|
+
```
|
|
810
|
+
|
|
811
|
+
Import and use in your main config:
|
|
812
|
+
|
|
813
|
+
```yaml
|
|
814
|
+
# .visor.yaml
|
|
815
|
+
imports:
|
|
816
|
+
- ./workflows/security-scan.yaml
|
|
817
|
+
|
|
818
|
+
steps:
|
|
819
|
+
run-security:
|
|
820
|
+
type: workflow
|
|
821
|
+
workflow: security-scan
|
|
822
|
+
args:
|
|
823
|
+
severity_threshold: high
|
|
824
|
+
```
|
|
825
|
+
|
|
826
|
+
See [Reusable Workflows](./workflows.md) for complete documentation.
|
|
827
|
+
|
|
828
|
+
---
|
|
829
|
+
|
|
830
|
+
## Further Reading
|
|
831
|
+
|
|
832
|
+
- [Configuration Reference](./configuration.md) - Complete configuration options
|
|
833
|
+
- [Provider Documentation](./pluggable.md) - All 15+ provider types
|
|
834
|
+
- [Debugging Guide](./debugging.md) - Troubleshooting techniques
|
|
835
|
+
- [Recipes](./recipes.md) - Copy-paste workflow examples
|
|
836
|
+
- [Workflow Style Guide](./guides/workflow-style-guide.md) - Best practices
|