@probelabs/visor 0.1.131 → 0.1.132-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.
- package/README.md +460 -596
- package/action.yml +2 -2
- package/dist/ai-review-service.d.ts +3 -0
- package/dist/ai-review-service.d.ts.map +1 -1
- package/dist/cli-main.d.ts.map +1 -1
- package/dist/config/config-watcher.d.ts +15 -1
- package/dist/config/config-watcher.d.ts.map +1 -1
- package/dist/enterprise/policy/policy-input-builder.d.ts +2 -0
- package/dist/enterprise/policy/policy-input-builder.d.ts.map +1 -1
- package/dist/frontends/slack-frontend.d.ts.map +1 -1
- package/dist/generated/config-schema.d.ts +404 -96
- package/dist/generated/config-schema.d.ts.map +1 -1
- package/dist/generated/config-schema.json +2875 -0
- package/dist/index.js +24782 -8528
- package/dist/providers/ai-check-provider.d.ts +12 -0
- package/dist/providers/ai-check-provider.d.ts.map +1 -1
- package/dist/providers/workflow-check-provider.d.ts.map +1 -1
- package/dist/providers/workflow-tool-executor.d.ts +5 -1
- package/dist/providers/workflow-tool-executor.d.ts.map +1 -1
- package/dist/sdk/{check-provider-registry-S7BMQ2FC.mjs → check-provider-registry-7TCA3NSG.mjs} +6 -6
- package/dist/sdk/{check-provider-registry-ZOLEYDKM.mjs → check-provider-registry-KUDVEKAC.mjs} +7 -7
- package/dist/sdk/{chunk-OMFPM576.mjs → chunk-27RV5RR2.mjs} +2 -2
- package/dist/sdk/{chunk-6ZZ4DPAA.mjs → chunk-2RNTEWOA.mjs} +236 -47
- package/dist/sdk/chunk-2RNTEWOA.mjs.map +1 -0
- package/dist/sdk/{chunk-2GCSK3PD.mjs → chunk-BGBXLPLL.mjs} +3 -3
- package/dist/sdk/{chunk-LQ5B4T6L.mjs → chunk-U3BLLEW3.mjs} +431 -82
- package/dist/sdk/chunk-U3BLLEW3.mjs.map +1 -0
- package/dist/sdk/{chunk-N4I6ZDCJ.mjs → chunk-VG7FWDC2.mjs} +3 -3
- package/dist/sdk/{chunk-RI77TA6V.mjs.map → chunk-VG7FWDC2.mjs.map} +1 -1
- package/dist/sdk/{chunk-MQ57AB4U.mjs → chunk-XGI47XIH.mjs} +260 -55
- package/dist/sdk/chunk-XGI47XIH.mjs.map +1 -0
- package/dist/sdk/{config-4EG7IQIU.mjs → config-FMIIATKX.mjs} +2 -2
- package/dist/sdk/{failure-condition-evaluator-GLHZZF47.mjs → failure-condition-evaluator-PNONVBXD.mjs} +3 -3
- package/dist/sdk/{github-frontend-F4TE2JY7.mjs → github-frontend-WR4S3NG5.mjs} +3 -3
- package/dist/sdk/{host-SAT6RHDX.mjs → host-TROSAWTE.mjs} +3 -3
- package/dist/sdk/{host-VA3ET7N6.mjs → host-U7V54J2H.mjs} +3 -3
- package/dist/sdk/knex-store-HPXJILBL.mjs +411 -0
- package/dist/sdk/knex-store-HPXJILBL.mjs.map +1 -0
- package/dist/sdk/loader-ZC5G3JGJ.mjs +89 -0
- package/dist/sdk/loader-ZC5G3JGJ.mjs.map +1 -0
- package/dist/sdk/opa-policy-engine-S2S2ULEI.mjs +655 -0
- package/dist/sdk/opa-policy-engine-S2S2ULEI.mjs.map +1 -0
- package/dist/sdk/{routing-KFYQGOYU.mjs → routing-F4FOWVKF.mjs} +4 -4
- package/dist/sdk/{schedule-tool-handler-OQF57URO.mjs → schedule-tool-handler-ULNF7TZW.mjs} +7 -7
- package/dist/sdk/{schedule-tool-handler-PJVKWSYX.mjs → schedule-tool-handler-VFES42DD.mjs} +6 -6
- package/dist/sdk/sdk.d.mts +56 -38
- package/dist/sdk/sdk.d.ts +56 -38
- package/dist/sdk/sdk.js +2275 -388
- package/dist/sdk/sdk.js.map +1 -1
- package/dist/sdk/sdk.mjs +6 -6
- package/dist/sdk/{slack-frontend-LAY45IBR.mjs → slack-frontend-JS2VAZWB.mjs} +95 -4
- package/dist/sdk/slack-frontend-JS2VAZWB.mjs.map +1 -0
- package/dist/sdk/{trace-helpers-R2ETIEC2.mjs → trace-helpers-RDPXIN4S.mjs} +2 -2
- package/dist/sdk/validator-XTZJZZJH.mjs +134 -0
- package/dist/sdk/validator-XTZJZZJH.mjs.map +1 -0
- package/dist/sdk/{workflow-check-provider-LRWD52WN.mjs → workflow-check-provider-4NFWH6YO.mjs} +6 -6
- package/dist/sdk/{workflow-check-provider-N2DRFQDB.mjs → workflow-check-provider-5XS62BCJ.mjs} +7 -7
- package/dist/slack/adapter.d.ts +2 -0
- package/dist/slack/adapter.d.ts.map +1 -1
- package/dist/slack/client.d.ts +3 -0
- package/dist/slack/client.d.ts.map +1 -1
- package/dist/slack/markdown.d.ts +29 -0
- package/dist/slack/markdown.d.ts.map +1 -1
- package/dist/slack/socket-runner.d.ts +2 -0
- package/dist/slack/socket-runner.d.ts.map +1 -1
- package/dist/tui/chat-tui.d.ts +7 -0
- package/dist/tui/chat-tui.d.ts.map +1 -1
- package/dist/tui/components/input-bar.d.ts +11 -0
- package/dist/tui/components/input-bar.d.ts.map +1 -1
- package/dist/tui/components/trace-viewer.d.ts +25 -1
- package/dist/tui/components/trace-viewer.d.ts.map +1 -1
- package/dist/types/bot.d.ts +12 -0
- package/dist/types/bot.d.ts.map +1 -1
- package/dist/types/config.d.ts +4 -1
- package/dist/types/config.d.ts.map +1 -1
- package/package.json +3 -3
- package/dist/defaults/.visor.yaml +0 -420
- package/dist/output/traces/run-2026-02-15T19-14-20-379Z.ndjson +0 -138
- package/dist/output/traces/run-2026-02-15T19-15-09-410Z.ndjson +0 -1357
- package/dist/sdk/check-provider-registry-AAPPJ4CP.mjs +0 -28
- package/dist/sdk/chunk-6ZZ4DPAA.mjs.map +0 -1
- package/dist/sdk/chunk-EBTD2D4L.mjs +0 -739
- package/dist/sdk/chunk-LDFUW34H.mjs +0 -39912
- package/dist/sdk/chunk-LDFUW34H.mjs.map +0 -1
- package/dist/sdk/chunk-LQ5B4T6L.mjs.map +0 -1
- package/dist/sdk/chunk-MQ57AB4U.mjs.map +0 -1
- package/dist/sdk/chunk-N4I6ZDCJ.mjs.map +0 -1
- package/dist/sdk/chunk-OMFPM576.mjs.map +0 -1
- package/dist/sdk/chunk-RI77TA6V.mjs +0 -436
- package/dist/sdk/chunk-VO4N6TEL.mjs +0 -1502
- package/dist/sdk/chunk-VO4N6TEL.mjs.map +0 -1
- package/dist/sdk/failure-condition-evaluator-KN55WXRO.mjs +0 -17
- package/dist/sdk/github-frontend-HCOKL53D.mjs +0 -1356
- package/dist/sdk/github-frontend-HCOKL53D.mjs.map +0 -1
- package/dist/sdk/routing-OXQKETSA.mjs +0 -25
- package/dist/sdk/schedule-tool-handler-G353DHS6.mjs +0 -38
- package/dist/sdk/schedule-tool-handler-PJVKWSYX.mjs.map +0 -1
- package/dist/sdk/slack-frontend-LAY45IBR.mjs.map +0 -1
- package/dist/sdk/trace-helpers-LOPBHYYX.mjs +0 -25
- package/dist/sdk/trace-helpers-LOPBHYYX.mjs.map +0 -1
- package/dist/sdk/trace-helpers-R2ETIEC2.mjs.map +0 -1
- package/dist/sdk/workflow-check-provider-57KAR4Y4.mjs +0 -28
- package/dist/sdk/workflow-check-provider-57KAR4Y4.mjs.map +0 -1
- package/dist/sdk/workflow-check-provider-LRWD52WN.mjs.map +0 -1
- package/dist/sdk/workflow-check-provider-N2DRFQDB.mjs.map +0 -1
- package/dist/traces/run-2026-02-15T19-14-20-379Z.ndjson +0 -138
- package/dist/traces/run-2026-02-15T19-15-09-410Z.ndjson +0 -1357
- /package/dist/sdk/{check-provider-registry-AAPPJ4CP.mjs.map → check-provider-registry-7TCA3NSG.mjs.map} +0 -0
- /package/dist/sdk/{check-provider-registry-S7BMQ2FC.mjs.map → check-provider-registry-KUDVEKAC.mjs.map} +0 -0
- /package/dist/sdk/{chunk-EBTD2D4L.mjs.map → chunk-27RV5RR2.mjs.map} +0 -0
- /package/dist/sdk/{chunk-2GCSK3PD.mjs.map → chunk-BGBXLPLL.mjs.map} +0 -0
- /package/dist/sdk/{check-provider-registry-ZOLEYDKM.mjs.map → config-FMIIATKX.mjs.map} +0 -0
- /package/dist/sdk/{config-4EG7IQIU.mjs.map → failure-condition-evaluator-PNONVBXD.mjs.map} +0 -0
- /package/dist/sdk/{github-frontend-F4TE2JY7.mjs.map → github-frontend-WR4S3NG5.mjs.map} +0 -0
- /package/dist/sdk/{host-SAT6RHDX.mjs.map → host-TROSAWTE.mjs.map} +0 -0
- /package/dist/sdk/{host-VA3ET7N6.mjs.map → host-U7V54J2H.mjs.map} +0 -0
- /package/dist/sdk/{failure-condition-evaluator-GLHZZF47.mjs.map → routing-F4FOWVKF.mjs.map} +0 -0
- /package/dist/sdk/{failure-condition-evaluator-KN55WXRO.mjs.map → schedule-tool-handler-ULNF7TZW.mjs.map} +0 -0
- /package/dist/sdk/{routing-KFYQGOYU.mjs.map → schedule-tool-handler-VFES42DD.mjs.map} +0 -0
- /package/dist/sdk/{routing-OXQKETSA.mjs.map → trace-helpers-RDPXIN4S.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-handler-G353DHS6.mjs.map → workflow-check-provider-4NFWH6YO.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-handler-OQF57URO.mjs.map → workflow-check-provider-5XS62BCJ.mjs.map} +0 -0
package/README.md
CHANGED
|
@@ -1,36 +1,96 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
<img src="site/visor.png" alt="Visor Logo" width="500" />
|
|
3
|
-
|
|
4
|
-
# Visor —
|
|
5
|
-
|
|
3
|
+
|
|
4
|
+
# Visor — AI workflow engine for code review, assistants & automation
|
|
5
|
+
|
|
6
6
|
[](https://www.typescriptlang.org/)
|
|
7
7
|
[](https://nodejs.org/)
|
|
8
8
|
[](LICENSE)
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
AI‑assisted when you want it, fully predictable when you don’t.
|
|
9
|
+
|
|
10
|
+
Orchestrate checks, MCP tools, and AI providers with YAML-driven pipelines.
|
|
11
|
+
Runs as GitHub Action, CLI, Slack bot, or HTTP API.
|
|
13
12
|
</div>
|
|
14
13
|
|
|
15
14
|
---
|
|
16
15
|
|
|
17
|
-
Visor
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
16
|
+
Visor is an open-source workflow engine that lets you define multi-step AI pipelines in YAML. Wire up shell commands, AI providers, MCP tools, HTTP calls, and custom scripts into dependency-aware DAGs — then run them from your terminal, CI, Slack, or an HTTP endpoint.
|
|
17
|
+
|
|
18
|
+
**What you get out of the box:**
|
|
19
|
+
|
|
20
|
+
- **YAML-driven pipelines** — define checks, transforms, routing, and AI prompts in a single config file.
|
|
21
|
+
- **4 runtime modes** — CLI, GitHub Action, Slack bot, HTTP server — same config, any surface.
|
|
22
|
+
- **12+ provider types** — `ai`, `command`, `script`, `mcp`, `http`, `claude-code`, `github`, `memory`, `workflow`, and more.
|
|
23
|
+
- **AI orchestration** — multi-provider (Gemini, Claude, OpenAI, Bedrock), session reuse, MCP tool calling, retry & fallback.
|
|
24
|
+
- **Execution engine** — dependency DAGs, parallel waves, forEach fan-out, conditional routing, failure auto-remediation.
|
|
25
|
+
- **Built-in testing** — YAML-native integration tests with fixtures, mocks, and assertions.
|
|
26
|
+
|
|
27
|
+
## Table of Contents
|
|
28
|
+
|
|
29
|
+
- [Quick Start](#-quick-start)
|
|
30
|
+
- [Runtime Modes](#-runtime-modes)
|
|
31
|
+
- [PR Comment Commands](#-pr-comment-commands)
|
|
32
|
+
- [Core Concepts](#-core-concepts)
|
|
33
|
+
- [Provider Types](#-provider-types)
|
|
34
|
+
- [Orchestration](#-orchestration)
|
|
35
|
+
- [AI & MCP](#-ai--mcp)
|
|
36
|
+
- [GitHub Provider](#-github-provider)
|
|
37
|
+
- [Templating & Transforms](#-templating--transforms)
|
|
38
|
+
- [Suppressing Warnings](#-suppressing-warnings)
|
|
39
|
+
- [Testing Framework](#-testing-framework)
|
|
40
|
+
- [SDK](#-sdk-programmatic-usage)
|
|
41
|
+
- [Configuration](#-configuration)
|
|
42
|
+
- [Observability](#-observability)
|
|
43
|
+
- [Security](#-security)
|
|
44
|
+
- [Enterprise Policy Engine](#-enterprise-policy-engine-ee)
|
|
45
|
+
- [Further Reading](#-further-reading)
|
|
46
|
+
- [Contributing](#-contributing)
|
|
47
|
+
- [License](#-license)
|
|
48
|
+
|
|
49
|
+
**Requirements:** Node.js 18+ (CI runs Node 20).
|
|
50
|
+
|
|
51
|
+
## 🚀 Quick Start
|
|
52
|
+
|
|
53
|
+
### Install & Run
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
# One-off
|
|
57
|
+
npx -y @probelabs/visor@latest --check all --output table
|
|
58
|
+
|
|
59
|
+
# As a dev dependency
|
|
60
|
+
npm i -D @probelabs/visor
|
|
61
|
+
npx visor --check all --output json
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Minimal Config (`.visor.yaml`)
|
|
65
|
+
|
|
66
|
+
```yaml
|
|
67
|
+
version: "1.0"
|
|
68
|
+
steps:
|
|
69
|
+
security:
|
|
70
|
+
type: ai
|
|
71
|
+
prompt: "Identify security issues in changed files"
|
|
72
|
+
tags: ["fast", "security"]
|
|
73
|
+
|
|
74
|
+
run-tests:
|
|
75
|
+
type: command
|
|
76
|
+
exec: npm test
|
|
77
|
+
depends_on: [security]
|
|
24
78
|
|
|
25
|
-
|
|
79
|
+
notify:
|
|
80
|
+
type: http
|
|
81
|
+
method: POST
|
|
82
|
+
url: https://hooks.slack.com/...
|
|
83
|
+
body: '{ "text": "Tests {{ outputs[''run-tests''].status }}" }'
|
|
84
|
+
depends_on: [run-tests]
|
|
85
|
+
```
|
|
26
86
|
|
|
27
|
-
###
|
|
87
|
+
### As a GitHub Action
|
|
28
88
|
|
|
29
89
|
```yaml
|
|
30
90
|
# .github/workflows/visor.yml
|
|
31
91
|
name: Visor
|
|
32
92
|
on:
|
|
33
|
-
pull_request: { types: [opened, synchronize] }
|
|
93
|
+
pull_request: { types: [opened, synchronize] }
|
|
34
94
|
issues: { types: [opened] }
|
|
35
95
|
issue_comment: { types: [created] }
|
|
36
96
|
permissions:
|
|
@@ -45,743 +105,576 @@ jobs:
|
|
|
45
105
|
- uses: actions/checkout@v4
|
|
46
106
|
- uses: probelabs/visor@v1
|
|
47
107
|
env:
|
|
48
|
-
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
|
|
108
|
+
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
|
|
49
109
|
```
|
|
50
110
|
|
|
51
|
-
|
|
52
|
-
- Visor posts a PR summary, creates GitHub Check runs, and annotates lines.
|
|
53
|
-
- **Note**: For external contributor PRs from forks, check runs may not be available due to GitHub security restrictions. Visor will gracefully fall back to PR comments. See [Fork PR Support](docs/GITHUB_CHECKS.md#fork-pr-support) for how to enable check runs for forks.
|
|
54
|
-
|
|
55
|
-
### Optional: Add `.visor.yaml`
|
|
56
|
-
|
|
57
|
-
```yaml
|
|
58
|
-
version: "1.0"
|
|
59
|
-
steps: # or 'checks' (legacy, both work identically)
|
|
60
|
-
security:
|
|
61
|
-
type: ai
|
|
62
|
-
schema: code-review
|
|
63
|
-
prompt: "Identify security issues in changed files"
|
|
64
|
-
tags: ["fast", "security"]
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
Tip: Pin releases for stability, e.g. `uses: probelabs/visor@v1`.
|
|
68
|
-
For latest changes, use `uses: probelabs/visor@nightly`. The `@main` ref is maintained for compatibility but may change frequently and is not recommended for production.
|
|
69
|
-
|
|
70
|
-
## Requirements
|
|
111
|
+
> **Tip:** Pin releases for stability with `@v1`. For bleeding-edge, use `@nightly`.
|
|
71
112
|
|
|
72
|
-
|
|
73
|
-
- When used as a GitHub Action: appropriate permissions/secrets (see [Security Defaults](#-security-defaults))
|
|
113
|
+
## 🖥️ Runtime Modes
|
|
74
114
|
|
|
75
|
-
|
|
115
|
+
Visor runs the same YAML config across four surfaces:
|
|
76
116
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
npm i -D @probelabs/visor
|
|
84
|
-
npx visor --check all --output json
|
|
85
|
-
```
|
|
117
|
+
| Mode | How to run | Best for |
|
|
118
|
+
|------|-----------|----------|
|
|
119
|
+
| **CLI** | `visor --check all --output table` | Local dev, CI pipelines |
|
|
120
|
+
| **GitHub Action** | `uses: probelabs/visor@v1` | PR reviews, issue triage, annotations |
|
|
121
|
+
| **Slack bot** | `visor --slack --config .visor.yaml` | Team assistants, ChatOps |
|
|
122
|
+
| **HTTP server** | `http_server: { enabled: true, port: 8080 }` | Webhooks, API integrations |
|
|
86
123
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
124
|
+
Additional modes:
|
|
125
|
+
- **TUI** — interactive chat-style terminal UI: `visor --tui`
|
|
126
|
+
- **SDK** — programmatic Node.js API: `import { runChecks } from '@probelabs/visor/sdk'`
|
|
127
|
+
- **Scheduler** — cron-based execution with database-backed persistence
|
|
90
128
|
|
|
91
129
|
```bash
|
|
92
|
-
#
|
|
93
|
-
visor validate # Search for .visor.yaml in current directory
|
|
94
|
-
visor validate --config .visor.yaml # Validate specific config file
|
|
95
|
-
|
|
96
|
-
# Run all checks with a table output
|
|
130
|
+
# CLI examples
|
|
97
131
|
visor --check all --output table
|
|
98
|
-
|
|
99
|
-
# Interactive TUI mode (chat-style interface for human-input workflows)
|
|
100
|
-
visor --tui --config ./my-workflow.yaml
|
|
101
|
-
|
|
102
|
-
# Filter by tags (e.g., fast/local) and increase parallelism
|
|
103
132
|
visor --tags fast,local --max-parallelism 5
|
|
133
|
+
visor --analyze-branch-diff # PR-style diff analysis
|
|
134
|
+
visor --event pr_updated # Simulate GitHub events
|
|
135
|
+
visor --tui --config ./workflow.yaml # Interactive TUI
|
|
136
|
+
visor --debug-server --debug-port 3456 # Live web debugger
|
|
137
|
+
visor config snapshots # Config version history
|
|
138
|
+
visor validate # Validate config
|
|
139
|
+
visor test --progress compact # Run integration tests
|
|
140
|
+
```
|
|
104
141
|
|
|
105
|
-
|
|
106
|
-
# Auto-enabled for code-review schemas, or force with --analyze-branch-diff
|
|
107
|
-
visor --analyze-branch-diff # Analyzes diff vs main/master branch
|
|
108
|
-
visor --check security --analyze-branch-diff # Specific checks on branch diff
|
|
109
|
-
|
|
110
|
-
# Simulate GitHub events for event-based check filtering
|
|
111
|
-
visor --event pr_updated # Run checks triggered by PR updates (auto for code-review)
|
|
112
|
-
visor --event issue_opened # Run checks triggered by new issues
|
|
113
|
-
visor --event all # Run all checks regardless of event filters (default)
|
|
114
|
-
|
|
115
|
-
# Emit machine‑readable results and save to a file
|
|
116
|
-
visor --check security --output json --output-file visor-results.json
|
|
142
|
+
**Run modes:** Default is CLI mode everywhere. For GitHub-specific behavior (comments, checks, annotations), run with `--mode github-actions` or set `mode: github-actions` in the Action. Force CLI mode inside Actions with `VISOR_MODE=cli`.
|
|
117
143
|
|
|
118
|
-
|
|
119
|
-
visor --debug-server --debug-port 3456
|
|
144
|
+
See [docs/commands.md](docs/commands.md) for the full CLI reference.
|
|
120
145
|
|
|
121
|
-
|
|
122
|
-
visor config snapshots
|
|
123
|
-
visor config diff 1 2
|
|
146
|
+
## 💬 PR Comment Commands
|
|
124
147
|
|
|
125
|
-
|
|
126
|
-
visor --slack --config .visor.yaml --watch
|
|
148
|
+
Trigger reviews and assistant actions via comments on PRs or issues:
|
|
127
149
|
|
|
128
|
-
|
|
129
|
-
|
|
150
|
+
```
|
|
151
|
+
/review # Re-run all checks
|
|
152
|
+
/review --check security # Re-run specific check
|
|
153
|
+
/visor how does caching work? # Ask the built-in assistant
|
|
130
154
|
```
|
|
131
155
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
Additional guides:
|
|
135
|
-
|
|
136
|
-
- debugging and local development (TUI, debug server): [docs/debugging.md](docs/debugging.md)
|
|
137
|
-
- fail conditions: [docs/fail-if.md](docs/fail-if.md)
|
|
138
|
-
- forEach behavior and dependent propagation (including outputs_raw and history precedence): [docs/foreach-dependency-propagation.md](docs/foreach-dependency-propagation.md)
|
|
139
|
-
- Failure routing and `on_finish` (with outputs_raw in routing JS): [docs/failure-routing.md](docs/failure-routing.md)
|
|
140
|
-
- timeouts and provider units: [docs/timeouts.md](docs/timeouts.md)
|
|
141
|
-
- execution limits (run caps for safety): [docs/limits.md](docs/limits.md)
|
|
142
|
-
- output formatting limits and truncation controls: [docs/output-formatting.md](docs/output-formatting.md)
|
|
143
|
-
- live execution visualizer and control API: [docs/debug-visualizer.md](docs/debug-visualizer.md)
|
|
144
|
-
- scheduler for cron jobs and dynamic schedules: [docs/scheduler.md](docs/scheduler.md)
|
|
145
|
-
|
|
146
|
-
## 🧪 Integration Tests
|
|
147
|
-
|
|
148
|
-
Write and run integration tests for your Visor config in YAML. No network, built‑in GitHub fixtures, strict by default, and great CLI output.
|
|
156
|
+
Learn more: [docs/commands.md](docs/commands.md)
|
|
149
157
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
-
|
|
158
|
-
|
|
158
|
+
## 🧩 Core Concepts
|
|
159
|
+
|
|
160
|
+
| Concept | What it is |
|
|
161
|
+
|---------|-----------|
|
|
162
|
+
| **Step** (or Check) | Unit of work — a shell command, AI call, HTTP request, script, etc. |
|
|
163
|
+
| **Provider** | How a step runs: `ai`, `command`, `script`, `mcp`, `http`, `claude-code`, `github`, `memory`, `workflow`, … |
|
|
164
|
+
| **depends_on** | Execution order — independents run in parallel, dependents wait. |
|
|
165
|
+
| **forEach** | Fan-out — transform output into an array, run dependents per item. |
|
|
166
|
+
| **Routing** | `on_fail`, `on_success`, `goto`, `retry` — conditional flow with loop safety. |
|
|
167
|
+
| **Transform** | Reshape output with Liquid templates or JavaScript before passing downstream. |
|
|
168
|
+
| **Schema** | JSON Schema that validates step output (e.g., `code-review`). |
|
|
169
|
+
| **Template** | Renders validated output into Markdown/table for PR comments. |
|
|
170
|
+
| **Group** | Which PR comment a step posts into. |
|
|
171
|
+
| **Tags** | Label steps and filter with `--tags fast,local`. |
|
|
172
|
+
| **Events** | Trigger steps on PRs, issues, comments, webhooks, or cron schedules. |
|
|
173
|
+
|
|
174
|
+
## 🔌 Provider Types
|
|
175
|
+
|
|
176
|
+
| Provider | Description | Example use |
|
|
177
|
+
|----------|------------|------------|
|
|
178
|
+
| `ai` | Multi-provider AI (Gemini, Claude, OpenAI, Bedrock) | Code review, analysis, generation |
|
|
179
|
+
| `command` | Shell commands with Liquid templating | Run tests, build, lint |
|
|
180
|
+
| `script` | JavaScript in a secure sandbox | Transform data, custom logic |
|
|
181
|
+
| `mcp` | MCP tool execution (stdio/SSE/HTTP) | External tool integration |
|
|
182
|
+
| `claude-code` | Claude Code SDK with MCP tools | Deep code analysis, refactoring |
|
|
183
|
+
| `http` | HTTP output/webhook sender | Notify Slack, trigger CI |
|
|
184
|
+
| `http_input` | Webhook receiver | Accept external events |
|
|
185
|
+
| `http_client` | HTTP API client | Call external APIs |
|
|
186
|
+
| `github` | GitHub operations (labels, comments, checks) | Label PRs, post reviews |
|
|
187
|
+
| `memory` | Key-value store (get/set/append/increment) | State across steps |
|
|
188
|
+
| `workflow` | Reusable sub-workflows from files/URLs | Compose pipelines |
|
|
189
|
+
| `human-input` | Interactive prompts (TUI/Slack) | Approvals, user input |
|
|
190
|
+
| `log` / `logger` | Structured logging | Debug, audit trail |
|
|
191
|
+
| `noop` | No-op placeholder | Orchestration nodes |
|
|
192
|
+
| `git-checkout` | Git operations (clone, checkout, worktree) | Multi-repo workflows |
|
|
193
|
+
|
|
194
|
+
See [docs/pluggable.md](docs/pluggable.md) for building custom providers.
|
|
195
|
+
|
|
196
|
+
## ⚙️ Orchestration
|
|
197
|
+
|
|
198
|
+
### Dependencies & Parallel Execution
|
|
199
|
+
|
|
200
|
+
Steps without dependencies run in parallel waves. `depends_on` enforces ordering:
|
|
159
201
|
|
|
160
|
-
|
|
202
|
+
```yaml
|
|
203
|
+
steps:
|
|
204
|
+
fetch-data:
|
|
205
|
+
type: command
|
|
206
|
+
exec: curl -s https://api.example.com/data
|
|
161
207
|
|
|
162
|
-
|
|
208
|
+
analyze:
|
|
209
|
+
type: ai
|
|
210
|
+
prompt: "Analyze: {{ outputs['fetch-data'] }}"
|
|
211
|
+
depends_on: [fetch-data]
|
|
163
212
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
- Dependencies – `depends_on` controls order; independents run in parallel.
|
|
170
|
-
- Tags – label checks (`fast`, `local`, `comprehensive`) and filter with `--tags`.
|
|
171
|
-
- Events – PRs, issues, `/review` comments, webhooks, or cron schedules.
|
|
213
|
+
report:
|
|
214
|
+
type: command
|
|
215
|
+
exec: 'echo "Done: {{ outputs[''analyze''] | truncate: 100 }}"'
|
|
216
|
+
depends_on: [analyze]
|
|
217
|
+
```
|
|
172
218
|
|
|
173
|
-
|
|
219
|
+
### forEach Fan-Out
|
|
174
220
|
|
|
175
|
-
|
|
176
|
-
- PR Reviews – security/perf/style findings with native annotations
|
|
177
|
-
- Issue Assistant – `/visor …` for code Q&A and triage
|
|
178
|
-
- Release Notes – manual or tagged release workflows
|
|
179
|
-
- Scheduled Audits – cron‑driven checks against main
|
|
180
|
-
- Webhooks & HTTP – receive events, call APIs, and post results
|
|
181
|
-
- Policy‑as‑Code – schemas + templates for predictable, auditable outputs
|
|
221
|
+
Transform output into an array, run dependents once per item:
|
|
182
222
|
|
|
183
|
-
|
|
223
|
+
```yaml
|
|
224
|
+
steps:
|
|
225
|
+
list-services:
|
|
226
|
+
type: command
|
|
227
|
+
exec: 'echo ''["auth","payments","notifications"]'''
|
|
228
|
+
forEach: true
|
|
184
229
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
- [
|
|
188
|
-
-
|
|
189
|
-
- [Core Concepts (1 minute)](#-core-concepts-1-minute)
|
|
190
|
-
- [Beyond Code Review](#beyond-code-review)
|
|
191
|
-
- [Features](#-features)
|
|
192
|
-
- [When to pick Visor](#when-to-pick-visor)
|
|
193
|
-
- [Developer Experience Playbook](#-developer-experience-playbook)
|
|
194
|
-
- [Tag-Based Check Filtering](#-tag-based-check-filtering)
|
|
195
|
-
- [PR Comment Commands](#-pr-comment-commands)
|
|
196
|
-
- [Enterprise Policy Engine (EE)](#-enterprise-policy-engine-ee)
|
|
197
|
-
- [Suppressing Warnings](#-suppressing-warnings)
|
|
198
|
-
- [Troubleshooting](#-troubleshooting)
|
|
199
|
-
- [Security Defaults](#-security-defaults)
|
|
200
|
-
- [Performance & Cost Controls](#-performance--cost-controls)
|
|
201
|
-
- [Observability](#-observability)
|
|
202
|
-
- [AI Configuration](#-ai-configuration)
|
|
203
|
-
- [Step Dependencies & Intelligent Execution](#-step-dependencies--intelligent-execution)
|
|
204
|
-
- [Failure Routing (Auto-fix Loops)](#-failure-routing-auto-fix-loops)
|
|
205
|
-
- [Claude Code Provider](#-claude-code-provider)
|
|
206
|
-
- [GitHub Provider](#-github-provider)
|
|
207
|
-
- [AI Session Reuse](#-ai-session-reuse)
|
|
208
|
-
- [Schema-Template System](#-schema-template-system)
|
|
209
|
-
- [Enhanced Prompts](#-enhanced-prompts)
|
|
210
|
-
- [SDK (Programmatic Usage)](#-sdk-programmatic-usage)
|
|
211
|
-
- [Debugging](#-debugging)
|
|
212
|
-
- [Advanced Configuration](#-advanced-configuration)
|
|
213
|
-
- [HTTP Integration & Scheduling](#-http-integration--scheduling)
|
|
214
|
-
- [Pluggable Architecture](#-pluggable-architecture)
|
|
215
|
-
- [GitHub Action Reference](#-github-action-reference)
|
|
216
|
-
- [Output Formats](#-output-formats)
|
|
217
|
-
- [Contributing](#-contributing)
|
|
218
|
-
- [Further Reading](#-further-reading)
|
|
219
|
-
- [License](#-license)
|
|
220
|
-
|
|
221
|
-
## ✨ Features
|
|
222
|
-
|
|
223
|
-
- Native GitHub reviews: Check runs, inline annotations, and status reporting wired into PRs.
|
|
224
|
-
- Config‑first: One `.visor.yaml` defines checks, prompts, schemas, and templates — no hidden logic.
|
|
225
|
-
- Structured outputs: JSON Schema validation drives deterministic rendering, annotations, and SARIF.
|
|
226
|
-
- Orchestrated pipelines: Dependencies, parallelism, and tag‑based profiles; run in Actions or any CI.
|
|
227
|
-
- Multi‑provider AI: Google Gemini, Anthropic Claude, OpenAI, AWS Bedrock — plus MCP tools, standalone MCP provider, and Claude Code SDK.
|
|
228
|
-
- Author permissions: Built-in functions to customize workflows based on contributor trust level (owner, member, collaborator, etc).
|
|
229
|
-
- Assistants & commands: `/review` to rerun checks, `/visor …` for Q&A, predictable comment groups.
|
|
230
|
-
- HTTP & schedules: Receive webhooks, call external APIs, and run cron‑scheduled audits and reports.
|
|
231
|
-
- Extensible providers: `ai`, `mcp`, `http`, `http_client`, `log`, `command`, `github`, `claude-code`, `human-input`, `memory` — or add your own.
|
|
232
|
-
- Security by default: GitHub App support, scoped tokens, remote‑extends allowlist, opt‑in network usage.
|
|
233
|
-
- Observability & control: JSON/SARIF outputs, fail‑fast and timeouts, parallelism and cost control.
|
|
234
|
-
|
|
235
|
-
## When to pick Visor
|
|
236
|
-
|
|
237
|
-
- You want native GitHub checks/annotations and config‑driven behavior
|
|
238
|
-
- You need structured outputs (schemas) and predictable templates
|
|
239
|
-
- You care about dependency‑aware execution and tag‑based profiles
|
|
240
|
-
- You want PR reviews + assistants + scheduled audits from one tool
|
|
241
|
-
- You prefer open‑source with no hidden rules
|
|
242
|
-
|
|
243
|
-
## 🧭 Developer Experience Playbook
|
|
244
|
-
|
|
245
|
-
Start with the defaults, iterate locally, and commit a shared `.visor.yaml` for your team.
|
|
246
|
-
|
|
247
|
-
Example:
|
|
248
|
-
```bash
|
|
249
|
-
npx -y @probelabs/visor@latest --check all --debug
|
|
230
|
+
check-service:
|
|
231
|
+
type: command
|
|
232
|
+
exec: 'curl -s https://{{ outputs["list-services"] }}/health'
|
|
233
|
+
depends_on: [list-services]
|
|
250
234
|
```
|
|
251
235
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
## 🏷️ Tag-Based Check Filtering
|
|
236
|
+
Use `outputs_raw` in downstream steps to access the aggregated array of all forEach results:
|
|
255
237
|
|
|
256
|
-
Run subsets of checks (e.g., `local`, `fast`, `security`) and select them per environment with `--tags`/`--exclude-tags`.
|
|
257
|
-
|
|
258
|
-
Example:
|
|
259
238
|
```yaml
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
239
|
+
summarize:
|
|
240
|
+
type: script
|
|
241
|
+
depends_on: [list-services]
|
|
242
|
+
content: |
|
|
243
|
+
const arr = outputs_raw['list-services'] || [];
|
|
244
|
+
return { total: arr.length };
|
|
265
245
|
```
|
|
266
246
|
|
|
267
|
-
|
|
268
|
-
```bash
|
|
269
|
-
visor --tags local,fast
|
|
270
|
-
```
|
|
247
|
+
Learn more: [docs/foreach-dependency-propagation.md](docs/foreach-dependency-propagation.md)
|
|
271
248
|
|
|
272
|
-
|
|
249
|
+
### Failure Routing & Auto-Remediation
|
|
273
250
|
|
|
274
|
-
|
|
251
|
+
Steps can retry, run remediation, or jump to other steps on failure:
|
|
275
252
|
|
|
276
|
-
|
|
253
|
+
```yaml
|
|
254
|
+
version: "2.0"
|
|
255
|
+
routing:
|
|
256
|
+
max_loops: 5
|
|
257
|
+
steps:
|
|
258
|
+
build:
|
|
259
|
+
type: command
|
|
260
|
+
exec: make build
|
|
261
|
+
on_fail:
|
|
262
|
+
retry: { max: 2, backoff: { mode: exponential, delay_ms: 500 } }
|
|
263
|
+
goto: setup # Jump back on exhausted retries
|
|
277
264
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
265
|
+
deploy:
|
|
266
|
+
type: command
|
|
267
|
+
exec: make deploy
|
|
268
|
+
depends_on: [build]
|
|
269
|
+
on_success:
|
|
270
|
+
run: [notify] # Run extra steps on success
|
|
271
|
+
on_fail:
|
|
272
|
+
goto_js: |
|
|
273
|
+
return attempt <= 2 ? 'build' : null; # Dynamic routing
|
|
283
274
|
```
|
|
284
275
|
|
|
285
|
-
Learn more: [docs/
|
|
286
|
-
|
|
287
|
-
## 🔐 Author Permissions
|
|
276
|
+
Learn more: [docs/failure-routing.md](docs/failure-routing.md)
|
|
288
277
|
|
|
289
|
-
|
|
278
|
+
### Conditional Execution & Author Permissions
|
|
290
279
|
|
|
291
280
|
```yaml
|
|
292
281
|
steps:
|
|
293
|
-
# Run security scan only for external contributors
|
|
294
282
|
security-scan:
|
|
295
283
|
type: command
|
|
296
|
-
exec: npm
|
|
297
|
-
if: "!hasMinPermission('MEMBER')"
|
|
284
|
+
exec: npm audit
|
|
285
|
+
if: "!hasMinPermission('MEMBER')" # Only for external contributors
|
|
298
286
|
|
|
299
|
-
# Auto-approve PRs from collaborators
|
|
300
287
|
auto-approve:
|
|
301
|
-
type:
|
|
302
|
-
|
|
288
|
+
type: github
|
|
289
|
+
op: labels.add
|
|
290
|
+
values: ["approved"]
|
|
303
291
|
if: "hasMinPermission('COLLABORATOR') && totalIssues === 0"
|
|
304
292
|
|
|
305
|
-
# Block sensitive file changes from non-members
|
|
306
293
|
protect-secrets:
|
|
307
294
|
type: command
|
|
308
295
|
exec: echo "Checking permissions..."
|
|
309
296
|
fail_if: "!isMember() && files.some(f => f.filename.startsWith('secrets/'))"
|
|
310
297
|
```
|
|
311
298
|
|
|
312
|
-
|
|
313
|
-
- `hasMinPermission(level)` - Check if author has >= permission level
|
|
314
|
-
- `isOwner()`, `isMember()`, `isCollaborator()`, `isContributor()`, `isFirstTimer()` - Boolean checks
|
|
299
|
+
Available permission functions: `hasMinPermission(level)`, `isOwner()`, `isMember()`, `isCollaborator()`, `isContributor()`, `isFirstTimer()`.
|
|
315
300
|
|
|
316
301
|
Learn more: [docs/author-permissions.md](docs/author-permissions.md)
|
|
317
302
|
|
|
318
|
-
##
|
|
319
|
-
|
|
320
|
-
> **Enterprise Edition feature.** Requires a Visor EE license. Contact **hello@probelabs.com**.
|
|
303
|
+
## 🤖 AI & MCP
|
|
321
304
|
|
|
322
|
-
|
|
305
|
+
### Multi-Provider AI
|
|
323
306
|
|
|
324
307
|
```yaml
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
```
|
|
335
|
-
|
|
336
|
-
Checks denied by policy are skipped with reason `policy_denied`. Without a valid license, the engine silently disables and all checks run normally.
|
|
337
|
-
|
|
338
|
-
Learn more: [docs/enterprise-policy.md](docs/enterprise-policy.md) | [examples/enterprise-policy/](examples/enterprise-policy/)
|
|
339
|
-
|
|
340
|
-
## 🔇 Suppressing Warnings
|
|
341
|
-
|
|
342
|
-
Suppress a specific issue by adding a nearby `visor-disable` comment.
|
|
343
|
-
|
|
344
|
-
Example (JS):
|
|
345
|
-
```js
|
|
346
|
-
const testPassword = "demo123"; // visor-disable
|
|
347
|
-
```
|
|
348
|
-
|
|
349
|
-
Learn more: [docs/suppressions.md](docs/suppressions.md)
|
|
350
|
-
|
|
351
|
-
## 🛠️ Troubleshooting
|
|
352
|
-
|
|
353
|
-
If comments/annotations don’t appear, verify workflow permissions and run with `--debug`.
|
|
354
|
-
|
|
355
|
-
Example:
|
|
356
|
-
```bash
|
|
357
|
-
node dist/index.js --cli --check all --debug
|
|
308
|
+
steps:
|
|
309
|
+
review:
|
|
310
|
+
type: ai
|
|
311
|
+
prompt: "Review this code for security issues"
|
|
312
|
+
ai:
|
|
313
|
+
provider: anthropic # or: google, openai, bedrock
|
|
314
|
+
model: claude-sonnet-4-20250514
|
|
315
|
+
fallback:
|
|
316
|
+
strategy: any # Try other providers on failure
|
|
358
317
|
```
|
|
359
318
|
|
|
360
|
-
|
|
319
|
+
Supported providers: **Google Gemini**, **Anthropic Claude**, **OpenAI GPT**, **AWS Bedrock**.
|
|
361
320
|
|
|
362
|
-
|
|
363
|
-
- For GitHub-specific behavior (comments, checks), run with `--mode github-actions` or set `with: mode: github-actions` when using the GitHub Action.
|
|
321
|
+
Set one key via environment: `GOOGLE_API_KEY`, `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, or AWS credentials.
|
|
364
322
|
|
|
365
|
-
|
|
323
|
+
### MCP Tool Integration
|
|
366
324
|
|
|
367
|
-
|
|
368
|
-
# Local/CI CLI
|
|
369
|
-
npx -y @probelabs/visor@latest --config .visor.yaml --check all --output json
|
|
370
|
-
|
|
371
|
-
# GitHub Actions behavior from any shell/CI
|
|
372
|
-
npx -y @probelabs/visor@latest --mode github-actions --config .visor.yaml --check all
|
|
373
|
-
```
|
|
374
|
-
|
|
375
|
-
GitHub Action usage:
|
|
376
|
-
|
|
377
|
-
```yaml
|
|
378
|
-
- uses: probelabs/visor@vX
|
|
379
|
-
with:
|
|
380
|
-
mode: github-actions
|
|
381
|
-
checks: all
|
|
382
|
-
output-format: json
|
|
383
|
-
```
|
|
384
|
-
|
|
385
|
-
To force CLI mode inside a GitHub Action step, you can still use:
|
|
325
|
+
Give AI steps access to MCP tools, or call MCP tools directly:
|
|
386
326
|
|
|
387
327
|
```yaml
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
Examples:
|
|
399
|
-
```bash
|
|
400
|
-
visor --no-remote-extends
|
|
401
|
-
visor --allowed-remote-patterns "https://raw.githubusercontent.com/myorg/"
|
|
402
|
-
```
|
|
403
|
-
|
|
404
|
-
Learn more: [docs/security.md](docs/security.md)
|
|
405
|
-
|
|
406
|
-
## ⚡ Performance & Cost Controls
|
|
407
|
-
|
|
408
|
-
Use tags for fast lanes and raise parallelism cautiously.
|
|
328
|
+
# AI step with MCP tools
|
|
329
|
+
steps:
|
|
330
|
+
analyze:
|
|
331
|
+
type: ai
|
|
332
|
+
prompt: "Use the search tool to find security patterns"
|
|
333
|
+
ai:
|
|
334
|
+
mcp_servers:
|
|
335
|
+
- name: code-search
|
|
336
|
+
command: npx
|
|
337
|
+
args: ["-y", "@probe/search"]
|
|
409
338
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
339
|
+
# Direct MCP tool execution
|
|
340
|
+
search:
|
|
341
|
+
type: mcp
|
|
342
|
+
transport: stdio
|
|
343
|
+
command: npx
|
|
344
|
+
args: ["-y", "@probe/search"]
|
|
345
|
+
method: search
|
|
346
|
+
arguments:
|
|
347
|
+
query: "{{ outputs['setup'].pattern }}"
|
|
413
348
|
```
|
|
414
349
|
|
|
415
|
-
|
|
350
|
+
### AI Session Reuse
|
|
416
351
|
|
|
417
|
-
|
|
352
|
+
Chain AI conversations across steps:
|
|
418
353
|
|
|
419
|
-
|
|
354
|
+
```yaml
|
|
355
|
+
steps:
|
|
356
|
+
security:
|
|
357
|
+
type: ai
|
|
358
|
+
prompt: "Find security issues"
|
|
420
359
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
360
|
+
remediation:
|
|
361
|
+
type: ai
|
|
362
|
+
prompt: "Suggest fixes for the issues you found"
|
|
363
|
+
depends_on: [security]
|
|
364
|
+
reuse_ai_session: true # Carries conversation history
|
|
365
|
+
session_mode: append # Or: clone (default)
|
|
425
366
|
```
|
|
426
367
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
## 🤖 AI Configuration
|
|
368
|
+
### Claude Code Provider
|
|
430
369
|
|
|
431
|
-
|
|
370
|
+
Full Claude Code SDK integration with MCP tools and subagents:
|
|
432
371
|
|
|
433
|
-
Example (Action):
|
|
434
372
|
```yaml
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
373
|
+
steps:
|
|
374
|
+
deep-review:
|
|
375
|
+
type: claude-code
|
|
376
|
+
prompt: "Analyze code complexity and suggest refactoring"
|
|
377
|
+
max_turns: 10
|
|
378
|
+
mcp_servers:
|
|
379
|
+
- name: filesystem
|
|
380
|
+
command: npx
|
|
381
|
+
args: ["-y", "@modelcontextprotocol/server-filesystem", "."]
|
|
442
382
|
```
|
|
443
383
|
|
|
444
|
-
Learn more: [docs/
|
|
384
|
+
Learn more: [docs/claude-code.md](docs/claude-code.md) · [docs/mcp-provider.md](docs/mcp-provider.md) · [docs/advanced-ai.md](docs/advanced-ai.md)
|
|
445
385
|
|
|
446
|
-
##
|
|
386
|
+
## 🧰 GitHub Provider
|
|
447
387
|
|
|
448
|
-
|
|
388
|
+
Native GitHub operations (labels, comments, checks) without shelling out to `gh`:
|
|
449
389
|
|
|
450
|
-
Example:
|
|
451
390
|
```yaml
|
|
452
391
|
steps:
|
|
453
|
-
|
|
454
|
-
|
|
392
|
+
apply-labels:
|
|
393
|
+
type: github
|
|
394
|
+
op: labels.add
|
|
395
|
+
values:
|
|
396
|
+
- "{{ outputs.overview.tags.label | default: '' | safe_label }}"
|
|
397
|
+
value_js: |
|
|
398
|
+
return values.filter(v => typeof v === 'string' && v.trim().length > 0);
|
|
455
399
|
```
|
|
456
400
|
|
|
457
|
-
Learn more: [docs/
|
|
401
|
+
Learn more: [docs/github-ops.md](docs/github-ops.md)
|
|
458
402
|
|
|
459
|
-
|
|
403
|
+
## 🧬 Templating & Transforms
|
|
460
404
|
|
|
461
|
-
|
|
462
|
-
version: "2.0"
|
|
463
|
-
checks:
|
|
464
|
-
list:
|
|
465
|
-
type: command
|
|
466
|
-
exec: echo '["a","b","c"]'
|
|
467
|
-
forEach: true
|
|
405
|
+
### Liquid Templates
|
|
468
406
|
|
|
469
|
-
|
|
470
|
-
type: script
|
|
471
|
-
depends_on: [list]
|
|
472
|
-
content: |
|
|
473
|
-
const arr = outputs_raw['list'] || [];
|
|
474
|
-
return { total: arr.length };
|
|
407
|
+
Steps can use Liquid templates in prompts, exec commands, HTTP bodies, and more:
|
|
475
408
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
goto_js: |
|
|
482
|
-
return (outputs_raw['list'] || []).length >= 3 ? 'after' : null;
|
|
409
|
+
```yaml
|
|
410
|
+
steps:
|
|
411
|
+
greet:
|
|
412
|
+
type: command
|
|
413
|
+
exec: 'echo "Files changed: {{ files | size }}, branch: {{ branch }}"'
|
|
483
414
|
|
|
484
|
-
|
|
485
|
-
type:
|
|
486
|
-
|
|
415
|
+
post-results:
|
|
416
|
+
type: http
|
|
417
|
+
url: https://api.example.com/results
|
|
418
|
+
body: |
|
|
419
|
+
{ "issues": {{ outputs["review"] | json }},
|
|
420
|
+
"pr": {{ pr.number }} }
|
|
487
421
|
```
|
|
488
422
|
|
|
489
|
-
|
|
423
|
+
Available context: `outputs`, `outputs_raw`, `inputs`, `pr`, `files`, `env`, `memory`, `branch`, `event`, `conversation`.
|
|
490
424
|
|
|
491
|
-
|
|
425
|
+
### JavaScript Transforms
|
|
492
426
|
|
|
493
|
-
|
|
494
|
-
- `retry` with fixed/exponential backoff (+ deterministic jitter)
|
|
495
|
-
- `run`: remediation steps (single or list)
|
|
496
|
-
- `goto`: jump back to an ancestor step and continue forward
|
|
497
|
-
- `goto_js` / `run_js`: dynamic routing with safe, synchronous JS
|
|
498
|
-
- Loop safety:
|
|
499
|
-
- Global `routing.max_loops` per scope to prevent livelock
|
|
500
|
-
- Per‑step attempt counters; forEach items have isolated counters
|
|
427
|
+
Transform step output before passing to dependents:
|
|
501
428
|
|
|
502
|
-
Example (retry + goto on failure):
|
|
503
429
|
```yaml
|
|
504
|
-
version: "2.0"
|
|
505
|
-
routing:
|
|
506
|
-
max_loops: 5
|
|
507
430
|
steps:
|
|
508
|
-
|
|
509
|
-
build:
|
|
431
|
+
fetch:
|
|
510
432
|
type: command
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
echo ok
|
|
515
|
-
on_fail:
|
|
516
|
-
goto: setup
|
|
517
|
-
retry: { max: 1, backoff: { mode: exponential, delay_ms: 400 } }
|
|
433
|
+
exec: 'node -e "console.log(JSON.stringify({items:[1,2,3]}))"'
|
|
434
|
+
transform_js: |
|
|
435
|
+
return output.items.filter(i => i > 1);
|
|
518
436
|
```
|
|
519
437
|
|
|
520
|
-
|
|
438
|
+
### Dynamic Routing with JavaScript
|
|
439
|
+
|
|
521
440
|
```yaml
|
|
522
441
|
steps:
|
|
523
|
-
|
|
524
|
-
build:
|
|
442
|
+
check:
|
|
525
443
|
type: command
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
on_success:
|
|
529
|
-
run: [notify]
|
|
444
|
+
exec: npm test
|
|
445
|
+
on_fail:
|
|
530
446
|
goto_js: |
|
|
531
|
-
|
|
532
|
-
return
|
|
533
|
-
notify: { type: command, exec: "echo notify" }
|
|
447
|
+
if (attempt > 3) return null; // Give up
|
|
448
|
+
return 'fix-and-retry'; // Jump to remediation
|
|
534
449
|
```
|
|
535
450
|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
## 🤖 Claude Code Provider
|
|
451
|
+
Prompts can live in external files with full Liquid variable access:
|
|
539
452
|
|
|
540
|
-
Use the Claude Code SDK as a provider for deeper analysis.
|
|
541
|
-
|
|
542
|
-
Example:
|
|
543
453
|
```yaml
|
|
544
454
|
steps:
|
|
545
|
-
|
|
546
|
-
type:
|
|
547
|
-
|
|
455
|
+
overview:
|
|
456
|
+
type: ai
|
|
457
|
+
schema: code-review
|
|
458
|
+
prompt: ./prompts/overview.liquid
|
|
548
459
|
```
|
|
549
460
|
|
|
550
|
-
Learn more: [docs/
|
|
551
|
-
|
|
552
|
-
## 🔄 AI Session Reuse
|
|
461
|
+
Learn more: [docs/liquid-templates.md](docs/liquid-templates.md) · [docs/schema-templates.md](docs/schema-templates.md)
|
|
553
462
|
|
|
554
|
-
|
|
463
|
+
## 🔇 Suppressing Warnings
|
|
555
464
|
|
|
556
|
-
|
|
557
|
-
- **`clone` (default)**: Independent copy of history for parallel follow-ups
|
|
558
|
-
- **`append`**: Shared conversation thread for sequential multi-turn dialogue
|
|
465
|
+
Suppress a specific issue by adding a nearby `visor-disable` comment:
|
|
559
466
|
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
steps:
|
|
563
|
-
security: { type: ai }
|
|
564
|
-
remediation:
|
|
565
|
-
type: ai
|
|
566
|
-
depends_on: [security]
|
|
567
|
-
reuse_ai_session: true # Clones history by default
|
|
568
|
-
verify:
|
|
569
|
-
type: ai
|
|
570
|
-
depends_on: [remediation]
|
|
571
|
-
reuse_ai_session: true
|
|
572
|
-
session_mode: append # Shares history for full conversation
|
|
467
|
+
```js
|
|
468
|
+
const testPassword = "demo123"; // visor-disable
|
|
573
469
|
```
|
|
574
470
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
- `reuse_ai_session: "self"` with `session_mode: append`
|
|
578
|
-
|
|
579
|
-
See the standalone example at `examples/session-reuse-self.yaml` and the detailed guide in [docs/advanced-ai.md](docs/advanced-ai.md).
|
|
580
|
-
|
|
581
|
-
Learn more: [docs/advanced-ai.md](docs/advanced-ai.md)
|
|
471
|
+
Learn more: [docs/suppressions.md](docs/suppressions.md)
|
|
582
472
|
|
|
583
|
-
##
|
|
473
|
+
## 🧪 Testing Framework
|
|
584
474
|
|
|
585
|
-
|
|
475
|
+
Write and run integration tests for your Visor config in YAML:
|
|
586
476
|
|
|
587
|
-
Example:
|
|
588
477
|
```yaml
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
478
|
+
# .visor.tests.yaml
|
|
479
|
+
tests:
|
|
480
|
+
- name: "Security check finds issues"
|
|
481
|
+
config: .visor.yaml
|
|
482
|
+
steps:
|
|
483
|
+
security:
|
|
484
|
+
mock_output: '{"issues": [{"severity": "high"}]}'
|
|
485
|
+
assertions:
|
|
486
|
+
- step: security
|
|
487
|
+
called: { exactly: 1 }
|
|
488
|
+
- step: security
|
|
489
|
+
output_contains: "high"
|
|
594
490
|
```
|
|
595
491
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
Example:
|
|
603
|
-
```yaml
|
|
604
|
-
steps:
|
|
605
|
-
overview:
|
|
606
|
-
type: ai
|
|
607
|
-
prompt: ./prompts/overview.liquid
|
|
492
|
+
```bash
|
|
493
|
+
visor test --progress compact # Run tests
|
|
494
|
+
visor test --list # List test cases
|
|
495
|
+
visor test --only "Security*" # Filter tests
|
|
496
|
+
visor test --bail # Stop on first failure
|
|
608
497
|
```
|
|
609
498
|
|
|
610
|
-
|
|
499
|
+
Docs: [Getting started](docs/testing/getting-started.md) · [DSL reference](docs/testing/dsl-reference.md) · [Fixtures & mocks](docs/testing/fixtures-and-mocks.md) · [Assertions](docs/testing/assertions.md) · [Cookbook](docs/testing/cookbook.md)
|
|
611
500
|
|
|
612
501
|
## 📦 SDK (Programmatic Usage)
|
|
613
502
|
|
|
614
|
-
Run Visor programmatically from Node.js
|
|
615
|
-
|
|
616
|
-
**Install:**
|
|
617
|
-
```bash
|
|
618
|
-
npm i -D @probelabs/visor
|
|
619
|
-
```
|
|
503
|
+
Run Visor programmatically from Node.js:
|
|
620
504
|
|
|
621
|
-
**ESM Example:**
|
|
622
505
|
```ts
|
|
623
506
|
import { loadConfig, runChecks } from '@probelabs/visor/sdk';
|
|
624
507
|
|
|
625
|
-
const config = await loadConfig();
|
|
508
|
+
const config = await loadConfig('.visor.yaml');
|
|
626
509
|
const result = await runChecks({
|
|
627
510
|
config,
|
|
628
511
|
checks: Object.keys(config.checks || {}),
|
|
629
512
|
output: { format: 'json' },
|
|
630
513
|
});
|
|
631
|
-
console.log('
|
|
514
|
+
console.log('Issues:', result.reviewSummary.issues?.length ?? 0);
|
|
632
515
|
```
|
|
633
516
|
|
|
634
|
-
**CommonJS Example:**
|
|
635
|
-
```js
|
|
636
|
-
const { loadConfig, runChecks } = require('@probelabs/visor/sdk');
|
|
637
|
-
(async () => {
|
|
638
|
-
const config = await loadConfig();
|
|
639
|
-
const result = await runChecks({
|
|
640
|
-
config,
|
|
641
|
-
checks: Object.keys(config.checks || {}),
|
|
642
|
-
output: { format: 'json' }
|
|
643
|
-
});
|
|
644
|
-
console.log('Total issues:', result.reviewSummary.issues?.length ?? 0);
|
|
645
|
-
})();
|
|
646
|
-
```
|
|
647
|
-
|
|
648
|
-
**Key Functions:**
|
|
649
|
-
- `loadConfig(configPath?: string)` — Load Visor config
|
|
650
|
-
- `resolveChecks(checkIds, config)` — Expand check IDs with dependencies
|
|
651
|
-
- `runChecks(options)` — Run checks programmatically
|
|
652
|
-
|
|
653
517
|
Learn more: [docs/sdk.md](docs/sdk.md)
|
|
654
518
|
|
|
655
|
-
##
|
|
519
|
+
## 🔧 Configuration
|
|
656
520
|
|
|
657
|
-
|
|
521
|
+
### Config Loading Order
|
|
522
|
+
1. CLI `--config` flag
|
|
523
|
+
2. `.visor.yaml` in project root
|
|
524
|
+
3. Built-in defaults
|
|
658
525
|
|
|
659
|
-
###
|
|
526
|
+
### Extending Configs
|
|
660
527
|
|
|
661
|
-
```
|
|
662
|
-
|
|
663
|
-
|
|
528
|
+
```yaml
|
|
529
|
+
extends:
|
|
530
|
+
- default
|
|
531
|
+
- ./team-standards.yaml
|
|
532
|
+
- https://raw.githubusercontent.com/org/policies/main/base.yaml
|
|
533
|
+
```
|
|
664
534
|
|
|
665
|
-
|
|
666
|
-
visor --tui --config ./examples/calculator-config.yaml
|
|
535
|
+
### Dynamic Config Reloading
|
|
667
536
|
|
|
668
|
-
|
|
669
|
-
visor --debug-server --debug-port 3456
|
|
537
|
+
Long-running modes (Slack, HTTP) support live config reload:
|
|
670
538
|
|
|
671
|
-
|
|
672
|
-
visor --
|
|
539
|
+
```bash
|
|
540
|
+
visor --slack --config .visor.yaml --watch # Auto-reload on file change
|
|
541
|
+
visor config snapshots # List config versions
|
|
542
|
+
visor config diff 1 2 # Diff two snapshots
|
|
673
543
|
```
|
|
674
544
|
|
|
675
|
-
|
|
676
|
-
- Chat-style interface with persistent input bar
|
|
677
|
-
- Press `Tab` to switch between Chat and Logs tabs
|
|
678
|
-
- Re-run workflows by typing new messages after completion
|
|
679
|
-
- Press `q` to exit when done
|
|
545
|
+
### Key Config Options
|
|
680
546
|
|
|
681
|
-
### Quick Debugging Tips
|
|
682
|
-
|
|
683
|
-
**Use `log()` in JavaScript expressions:**
|
|
684
547
|
```yaml
|
|
548
|
+
version: "1.0"
|
|
549
|
+
max_parallelism: 3 # Concurrent steps
|
|
550
|
+
max_ai_concurrency: 3 # Concurrent AI API calls
|
|
551
|
+
routing:
|
|
552
|
+
max_loops: 10 # Loop safety limit
|
|
553
|
+
|
|
554
|
+
http_server:
|
|
555
|
+
enabled: true
|
|
556
|
+
port: 8080
|
|
557
|
+
auth: { bearer_token: "${WEBHOOK_SECRET}" }
|
|
558
|
+
|
|
559
|
+
telemetry:
|
|
560
|
+
enabled: true
|
|
561
|
+
sink: otlp # or: file, console
|
|
562
|
+
|
|
685
563
|
steps:
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
564
|
+
# ... your pipeline
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
Learn more: [docs/configuration.md](docs/configuration.md)
|
|
568
|
+
|
|
569
|
+
## 👀 Observability
|
|
570
|
+
|
|
571
|
+
### Output Formats
|
|
572
|
+
|
|
573
|
+
```bash
|
|
574
|
+
visor --output table # Terminal-friendly (default)
|
|
575
|
+
visor --output json --output-file results.json
|
|
576
|
+
visor --output sarif --output-file results.sarif
|
|
577
|
+
visor --output markdown
|
|
694
578
|
```
|
|
695
579
|
|
|
696
|
-
|
|
580
|
+
### OpenTelemetry Tracing
|
|
581
|
+
|
|
697
582
|
```yaml
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
message: |
|
|
702
|
-
Outputs: {{ outputs | json }}
|
|
703
|
-
PR: {{ pr | json }}
|
|
583
|
+
telemetry:
|
|
584
|
+
enabled: true
|
|
585
|
+
sink: otlp
|
|
704
586
|
```
|
|
705
587
|
|
|
706
|
-
**Enable debug mode:**
|
|
707
588
|
```bash
|
|
708
|
-
visor --check all
|
|
589
|
+
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://localhost:4318/v1/traces visor --check all
|
|
709
590
|
```
|
|
710
591
|
|
|
711
|
-
|
|
592
|
+
Span hierarchy: `visor.run` → `engine.state.*` → `visor.check.*` → `visor.foreach.item`
|
|
712
593
|
|
|
713
|
-
|
|
594
|
+
### Debug Tools
|
|
714
595
|
|
|
715
|
-
|
|
596
|
+
```bash
|
|
597
|
+
visor --debug # Verbose logging
|
|
598
|
+
visor --debug-server --debug-port 3456 # Live web visualizer
|
|
599
|
+
```
|
|
716
600
|
|
|
717
|
-
|
|
601
|
+
**Quick debugging tips:**
|
|
602
|
+
|
|
603
|
+
Use `log()` in JavaScript expressions (`if`, `fail_if`, `transform_js`):
|
|
718
604
|
```yaml
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
-
|
|
605
|
+
if: |
|
|
606
|
+
log("Outputs:", outputs);
|
|
607
|
+
outputs["fetch-data"]?.status === "ready"
|
|
722
608
|
```
|
|
723
609
|
|
|
724
|
-
|
|
610
|
+
Use the `json` filter in Liquid to inspect objects:
|
|
611
|
+
```yaml
|
|
612
|
+
type: logger
|
|
613
|
+
message: "Outputs: {{ outputs | json }}"
|
|
614
|
+
```
|
|
725
615
|
|
|
726
|
-
|
|
616
|
+
**TUI mode** (`visor --tui`): Press `Tab` to switch between Chat and Logs tabs, `q` to exit.
|
|
727
617
|
|
|
728
|
-
|
|
618
|
+
Learn more: [docs/observability.md](docs/observability.md) · [docs/debugging.md](docs/debugging.md) · [docs/debug-visualizer.md](docs/debug-visualizer.md)
|
|
729
619
|
|
|
730
|
-
|
|
731
|
-
```yaml
|
|
732
|
-
http_server: { enabled: true, port: 8080 }
|
|
733
|
-
steps:
|
|
734
|
-
nightly: { type: ai, schedule: "0 2 * * *" }
|
|
735
|
-
```
|
|
620
|
+
## 🔐 Security
|
|
736
621
|
|
|
737
|
-
|
|
622
|
+
- **GitHub App support** for scoped, auditable access
|
|
623
|
+
- **Remote extends allowlist** to control external config sources
|
|
624
|
+
- **MCP method filtering** — allow/deny lists with wildcards
|
|
625
|
+
- **Bash allow/deny patterns** for AI-driven command execution
|
|
626
|
+
- **Docker & process sandboxes** for isolated step execution
|
|
627
|
+
- **Author permissions** — `hasMinPermission()`, `isMember()`, etc. for role-based logic
|
|
628
|
+
- **Environment filtering** — control which env vars steps can access
|
|
738
629
|
|
|
739
|
-
|
|
630
|
+
```bash
|
|
631
|
+
visor --no-remote-extends
|
|
632
|
+
visor --allowed-remote-patterns "https://raw.githubusercontent.com/myorg/"
|
|
633
|
+
```
|
|
740
634
|
|
|
741
|
-
|
|
635
|
+
Learn more: [docs/security.md](docs/security.md) · [docs/author-permissions.md](docs/author-permissions.md)
|
|
742
636
|
|
|
743
|
-
|
|
744
|
-
- **Script Provider**: Run JavaScript in a secure sandbox - [docs/script.md](docs/script.md)
|
|
745
|
-
- **MCP Provider**: Call MCP tools directly via stdio, SSE, or HTTP transports - [docs/mcp-provider.md](docs/mcp-provider.md)
|
|
746
|
-
- **MCP Tools for AI**: Enhance AI providers with MCP context - [docs/mcp.md](docs/mcp.md)
|
|
747
|
-
- **Custom Providers**: Build your own providers - [docs/pluggable.md](docs/pluggable.md)
|
|
637
|
+
## 🏢 Enterprise Policy Engine (EE)
|
|
748
638
|
|
|
749
|
-
|
|
639
|
+
> **Enterprise Edition.** Requires a Visor EE license. Contact **hello@probelabs.com**.
|
|
750
640
|
|
|
751
|
-
|
|
641
|
+
OPA-based policy enforcement for gating checks, MCP tools, and AI capabilities:
|
|
752
642
|
|
|
753
|
-
Example:
|
|
754
643
|
```yaml
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
644
|
+
policy:
|
|
645
|
+
engine: local
|
|
646
|
+
rules: ./policies/
|
|
647
|
+
fallback: deny
|
|
648
|
+
roles:
|
|
649
|
+
admin: { author_association: [OWNER] }
|
|
650
|
+
developer: { author_association: [MEMBER, COLLABORATOR] }
|
|
758
651
|
```
|
|
759
652
|
|
|
760
|
-
Learn more: [docs/
|
|
653
|
+
Learn more: [docs/enterprise-policy.md](docs/enterprise-policy.md)
|
|
761
654
|
|
|
762
|
-
##
|
|
655
|
+
## 📚 Further Reading
|
|
763
656
|
|
|
764
|
-
|
|
657
|
+
**Guides:**
|
|
658
|
+
[CLI commands](docs/commands.md) · [Configuration](docs/configuration.md) · [AI config](docs/ai-configuration.md) · [Dependencies](docs/dependencies.md) · [forEach propagation](docs/foreach-dependency-propagation.md) · [Failure routing](docs/failure-routing.md) · [Liquid templates](docs/liquid-templates.md) · [Schema-template system](docs/schema-templates.md) · [Fail conditions](docs/fail-if.md) · [Timeouts](docs/timeouts.md) · [Execution limits](docs/limits.md) · [Output formats](docs/output-formats.md) · [Output formatting](docs/output-formatting.md) · [HTTP integration](docs/http.md) · [Scheduler](docs/scheduler.md)
|
|
765
659
|
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
visor --check security --output json
|
|
769
|
-
```
|
|
660
|
+
**Providers:**
|
|
661
|
+
[Command](docs/command-provider.md) · [Script](docs/script.md) · [MCP](docs/mcp-provider.md) · [MCP tools for AI](docs/mcp.md) · [Claude Code](docs/claude-code.md) · [GitHub ops](docs/github-ops.md) · [Custom providers](docs/pluggable.md)
|
|
770
662
|
|
|
771
|
-
|
|
663
|
+
**Operations:**
|
|
664
|
+
[GitHub Action reference](docs/action-reference.md) · [Security](docs/security.md) · [Performance](docs/performance.md) · [Observability](docs/observability.md) · [Debugging](docs/debugging.md) · [Debug visualizer](docs/debug-visualizer.md) · [Troubleshooting](docs/troubleshooting.md) · [Suppressions](docs/suppressions.md) · [GitHub checks](docs/GITHUB_CHECKS.md)
|
|
772
665
|
|
|
773
|
-
|
|
666
|
+
**Architecture:**
|
|
667
|
+
[Failure conditions schema](docs/failure-conditions-schema.md) · [Failure conditions implementation](docs/failure-conditions-implementation.md)
|
|
774
668
|
|
|
775
|
-
|
|
669
|
+
**Testing:**
|
|
670
|
+
[Getting started](docs/testing/getting-started.md) · [DSL reference](docs/testing/dsl-reference.md) · [Flows](docs/testing/flows.md) · [Fixtures & mocks](docs/testing/fixtures-and-mocks.md) · [Assertions](docs/testing/assertions.md) · [Cookbook](docs/testing/cookbook.md) · [CLI & reporters](docs/testing/cli.md) · [CI integration](docs/testing/ci.md) · [Troubleshooting](docs/testing/troubleshooting.md)
|
|
776
671
|
|
|
777
|
-
|
|
672
|
+
**Recipes & examples:**
|
|
673
|
+
[Recipes](docs/recipes.md) · [Dev playbook](docs/dev-playbook.md) · [Tag filtering](docs/tag-filtering.md) · [Author permissions](docs/author-permissions.md) · [Session reuse](docs/advanced-ai.md)
|
|
778
674
|
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
- ForEach outputs and precedence (outputs vs outputs_raw vs history): [docs/foreach-dependency-propagation.md](docs/foreach-dependency-propagation.md)
|
|
783
|
-
- Failure routing and on_finish aggregation (with outputs_raw in routing): [docs/failure-routing.md](docs/failure-routing.md)
|
|
784
|
-
- Example config using outputs_raw: examples/outputs-raw-basic.yaml
|
|
675
|
+
## 🤝 Contributing
|
|
676
|
+
|
|
677
|
+
Learn more: [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
785
678
|
|
|
786
679
|
## 📄 License
|
|
787
680
|
|
|
@@ -792,32 +685,3 @@ MIT License — see [LICENSE](LICENSE)
|
|
|
792
685
|
<div align="center">
|
|
793
686
|
Made with ❤️ by <a href="https://probelabs.com">Probe Labs</a>
|
|
794
687
|
</div>
|
|
795
|
-
## 🧰 GitHub Provider
|
|
796
|
-
|
|
797
|
-
Use the native GitHub provider for safe labels and comments without invoking the `gh` CLI.
|
|
798
|
-
|
|
799
|
-
Example — apply overview‑derived labels to a PR:
|
|
800
|
-
|
|
801
|
-
```yaml
|
|
802
|
-
steps:
|
|
803
|
-
apply-overview-labels:
|
|
804
|
-
type: github
|
|
805
|
-
op: labels.add
|
|
806
|
-
values:
|
|
807
|
-
- "{{ outputs.overview.tags.label | default: '' | safe_label }}"
|
|
808
|
-
- "{{ outputs.overview.tags['review-effort'] | default: '' | prepend: 'review/effort:' | safe_label }}"
|
|
809
|
-
value_js: |
|
|
810
|
-
return values.filter(v => typeof v === 'string' && v.trim().length > 0);
|
|
811
|
-
```
|
|
812
|
-
|
|
813
|
-
See docs: docs/github-ops.md
|
|
814
|
-
## Integration Tests
|
|
815
|
-
|
|
816
|
-
Visor ships a YAML‑native integration test runner so you can describe user flows, mocks, and assertions alongside your config.
|
|
817
|
-
|
|
818
|
-
- Start here: docs/testing/getting-started.md
|
|
819
|
-
- CLI details: docs/testing/cli.md
|
|
820
|
-
- Fixtures and mocks: docs/testing/fixtures-and-mocks.md
|
|
821
|
-
- Assertions reference: docs/testing/assertions.md
|
|
822
|
-
|
|
823
|
-
Example suite: defaults/.visor.tests.yaml
|