| 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. |
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.
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)
Vale supports several rule types. Here are the most common:
Checks if certain patterns exist in the text.
# .ci/vale/styles/InfluxDataDocs/BadWords.yml
extends: existence
message: "Don't use '%s'"
level: error
tokens:
- obviously
- basically
- simplyWith nonword: true for punctuation:
# .ci/vale/styles/Google/Colons.yml
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]'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):
# Illustrative — mirrors the style of InfluxDataDocs/WordList.yml
extends: substitution
message: "Use '%s' instead of '%s'"
level: warning
swap:
admin: administrator
repo: repositoryMore complex rules with exceptions.
extends: conditional
first: '\b(if|when)\b'
second: '\bthen\b'
message: "If/when statements should include 'then'"
level: warningVale 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.
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."
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:
# ✅ This works! Negative lookbehind is supported
- '(?<!:[^ ]+?):\s[A-Z]'How it works:
(?<!:[^ ]+?)- Negative lookbehind: NOT preceded by:followed by non-space characters:\s[A-Z]- Colon, whitespace, uppercase letter
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)'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:
- 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
# Using raw for full control
extends: existence
message: "Use 'database' instead"
raw:
- '\bDB\b(?!\s+instance)' # DB but not "DB instance"Vocabulary files manage accepted and rejected terms across the documentation.
.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.
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
Rejected terms that should never be used:
Influx
influxdb (lowercase)
big data
simply
obviously
Create product-specific vocabularies by:
- Creating a new vocabulary directory in
.ci/vale/styles/config/vocabularies/ - Adding
accept.txtandreject.txt - Configuring in product's
.vale.ini
Example:
# content/influxdb3/cloud-dedicated/.vale.ini
StylesPath = ../../../.ci/vale/styles
Vocab = Cloud-Dedicated
[*.md]
BasedOnStyles = Vale, InfluxDataDocs, Cloud-Dedicated, Google, write-good.vale.ini in repository root:
StylesPath = .ci/vale/styles
MinAlertLevel = suggestion
Vocab = InfluxDataDocs
[*.md]
BasedOnStyles = Vale, InfluxDataDocs, Google, write-goodProduct 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.
Individual rules are YAML files in style directories:
.ci/vale/styles/
├── Google/
│ ├── Colons.yml
│ ├── Headings.yml
│ └── ...
├── InfluxDataDocs/
│ ├── Branding.yml
│ ├── WordList.yml
│ └── ...
└── config/
└── vocabularies/
# Test specific rule on one file
.ci/vale/vale.sh \
--config=.vale.ini \
--minAlertLevel=suggestion \
content/influxdb3/core/get-started/_index.md
# Test only error-level issues
.ci/vale/vale.sh \
--config=content/influxdb3/cloud-dedicated/.vale.ini \
--minAlertLevel=error \
content/influxdb3/cloud-dedicated/**/*.mdYou can test regex patterns with Python or online tools first:
import re
# Test negative lookbehind pattern
pattern = r'(?<!:[^ ]+?):\s[A-Z]'
text = "Install the package: Then run it."
matches = re.findall(pattern, text)
print(matches) # Should match ": T"
# Should NOT match URL schemes
text2 = "Visit https://example.com"
matches2 = re.findall(pattern, text2)
print(matches2) # Should be emptyPattern not matching:
- Check if you need
nonword: truefor punctuation - Verify scope is appropriate (
sentence,heading, etc.) - Test with
rawinstead oftokensfor 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
rawfield for exact pattern control
# Match "database" but not "database instance" or "database cluster"
extends: existence
message: "Use 'DB' for brevity"
tokens:
- '\bdatabase\b(?! instance| cluster)'extends: existence
message: "Use 'InfluxDB' with proper capitalization"
tokens:
- '(?i)influx ?db' # Matches influxdb, influx db, INFLUXDB, etc.extends: conditional
first: '\b(will|shall)\b'
second: '(?:not|n''t)\b'
message: "Use 'won't' or 'will not' consistently"extends: substitution
message: "Use '%s' instead of '%s'"
swap:
'(\w+)base': '$1-base' # Changes 'database' to 'data-base'- Start simple: Use
tokensbefore moving toraw - 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.)
- 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.
error: Critical issues (broken links, branding violations)warning: Style guide rulessuggestion: Optional improvements
text: All text contentsentence: Individual sentencesparagraph: Full paragraphsheading: Heading text onlylist: List items onlycode: Code blocks (rarely used)
existence: Check if patterns existsubstitution: Suggest replacementsconditional: If X then Y must also existconsistency: Enforce consistent usageoccurrence: Limit pattern occurrencesrepetition: Check for repeated wordssequence: Check word ordering
Let's create a rule to enforce "InfluxDB 3" instead of "InfluxDB v3":
# Create new rule
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# Test on one file first
.ci/vale/vale.sh content/influxdb3/core/get-started/_index.mdIf too many false positives, add exceptions:
extends: existence
message: "Use 'InfluxDB 3' instead of 'InfluxDB v3'"
level: warning
tokens:
# Match "InfluxDB v3" but not in URLs or code
- 'InfluxDB v3(?![`/])'# Test on entire product
.ci/vale/vale.sh content/influxdb3/**/*.md- content-editing - For content editors who need to run Vale and fix issues
- cypress-e2e-testing - For testing documentation after style fixes
- Vale issue #233 - RFC on lookarounds
- Vale discussion #817 - Working lookbehind example
- Google Developer Documentation Style Guide
- DOCS-CONTRIBUTING.md - Vale configuration section
- DOCS-TESTING.md - Vale testing procedures
- Pattern tested in isolation (Python/regex tool)
- Rule tested on sample content
- False positives identified and handled
- Appropriate alert level chosen (error/warning/suggestion)
- Documentation link added (if applicable)
- Rule tested on full product content
- Rule added to appropriate style directory
- Configuration updated if needed (.vale.ini)
- PR includes examples of rule in action
- Team reviewed for style guide alignment