Skip to main content

Dry Run Mode

Dry run lets you test rule patterns against your codebase without failing the build or blocking any commits. It is the primary way to iterate on rules before committing them.

CLI dry run

Add --dry-run to any vyb check invocation:

vyb check --dry-run

The output is identical to a normal check, including violation details and file/line references. The only difference: the exit code is always 0, even if block-severity violations are found.

vyb check --dry-run v1.0.0
───────────────────────────────────────────────────────────
Mode: DRY RUN (exit code forced to 0)

Rules evaluated: 31
Violations: 2

[BLOCK] sec-001 / no-eval
src/utils/parser.ts:47
eval(userInput)
→ Replace with JSON.parse() or a safe eval library.

[WARN] dep-001 / no-lodash
src/helpers/array.ts:3
import _ from 'lodash'
→ Use native Array methods or lodash-es imports.

DRY RUN complete — not failing despite violations
───────────────────────────────────────────────────────────
Exit code: 0

No Evidence Pack is written in dry-run mode.

Use cases

Introducing a new rule: Add the rule to your spec with enabled: true and run vyb check --dry-run to see how many existing violations it would catch before you enforce it.

Staging migration: Before adding a new rule to CI, run it in dry-run for a sprint to let the team clean up the codebase at their own pace.

Auditing a codebase: Run vyb check --dry-run --base main on a branch to get a full inventory of constraint violations without blocking anything.

Scoping dry runs

Dry run supports the same scope flags as a normal check:

# Dry run on only staged changes
vyb check --dry-run --staged

# Dry run scoped to specific files
vyb check --dry-run --files "src/utils/**"

# Dry run against entire repo history from main
vyb check --dry-run --base $(git merge-base HEAD origin/main)

# Dry run and write results to a JSON file
vyb check --dry-run --output violations.json

MCP dry run

The Claude Desktop MCP server exposes a dryRunRule tool that lets you test a proposed rule interactively:

User: Can you propose a rule that bans the use of 'moment' package?

Claude: Let me propose and dry-run that rule.

[calls proposeRule]
id: pkg-moment
name: no-moment
pattern: from 'moment'|require\('moment'\)
severity: warn
remediation: Use date-fns or dayjs instead of moment.js.

[calls dryRunRule with above rule]
Dry run result:
Files scanned: 47
Violations: 3
package.json:12 "moment": "^2.29.4"
src/utils/date.ts:1 import moment from 'moment'
src/helpers/format.ts:8 import { format } from 'moment'

3 violations found. Ready to commit this rule?

After reviewing the dry run output, you can call commitRule to add the rule to your spec. See Claude Desktop MCP for the full MCP workflow.

Temporarily disabling rules in spec

An alternative to dry run for individual rules is to disable them in the spec:

- id: sec-001
name: no-eval
severity: block
enabled: false # ← rule exists but is skipped
pattern: "\\beval\\("

This is useful when:

  • A rule is defined in a pack but you need to temporarily suspend it during a migration
  • A rule has too many false positives in a specific file or module

Setting enabled: false is recorded in the Evidence Pack. If you later re-enable the rule, the re-enablement is also logged.

Output formats for dry run

# Default: human-readable terminal output
vyb check --dry-run

# JSON output for programmatic processing
vyb check --dry-run --output-format json

# SARIF output for GitHub Code Scanning integration
vyb check --dry-run --output-format sarif

SARIF output can be uploaded to GitHub Code Scanning to surface vybdocs violations as code quality annotations on PRs — even before you make them blocking.


Next: Packs Overview