| name | vale-rule-config |
| description | Author and test custom Vale rules for InfluxData documentation: rule types (existence, substitution, conditional), the regexp2 engine and PCRE lookarounds, and testing rule patterns in isolation. Use when writing a new Vale rule, debugging why a rule pattern does not match, or working with Vale regex. To run Vale, manage vocabulary, or fix flagged content, see vale-linting. |
Vale Rule Configuration
Purpose
This skill guides CI/Quality Engineers in writing, testing, and maintaining Vale style linting rules for the InfluxData documentation. It covers Vale's regex engine, rule syntax, configuration files, and best practices for creating effective style rules.
Use this skill when:
- Writing new Vale rules (existence, substitution, etc.)
- Debugging Vale rule patterns that aren't working
- Understanding Vale's regex capabilities
- Configuring Vale for product-specific style guides
- Managing vocabulary and branding terms
For content editors who just need to run Vale and fix issues, see the content-editing skill instead.
Quick Decision Tree
Writing a new Vale rule?
├─ Simple pattern? Use tokens (See Part 1: Basic Rules)
└─ Complex pattern? Use raw or check regex engine (See Part 2: Regex Engine)
Rule not matching as expected?
├─ Check Vale's regex flavor (See Part 2: Regex Engine)
└─ Test pattern in isolation (See Part 5: Testing)
Need product-specific terms?
└─ Add to vocabulary files (See Part 3: Vocabulary)
Need to configure Vale for a product?
└─ Create .vale.ini (See Part 4: Configuration)
Part 1: Basic Vale Rule Types
Vale supports several rule types. Here are the most common:
Existence Rules
Checks if certain patterns exist in the text.
extends: existence
message: "Don't use '%s'"
level: error
tokens:
- obviously
- basically
- simply
With nonword: true for punctuation:
extends: existence
message: "'%s' should be in lowercase."
link: 'https://developers.google.com/style/colons'
nonword: true
level: warning
scope: sentence
tokens:
- ':\s[A-Z]'
Substitution Rules
Suggests replacements for problematic patterns.
Substitution rules in this repo expand abbreviations rather than introduce
them (the real terminology rule lives in
.ci/vale/styles/InfluxDataDocs/WordList.yml):
extends: substitution
message: "Use '%s' instead of '%s'"
level: warning
swap:
admin: administrator
repo: repository
Conditional Rules
More complex rules with exceptions.
extends: conditional
first: '\b(if|when)\b'
second: '\bthen\b'
message: "If/when statements should include 'then'"
level: warning
Part 2: Vale's Regex Engine
Critical: Vale Uses regexp2, Not RE2
Vale uses the regexp2 library, not Go's standard regexp package (which uses RE2). This is a common source of confusion because Vale is written in Go.
Supported Regex Features
Vale supports PCRE-style lookarounds despite being written in Go:
- ✅ Positive lookahead:
(?=re)
- ✅ Negative lookahead:
(?!re)
- ✅ Positive lookbehind:
(?<=re)
- ✅ Negative lookbehind:
(?<!re)
- ✅ Lazy quantifiers:
*?, +?, ??
- ✅ Named groups:
(?P<name>...)
- ✅ Atomic groups:
(?>...)
According to Vale's maintainer:
"Vale uses a superset of the Go flavor, supporting PCRE-style lookarounds."
Example: Negative Lookbehind
This pattern matches a colon followed by uppercase letter, but NOT when the colon is part of a URL scheme (like https:):
extends: existence
message: "'%s' should be in lowercase."
nonword: true
scope: sentence
tokens:
- '(?<!:[^ ]+?):\s[A-Z]'
How it works:
(?<!:[^ ]+?) - Negative lookbehind: NOT preceded by : followed by non-space characters
:\s[A-Z] - Colon, whitespace, uppercase letter
Example: Positive Lookbehind
Match "Internet" only when preceded by whitespace, excluding specific phrases:
extends: existence
message: "'%s' should only be capitalized when starting a sentence."
scope: sentence
tokens:
- '(?<=\s)Internet(?! Service Provider| Protocol)'
Critical Limitation: Vale Cannot Match URLs
TokenIgnores in .vale.ini strips all URLs before rules run. No rule — existence, substitution, or raw — can match content inside a URL. This applies globally and cannot be overridden per-rule.
For URL pattern validation (e.g., enforcing canonical support URLs), use a shell script or pre-commit hook instead of a Vale rule. See .ci/scripts/check-support-links.sh for an example.
tokens vs raw
tokens:
- Automatically wrapped in word boundaries
- Converted to non-capturing groups
- Good for simple patterns
raw:
- Full control over the pattern
- No automatic processing
- Use for complex regex
extends: existence
message: "Use 'database' instead"
raw:
- '\bDB\b(?!\s+instance)'
Part 3: Vocabulary Management
Vocabulary files manage accepted and rejected terms across the documentation.
File Locations
.ci/vale/styles/config/vocabularies/
└── InfluxDataDocs/
├── accept.txt # Accepted terms (won't be flagged)
└── reject.txt # Rejected terms (will be flagged)
# Only InfluxDataDocs exists today. To add a product-specific vocabulary,
# create a sibling directory (for example, Cloud-Dedicated/) with its own
# accept.txt/reject.txt and reference it via Vocab in the product .vale.ini.
accept.txt Format
One term per line. Case-sensitive by default:
InfluxDB
InfluxQL
Telegraf
ClickHouse
PostgreSQL
Support for regex patterns:
# Accept both capitalizations
[Dd]atabase
[Aa]PI
# Accept with word boundaries
\bDB\b
reject.txt Format
Rejected terms that should never be used:
Influx
influxdb (lowercase)
big data
simply
obviously
Product-Specific Vocabulary
Create product-specific vocabularies by:
- Creating a new vocabulary directory in
.ci/vale/styles/config/vocabularies/
- Adding
accept.txt and reject.txt
- Configuring in product's
.vale.ini
Example:
StylesPath = ../../../.ci/vale/styles
Vocab = Cloud-Dedicated
[*.md]
BasedOnStyles = Vale, InfluxDataDocs, Cloud-Dedicated, Google, write-good
Part 4: Vale Configuration Files
Repository-Level Config
.vale.ini in repository root:
StylesPath = .ci/vale/styles
MinAlertLevel = suggestion
Vocab = InfluxDataDocs
[*.md]
BasedOnStyles = Vale, InfluxDataDocs, Google, write-good
Product-Specific Config
Product configs must mirror all disabled rules from root .vale.ini (rules disabled in root are NOT inherited). See the vale-linting skill for a complete product config example with all disabled rules.
Rule Configuration
Individual rules are YAML files in style directories:
.ci/vale/styles/
├── Google/
│ ├── Colons.yml
│ ├── Headings.yml
│ └── ...
├── InfluxDataDocs/
│ ├── Branding.yml
│ ├── WordList.yml
│ └── ...
└── config/
└── vocabularies/
Part 5: Testing Vale Rules
Test a Rule in Isolation
.ci/vale/vale.sh \
--config=.vale.ini \
--minAlertLevel=suggestion \
content/influxdb3/core/get-started/_index.md
.ci/vale/vale.sh \
--config=content/influxdb3/cloud-dedicated/.vale.ini \
--minAlertLevel=error \
content/influxdb3/cloud-dedicated/**/*.md
Test Rule Pattern Before Adding to Vale
You can test regex patterns with Python or online tools first:
import re
pattern = r'(?<!:[^ ]+?):\s[A-Z]'
text = "Install the package: Then run it."
matches = re.findall(pattern, text)
print(matches)
text2 = "Visit https://example.com"
matches2 = re.findall(pattern, text2)
print(matches2)
Common Issues
Pattern not matching:
- Check if you need
nonword: true for punctuation
- Verify scope is appropriate (
sentence, heading, etc.)
- Test with
raw instead of tokens for complex patterns
Too many false positives:
- Add exceptions using negative lookahead/lookbehind
- Adjust scope to be more specific
- Consider using substitution rule with exceptions
Pattern works in Python but not Vale:
- Unlikely if you're using PCRE features (Vale supports them)
- Check for differences in whitespace handling
- Try
raw field for exact pattern control
Part 6: Advanced Patterns
Excluding Specific Contexts
extends: existence
message: "Use 'DB' for brevity"
tokens:
- '\bdatabase\b(?! instance| cluster)'
Case-Insensitive Matching
extends: existence
message: "Use 'InfluxDB' with proper capitalization"
tokens:
- '(?i)influx ?db'
Multiple Conditions
extends: conditional
first: '\b(will|shall)\b'
second: '(?:not|n''t)\b'
message: "Use 'won't' or 'will not' consistently"
Capture Groups for Messages
extends: substitution
message: "Use '%s' instead of '%s'"
swap:
'(\w+)base': '$1-base'
Part 7: Best Practices
DO:
- Start simple: Use
tokens before moving to raw
- Test incrementally: Add patterns one at a time
- Use vocabulary files: For spelling and branding terms
- Document patterns: Add comments explaining complex regex
- Be specific: Use lookarounds to reduce false positives
- Check scope: Use appropriate scope (sentence, heading, etc.)
DON'T:
- Assume RE2 limitations: Vale supports lookarounds
- Over-complicate: Sometimes simpler patterns work better
- Ignore performance: Complex patterns can slow down linting
- Skip testing: Always test rules on real content first
- Forget edge cases: Test with URLs, code blocks, etc.
Part 8: Reference
Alert Levels
error: Critical issues (broken links, branding violations)
warning: Style guide rules
suggestion: Optional improvements
Common Scopes
text: All text content
sentence: Individual sentences
paragraph: Full paragraphs
heading: Heading text only
list: List items only
code: Code blocks (rarely used)
Rule Types
existence: Check if patterns exist
substitution: Suggest replacements
conditional: If X then Y must also exist
consistency: Enforce consistent usage
occurrence: Limit pattern occurrences
repetition: Check for repeated words
sequence: Check word ordering
Part 9: Example: Creating a New Rule
Let's create a rule to enforce "InfluxDB 3" instead of "InfluxDB v3":
Step 1: Create the rule file
cat > .ci/vale/styles/InfluxDataDocs/InfluxDB3Version.yml <<'EOF'
extends: substitution
message: "Use '%s' instead of '%s'"
level: warning
link: 'https://docs.influxdata.com/style-guide/#version-names'
swap:
'InfluxDB v3': 'InfluxDB 3'
'InfluxDB V3': 'InfluxDB 3'
EOF
Step 2: Test on sample content
.ci/vale/vale.sh content/influxdb3/core/get-started/_index.md
Step 3: Refine if needed
If too many false positives, add exceptions:
extends: existence
message: "Use 'InfluxDB 3' instead of 'InfluxDB v3'"
level: warning
tokens:
- 'InfluxDB v3(?![`/])'
Step 4: Run on full product
.ci/vale/vale.sh content/influxdb3/**/*.md
Related Skills
- content-editing - For content editors who need to run Vale and fix issues
- cypress-e2e-testing - For testing documentation after style fixes
Resources
Official Documentation
Community Resources
Internal Documentation
Checklist: Before Adding a New Vale Rule