Skip to main content

Rules Overview

Rules are the atomic unit of enforcement in vybdocs. Each rule defines one constraint — a pattern that should not (or must) appear in your code — along with how violations are handled and how they map to compliance frameworks.

Anatomy of a rule

- id: sec-001
name: no-eval
description: Prohibit use of eval() and the Function() constructor
severity: block
pattern: "\\beval\\s*\\(|new\\s+Function\\s*\\("
pattern-mode: line
remediation: >
Use JSON.parse() for data deserialization.
Replace dynamic expressions with a safe evaluator library.
eval() is a critical XSS and code injection vulnerability.
exclude:
- "**/*.test.ts"
enabled: true
maps-to:
- framework: soc2
control: CC7.1
- framework: eu-ai-act
control: Art.9.5

Every field is documented in the spec.yaml reference. The most important are id, severity, and pattern.

How rules are evaluated

When vyb check runs:

  1. The spec is loaded and all enabled rules are collected across all categories
  2. The diff is computed (added/modified lines)
  3. Each changed line is tested against each rule's pattern
  4. Violations are grouped by severity and reported
  5. If any block violations exist, the check fails

Rules only test added or modified lines. Deleting code that matched a rule is always safe.

Rules vs. packs

A rule is one constraint. A pack is a curated set of rules designed for a specific context — a vertical (fintech, healthtech), a tech stack (Next.js, Django), or a team standard.

Packs are YAML files that contain rules organized into categories. When you run vyb init --pack eu-fintech, the pack's rules are merged into your .vyb/spec.yaml. You can then extend, override, or disable individual rules.

See Packs Overview for the full pack system documentation.

Rule ID conventions

Rule IDs follow the pattern <category-prefix>-<zero-padded-number>:

fe-001 ← frontend, rule 1
sec-023 ← security, rule 23
llm-004 ← llms, rule 4

IDs must be unique within a spec. When merging a pack into your spec, if the pack defines sec-001 and your spec already has sec-001, your spec's version takes precedence (local override wins).

Rule states

StateHowEffect
Activeenabled: true (default)Rule is evaluated on every check
Disabledenabled: falseRule is skipped silently
Excludedexclude: [glob]Rule runs but skips matching files

Disabling a rule is recorded in the Evidence Pack. If a rule was disabled after being active, the Evidence Pack notes the timestamp and the git author of the change.

Ordering within categories

Rules within a category are evaluated in the order they are listed in the YAML. Order affects:

  • The order violations appear in output
  • Nothing else — all rules are independent

A complete rule set example

.vyb/spec.yaml (categories section)
categories:
security:
rules:
- id: sec-001
name: no-eval
description: Prohibit eval() and Function() constructor
severity: block
pattern: "\\beval\\s*\\(|new\\s+Function\\s*\\("
remediation: Replace with JSON.parse() or a safe eval library.
maps-to:
- framework: soc2
control: CC7.1

- id: sec-002
name: no-hardcoded-jwt-secret
description: Detect hardcoded JWT signing secrets
severity: block
pattern: "(jwt|JWT).*['\"][A-Za-z0-9+/]{20,}"
remediation: Load JWT_SECRET from environment variables or a secrets vault.
maps-to:
- framework: soc2
control: CC6.1

- id: sec-003
name: no-http-urls
description: Require HTTPS for all external URLs
severity: warn
pattern: "http://(?!localhost|127\\.0\\.0\\.1)"
remediation: Change http:// to https://. HTTP transmits data in plaintext.
exclude:
- "**/*.md"
- "**/README*"

Next: Writing Rules