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:
- The spec is loaded and all enabled rules are collected across all categories
- The diff is computed (added/modified lines)
- Each changed line is tested against each rule's pattern
- Violations are grouped by severity and reported
- If any
blockviolations 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
| State | How | Effect |
|---|---|---|
| Active | enabled: true (default) | Rule is evaluated on every check |
| Disabled | enabled: false | Rule is skipped silently |
| Excluded | exclude: [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
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