https://github.com/probelabs/visor
Visor — AI workflow engine for code review, assistants, and automation. Orchestrates checks, MCP tools, and AI providers with YAML-driven pipelines. Runs as GitHub Action, CLI, Slack bot, or HTTP API.
https://github.com/probelabs/visor
ai ai-agents automation cli code-review github-actions mcp slack-bot typescript workflow-engine
Last synced: 4 months ago
JSON representation
Visor — AI workflow engine for code review, assistants, and automation. Orchestrates checks, MCP tools, and AI providers with YAML-driven pipelines. Runs as GitHub Action, CLI, Slack bot, or HTTP API.
- Host: GitHub
- URL: https://github.com/probelabs/visor
- Owner: probelabs
- License: mit
- Created: 2025-09-04T19:02:47.000Z (10 months ago)
- Default Branch: main
- Last Pushed: 2026-03-04T13:06:37.000Z (4 months ago)
- Last Synced: 2026-03-04T13:08:09.039Z (4 months ago)
- Topics: ai, ai-agents, automation, cli, code-review, github-actions, mcp, slack-bot, typescript, workflow-engine
- Language: TypeScript
- Homepage: https://probelabs.com/visor
- Size: 174 MB
- Stars: 16
- Watchers: 0
- Forks: 1
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Security: docs/security.md
- Roadmap: docs/roadmap/criticality-implementation-tasks.md
Awesome Lists containing this project
README
# Visor — AI workflow engine for code review, assistants & automation
[](https://www.typescriptlang.org/)
[](https://nodejs.org/)
[](LICENSE)
Orchestrate checks, MCP tools, and AI providers with YAML-driven pipelines.
Runs as GitHub Action, CLI, Slack bot, or HTTP API.
---
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.
**What you get out of the box:**
- **YAML-driven pipelines** — define checks, transforms, routing, and AI prompts in a single config file.
- **4 runtime modes** — CLI, GitHub Action, Slack bot, HTTP server — same config, any surface.
- **12+ provider types** — `ai`, `command`, `script`, `mcp`, `http`, `claude-code`, `github`, `memory`, `workflow`, and more.
- **AI orchestration** — multi-provider (Gemini, Claude, OpenAI, Bedrock), session reuse, MCP tool calling, retry & fallback.
- **Execution engine** — dependency DAGs, parallel waves, forEach fan-out, conditional routing, failure auto-remediation.
- **Built-in testing** — YAML-native integration tests with fixtures, mocks, and assertions.
## Table of Contents
- [Quick Start](#-quick-start)
- [AI Assistant Framework](#-ai-assistant-framework)
- [Runtime Modes](#-runtime-modes)
- [PR Comment Commands](#-pr-comment-commands)
- [Core Concepts](#-core-concepts)
- [Provider Types](#-provider-types)
- [Orchestration](#-orchestration)
- [AI & MCP](#-ai--mcp)
- [GitHub Provider](#-github-provider)
- [Templating & Transforms](#-templating--transforms)
- [Suppressing Warnings](#-suppressing-warnings)
- [Testing Framework](#-testing-framework)
- [SDK](#-sdk-programmatic-usage)
- [Configuration](#-configuration)
- [Observability](#-observability)
- [Security](#-security)
- [Enterprise Policy Engine](#-enterprise-policy-engine-ee)
- [Further Reading](#-further-reading)
- [Contributing](#-contributing)
- [License](#-license)
**Requirements:** Node.js 18+ (CI runs Node 20).
## 🚀 Quick Start
### Install & Run
```bash
# One-off
npx -y @probelabs/visor@latest --check all --output table
# As a dev dependency
npm i -D @probelabs/visor
npx visor --check all --output json
```
### Minimal Config (`.visor.yaml`)
```yaml
version: "1.0"
steps:
security:
type: ai
prompt: "Identify security issues in changed files"
tags: ["fast", "security"]
run-tests:
type: command
exec: npm test
depends_on: [security]
notify:
type: http
method: POST
url: https://hooks.slack.com/...
body: '{ "text": "Tests {{ outputs[''run-tests''].status }}" }'
depends_on: [run-tests]
```
### As a GitHub Action
```yaml
# .github/workflows/visor.yml
name: Visor
on:
pull_request: { types: [opened, synchronize] }
issues: { types: [opened] }
issue_comment: { types: [created] }
permissions:
contents: read
pull-requests: write
issues: write
checks: write
jobs:
visor:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: probelabs/visor@v1
env:
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
```
> **Tip:** Pin releases for stability with `@v1`. For bleeding-edge, use `@nightly`.
## 🤖 AI Assistant Framework
Visor ships with a built-in assistant framework — three composable workflows for building AI-powered assistants with skills, tools, and multi-repo code exploration. Import them with a single line:
```yaml
version: "1.0"
imports:
- visor://assistant.yaml
checks:
chat:
type: workflow
workflow: assistant
assume: ["true"]
args:
question: "{{ conversation.current.text }}"
system_prompt: "You are a helpful engineering assistant."
intents:
- id: chat
description: general Q&A or small talk
- id: code_help
description: questions about code or architecture
default_skills: [code-explorer]
skills:
- id: code-explorer
description: needs codebase exploration or code search
tools:
code-talk:
workflow: code-talk
inputs:
projects:
- id: backend
repo: my-org/backend
description: Backend API service
allowed_commands: ['git:log:*', 'git:diff:*']
on_success:
goto: chat
```
| Workflow | What it does |
|----------|-------------|
| **assistant** | Full AI assistant — intent routing, dynamic skill activation, tool orchestration, knowledge injection, bash command control |
| **code-talk** | Multi-repo code exploration — routes questions to repos, checks out code, explores with tools, returns answers with file references and confidence scoring |
| **intent-router** | Lightweight intent classification — picks intent, rewrites question, selects skills/tags |
The `visor://` protocol resolves to bundled workflows shipped with the package — no network fetch needed.
Learn more: [docs/assistant-workflows.md](docs/assistant-workflows.md) | Examples: [code-talk-workflow](examples/code-talk-workflow.yaml) · [code-talk-as-tool](examples/code-talk-as-tool.yaml) · [intent-router](examples/intent-router-workflow.yaml)
## 🖥️ Runtime Modes
Visor runs the same YAML config across four surfaces:
| Mode | How to run | Best for |
|------|-----------|----------|
| **CLI** | `visor --check all --output table` | Local dev, CI pipelines |
| **GitHub Action** | `uses: probelabs/visor@v1` | PR reviews, issue triage, annotations |
| **Slack bot** | `visor --slack --config .visor.yaml` | Team assistants, ChatOps |
| **HTTP server** | `http_server: { enabled: true, port: 8080 }` | Webhooks, API integrations |
Additional modes:
- **TUI** — interactive chat-style terminal UI: `visor --tui`
- **SDK** — programmatic Node.js API: `import { runChecks } from '@probelabs/visor/sdk'`
- **Scheduler** — cron-based execution with database-backed persistence
```bash
# CLI examples
visor --check all --output table
visor --tags fast,local --max-parallelism 5
visor --analyze-branch-diff # PR-style diff analysis
visor --event pr_updated # Simulate GitHub events
visor --tui --config ./workflow.yaml # Interactive TUI
visor --debug-server --debug-port 3456 # Live web debugger
visor config snapshots # Config version history
visor validate # Validate config
visor test --progress compact # Run integration tests
```
**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`.
See [docs/commands.md](docs/commands.md) for the full CLI reference.
## 💬 PR Comment Commands
Trigger reviews and assistant actions via comments on PRs or issues:
```
/review # Re-run all checks
/review --check security # Re-run specific check
/visor how does caching work? # Ask the built-in assistant
```
Learn more: [docs/commands.md](docs/commands.md)
## 🧩 Core Concepts
| Concept | What it is |
|---------|-----------|
| **Step** (or Check) | Unit of work — a shell command, AI call, HTTP request, script, etc. |
| **Provider** | How a step runs: `ai`, `command`, `script`, `mcp`, `http`, `claude-code`, `github`, `memory`, `workflow`, … |
| **depends_on** | Execution order — independents run in parallel, dependents wait. |
| **forEach** | Fan-out — transform output into an array, run dependents per item. |
| **Routing** | `on_fail`, `on_success`, `goto`, `retry` — conditional flow with loop safety. |
| **Transform** | Reshape output with Liquid templates or JavaScript before passing downstream. |
| **Schema** | JSON Schema that validates step output (e.g., `code-review`). |
| **Template** | Renders validated output into Markdown/table for PR comments. |
| **Group** | Which PR comment a step posts into. |
| **Tags** | Label steps and filter with `--tags fast,local`. |
| **Events** | Trigger steps on PRs, issues, comments, webhooks, or cron schedules. |
## 🔌 Provider Types
| Provider | Description | Example use |
|----------|------------|------------|
| `ai` | Multi-provider AI (Gemini, Claude, OpenAI, Bedrock) | Code review, analysis, generation |
| `command` | Shell commands with Liquid templating | Run tests, build, lint |
| `script` | JavaScript in a secure sandbox | Transform data, custom logic |
| `mcp` | MCP tool execution (stdio/SSE/HTTP) | External tool integration |
| `claude-code` | Claude Code SDK with MCP tools | Deep code analysis, refactoring |
| `http` | HTTP output/webhook sender | Notify Slack, trigger CI |
| `http_input` | Webhook receiver | Accept external events |
| `http_client` | HTTP API client | Call external APIs |
| `github` | GitHub operations (labels, comments, checks) | Label PRs, post reviews |
| `memory` | Key-value store (get/set/append/increment) | State across steps |
| `workflow` | Reusable sub-workflows from files/URLs | Compose pipelines |
| `human-input` | Interactive prompts (TUI/Slack) | Approvals, user input |
| `log` / `logger` | Structured logging | Debug, audit trail |
| `noop` | No-op placeholder | Orchestration nodes |
| `git-checkout` | Git operations (clone, checkout, worktree) | Multi-repo workflows |
See [docs/pluggable.md](docs/pluggable.md) for building custom providers.
## ⚙️ Orchestration
### Dependencies & Parallel Execution
Steps without dependencies run in parallel waves. `depends_on` enforces ordering:
```yaml
steps:
fetch-data:
type: command
exec: curl -s https://api.example.com/data
analyze:
type: ai
prompt: "Analyze: {{ outputs['fetch-data'] }}"
depends_on: [fetch-data]
report:
type: command
exec: 'echo "Done: {{ outputs[''analyze''] | truncate: 100 }}"'
depends_on: [analyze]
```
### forEach Fan-Out
Transform output into an array, run dependents once per item:
```yaml
steps:
list-services:
type: command
exec: 'echo ''["auth","payments","notifications"]'''
forEach: true
check-service:
type: command
exec: 'curl -s https://{{ outputs["list-services"] }}/health'
depends_on: [list-services]
```
Use `outputs_raw` in downstream steps to access the aggregated array of all forEach results:
```yaml
summarize:
type: script
depends_on: [list-services]
content: |
const arr = outputs_raw['list-services'] || [];
return { total: arr.length };
```
Learn more: [docs/foreach-dependency-propagation.md](docs/foreach-dependency-propagation.md)
### Failure Routing & Auto-Remediation
Steps can retry, run remediation, or jump to other steps on failure:
```yaml
version: "2.0"
routing:
max_loops: 5
steps:
build:
type: command
exec: make build
on_fail:
retry: { max: 2, backoff: { mode: exponential, delay_ms: 500 } }
goto: setup # Jump back on exhausted retries
deploy:
type: command
exec: make deploy
depends_on: [build]
on_success:
run: [notify] # Run extra steps on success
on_fail:
goto_js: |
return attempt <= 2 ? 'build' : null; # Dynamic routing
```
Learn more: [docs/failure-routing.md](docs/failure-routing.md)
### Conditional Execution & Author Permissions
```yaml
steps:
security-scan:
type: command
exec: npm audit
if: "!hasMinPermission('MEMBER')" # Only for external contributors
auto-approve:
type: github
op: labels.add
values: ["approved"]
if: "hasMinPermission('COLLABORATOR') && totalIssues === 0"
protect-secrets:
type: command
exec: echo "Checking permissions..."
fail_if: "!isMember() && files.some(f => f.filename.startsWith('secrets/'))"
```
Available permission functions: `hasMinPermission(level)`, `isOwner()`, `isMember()`, `isCollaborator()`, `isContributor()`, `isFirstTimer()`.
Learn more: [docs/author-permissions.md](docs/author-permissions.md)
## 🤖 AI & MCP
### Multi-Provider AI
```yaml
steps:
review:
type: ai
prompt: "Review this code for security issues"
ai:
provider: anthropic # or: google, openai, bedrock
model: claude-sonnet-4-20250514
fallback:
strategy: any # Try other providers on failure
```
Supported providers: **Google Gemini**, **Anthropic Claude**, **OpenAI GPT**, **AWS Bedrock**.
Set one key via environment: `GOOGLE_API_KEY`, `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, or AWS credentials.
### MCP Tool Integration
Give AI steps access to MCP tools, or call MCP tools directly:
```yaml
# AI step with MCP tools
steps:
analyze:
type: ai
prompt: "Use the search tool to find security patterns"
ai:
mcp_servers:
- name: code-search
command: npx
args: ["-y", "@probe/search"]
# Direct MCP tool execution
search:
type: mcp
transport: stdio
command: npx
args: ["-y", "@probe/search"]
method: search
arguments:
query: "{{ outputs['setup'].pattern }}"
```
### AI Session Reuse
Chain AI conversations across steps:
```yaml
steps:
security:
type: ai
prompt: "Find security issues"
remediation:
type: ai
prompt: "Suggest fixes for the issues you found"
depends_on: [security]
reuse_ai_session: true # Carries conversation history
session_mode: append # Or: clone (default)
```
### Claude Code Provider
Full Claude Code SDK integration with MCP tools and subagents:
```yaml
steps:
deep-review:
type: claude-code
prompt: "Analyze code complexity and suggest refactoring"
max_turns: 10
mcp_servers:
- name: filesystem
command: npx
args: ["-y", "@modelcontextprotocol/server-filesystem", "."]
```
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)
## 🧰 GitHub Provider
Native GitHub operations (labels, comments, checks) without shelling out to `gh`:
```yaml
steps:
apply-labels:
type: github
op: labels.add
values:
- "{{ outputs.overview.tags.label | default: '' | safe_label }}"
value_js: |
return values.filter(v => typeof v === 'string' && v.trim().length > 0);
```
Learn more: [docs/github-ops.md](docs/github-ops.md)
## 🧬 Templating & Transforms
### Liquid Templates
Steps can use Liquid templates in prompts, exec commands, HTTP bodies, and more:
```yaml
steps:
greet:
type: command
exec: 'echo "Files changed: {{ files | size }}, branch: {{ branch }}"'
post-results:
type: http
url: https://api.example.com/results
body: |
{ "issues": {{ outputs["review"] | json }},
"pr": {{ pr.number }} }
```
Available context: `outputs`, `outputs_raw`, `inputs`, `pr`, `files`, `env`, `memory`, `branch`, `event`, `conversation`.
### JavaScript Transforms
Transform step output before passing to dependents:
```yaml
steps:
fetch:
type: command
exec: 'node -e "console.log(JSON.stringify({items:[1,2,3]}))"'
transform_js: |
return output.items.filter(i => i > 1);
```
### Dynamic Routing with JavaScript
```yaml
steps:
check:
type: command
exec: npm test
on_fail:
goto_js: |
if (attempt > 3) return null; // Give up
return 'fix-and-retry'; // Jump to remediation
```
Prompts can live in external files with full Liquid variable access:
```yaml
steps:
overview:
type: ai
schema: code-review
prompt: ./prompts/overview.liquid
```
Learn more: [docs/liquid-templates.md](docs/liquid-templates.md) · [docs/schema-templates.md](docs/schema-templates.md)
## 🔇 Suppressing Warnings
Suppress a specific issue by adding a nearby `visor-disable` comment:
```js
const testPassword = "demo123"; // visor-disable
```
Learn more: [docs/suppressions.md](docs/suppressions.md)
## 🧪 Testing Framework
Write and run integration tests for your Visor config in YAML:
```yaml
# .visor.tests.yaml
tests:
- name: "Security check finds issues"
config: .visor.yaml
steps:
security:
mock_output: '{"issues": [{"severity": "high"}]}'
assertions:
- step: security
called: { exactly: 1 }
- step: security
output_contains: "high"
```
```bash
visor test --progress compact # Run tests
visor test --list # List test cases
visor test --only "Security*" # Filter tests
visor test --bail # Stop on first failure
```
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)
## 📦 SDK (Programmatic Usage)
Run Visor programmatically from Node.js:
```ts
import { loadConfig, runChecks } from '@probelabs/visor/sdk';
const config = await loadConfig('.visor.yaml');
const result = await runChecks({
config,
checks: Object.keys(config.checks || {}),
output: { format: 'json' },
});
console.log('Issues:', result.reviewSummary.issues?.length ?? 0);
```
Learn more: [docs/sdk.md](docs/sdk.md)
## 🔧 Configuration
### Config Loading Order
1. CLI `--config` flag
2. `.visor.yaml` in project root
3. Built-in defaults
### Extending Configs
```yaml
extends:
- default
- ./team-standards.yaml
- https://raw.githubusercontent.com/org/policies/main/base.yaml
```
### Dynamic Config Reloading
Long-running modes (Slack, HTTP) support live config reload:
```bash
visor --slack --config .visor.yaml --watch # Auto-reload on file change
visor config snapshots # List config versions
visor config diff 1 2 # Diff two snapshots
```
### Key Config Options
```yaml
version: "1.0"
max_parallelism: 3 # Concurrent steps
max_ai_concurrency: 3 # Concurrent AI API calls
routing:
max_loops: 10 # Loop safety limit
http_server:
enabled: true
port: 8080
auth: { bearer_token: "${WEBHOOK_SECRET}" }
telemetry:
enabled: true
sink: otlp # or: file, console
steps:
# ... your pipeline
```
Learn more: [docs/configuration.md](docs/configuration.md)
## 👀 Observability
### Output Formats
```bash
visor --output table # Terminal-friendly (default)
visor --output json --output-file results.json
visor --output sarif --output-file results.sarif
visor --output markdown
```
### OpenTelemetry Tracing
```yaml
telemetry:
enabled: true
sink: otlp
```
```bash
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://localhost:4318/v1/traces visor --check all
```
Span hierarchy: `visor.run` → `engine.state.*` → `visor.check.*` → `visor.foreach.item`
### Debug Tools
```bash
visor --debug # Verbose logging
visor --debug-server --debug-port 3456 # Live web visualizer
```
**Quick debugging tips:**
Use `log()` in JavaScript expressions (`if`, `fail_if`, `transform_js`):
```yaml
if: |
log("Outputs:", outputs);
outputs["fetch-data"]?.status === "ready"
```
Use the `json` filter in Liquid to inspect objects:
```yaml
type: logger
message: "Outputs: {{ outputs | json }}"
```
**TUI mode** (`visor --tui`): Press `Tab` to switch between Chat and Logs tabs, `q` to exit.
Learn more: [docs/observability.md](docs/observability.md) · [docs/debugging.md](docs/debugging.md) · [docs/debug-visualizer.md](docs/debug-visualizer.md)
## 🔐 Security
- **GitHub App support** for scoped, auditable access
- **Remote extends allowlist** to control external config sources
- **MCP method filtering** — allow/deny lists with wildcards
- **Bash allow/deny patterns** for AI-driven command execution
- **Docker & process sandboxes** for isolated step execution
- **Author permissions** — `hasMinPermission()`, `isMember()`, etc. for role-based logic
- **Environment filtering** — control which env vars steps can access
```bash
visor --no-remote-extends
visor --allowed-remote-patterns "https://raw.githubusercontent.com/myorg/"
```
Learn more: [docs/security.md](docs/security.md) · [docs/author-permissions.md](docs/author-permissions.md)
## 🏢 Enterprise Policy Engine (EE)
> **Enterprise Edition.** Requires a Visor EE license. Contact **hello@probelabs.com**.
OPA-based policy enforcement for gating checks, MCP tools, and AI capabilities:
```yaml
policy:
engine: local
rules: ./policies/
fallback: deny
roles:
admin: { author_association: [OWNER] }
developer: { author_association: [MEMBER, COLLABORATOR] }
```
Learn more: [docs/enterprise-policy.md](docs/enterprise-policy.md)
## 📚 Further Reading
**Guides:**
[Assistant workflows](docs/assistant-workflows.md) · [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)
**Providers:**
[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)
**Operations:**
[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)
**Architecture:**
[Failure conditions schema](docs/failure-conditions-schema.md) · [Failure conditions implementation](docs/failure-conditions-implementation.md)
**Testing:**
[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)
**Recipes & examples:**
[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)
## 🤝 Contributing
Learn more: [CONTRIBUTING.md](CONTRIBUTING.md)
## 📄 License
MIT License — see [LICENSE](LICENSE)
---