Overlays guide
Overlays let you customize third-party packs without forking. Change severity, add check inputs, or remove autofix while preserving upstream updates.
See it in action: Check out the overlays example for a working demonstration.
Quick start (60 seconds)
Scenario: You use @acme/standards but want to treat one check as an error.
# .aligntrue/.rules.yaml
sources:
- git: https://github.com/acme/standards
ref: v1.2.0
overlays:
overrides:
- selector: "rule[id=no-console-log]"
set:
severity: "error"Run sync:
aligntrue sync
# Output:
# ✓ Applied 1 overlay to @acme/standards
# ✓ Lockfile updated with overlay hashResult: no-console-log now fails CI instead of warning, and you still get upstream updates with aligntrue update.
When to use overlays vs plugs vs forks
Decision tree
Need to customize a third-party pack?
│
├─ Change exists in pack definition? (severity, inputs, autofix)
│ ├─ YES → Use overlay (this guide)
│ └─ NO → Continue...
│
├─ Customization is stack-specific? (test commands, paths)
│ ├─ YES → Use plug (see plugs guide)
│ └─ NO → Continue...
│
└─ Need to change check logic or add new checks?
└─ YES → Fork pack or create custom packWhen to use overlays
✅ Change severity: Warning → error, or disable a check
✅ Add check inputs: Pass project-specific config to checks
✅ Remove autofix: Keep check but disable automatic fixes
✅ Temporary adjustments: Override during migration, restore later
❌ Don’t use overlays for:
- Changing check logic (fork instead)
- Adding new checks (create custom pack)
- Stack-specific values (use plugs)
When to use plugs
✅ Stack-specific values: Test commands, file paths, URLs
✅ Template slots: Fill variables in rules
✅ Project metadata: Author names, organization names
See Plugs Guide for plug documentation.
When to fork
✅ Major changes: Rewrite check logic, change structure
✅ Divergent requirements: Your needs differ fundamentally
✅ No upstream updates needed: You maintain your version
Overlay anatomy
Basic overlay
overlays:
overrides:
- selector: "rule[id=no-console-log]"
set:
severity: "error" # Change severityAdvanced overlay
overlays:
overrides:
- selector: "rule[id=max-complexity]"
set:
severity: "warning"
"check.inputs.threshold": 15 # Nested property with dot notation
remove:
- "autofix" # Disable autofixNote: Track metadata like reason, expires, and owner via YAML comments.
Selector strategies
By rule ID
Applies to one specific rule by its unique ID:
overlays:
overrides:
- selector: "rule[id=no-console-log]"
set:
severity: "error"Use when: Most rules are fine, one needs adjustment.
By property path
Modify nested properties using dot notation:
overlays:
overrides:
- selector: "profile.version"
set:
value: "2.0.0"Use when: Changing configuration or metadata fields.
By array index
Target specific array elements:
overlays:
overrides:
- selector: "rules[0]"
set:
severity: "warn"Use when: Modifying rules by position (less common, prefer rule ID).
Note: Scope-based selectors (e.g., tests/**) are not yet implemented. Use hierarchical configs with scopes for path-based customization.
Override capabilities
Set operation
Use set to modify properties (supports dot notation for nested paths):
overlays:
overrides:
- selector: "rule[id=no-console-log]"
set:
severity: "error" # Simple property
"check.inputs.maxLength": 120 # Nested property
autofix: false # Disable autofixSeverity values: "off", "info", "warning", "error"
Remove operation
Use remove to delete properties:
overlays:
overrides:
- selector: "rule[id=max-complexity]"
remove:
- "autofix" # Remove autofix
- "tags" # Remove tags arrayCombined operations
Apply both set and remove in one overlay:
overlays:
overrides:
- selector: "rule[id=line-length]"
set:
severity: "warning"
"check.inputs.threshold": 120
remove:
- "autofix"Advanced patterns
Multiple overlays
Apply multiple overlays to different rules:
overlays:
overrides:
- selector: "rule[id=no-console-log]"
set:
severity: "error"
- selector: "rule[id=max-complexity]"
set:
"check.inputs.threshold": 15
- selector: "rule[id=prefer-const]"
remove:
- "autofix"Order: Overlays apply in definition order. Last matching overlay wins if multiple target the same rule.
Temporary overrides
Use YAML comments to track temporary overlays:
overlays:
overrides:
# TEMPORARY: Migration to new API in progress
# Expires: 2025-12-31
# Owner: platform-team
- selector: "rule[id=no-deprecated-api]"
set:
severity: "warning"Use aligntrue override status to review all active overlays.
Migration workflow
Gradually adopt stricter rules:
# Week 1: Disable new check
overlays:
overrides:
- selector: "rule[id=new-security-rule]"
set:
severity: "off"
# Week 2: Enable as warning
overlays:
overrides:
- selector: "rule[id=new-security-rule]"
set:
severity: "warning"
# Week 3: Remove overlay (use upstream default: error)
overlays:
overrides: []Scenario-based examples
More examples: See SCENARIOS.md in the overlays example for detailed scenarios with expected outputs.
Scenario 1: Solo developer - Temporarily disable strict rule
Goal: Disable strict TypeScript rule during refactoring, re-enable after.
Setup:
sources:
- git: https://github.com/org/typescript-standards
ref: v1.0.0
# Temporarily downgrade severity during refactoring
overlays:
overrides:
# TEMPORARY: Refactoring legacy code
# Expires: 2025-12-31
# Will re-enable after refactor complete
- selector: "rule[id=strict-null-checks]"
set:
severity: "warn" # Downgrade from errorWorkflow:
# 1. Add overlay
aligntrue sync
# 2. Refactor code with warnings instead of errors
# ... refactoring work ...
# 3. Remove overlay when done
aligntrue override remove 'rule[id=strict-null-checks]'
aligntrue syncScenario 2: Solo developer - Adjust complexity threshold
Goal: Increase complexity threshold for specific project needs.
Setup:
sources:
- git: https://github.com/org/code-quality-pack
ref: v2.0.0
overlays:
overrides:
# Project has complex domain logic, increase threshold
# Reviewed: 2025-10-01
- selector: "rule[id=max-complexity]"
set:
"check.inputs.threshold": 15 # Default is 10
"check.inputs.excludeComments": trueResult: Complexity check allows up to 15 instead of 10.
Scenario 3: Team - Enforce stricter severity
Goal: Team wants stricter enforcement than upstream defaults.
Setup:
sources:
- git: https://github.com/community/typescript-pack
ref: v1.0.0
overlays:
overrides:
# Team policy: No console.log in production
# Approved: 2025-10-15
# Owner: platform-team
- selector: "rule[id=no-console-log]"
set:
severity: "error" # Upgrade from warning
# Team policy: No any types
# Approved: 2025-10-15
# Owner: platform-team
- selector: "rule[id=no-any-type]"
set:
severity: "error" # Upgrade from warningWorkflow:
# 1. Team lead adds overlays
# 2. Commit to git
git add .aligntrue/.rules.yaml
git commit -m "chore: Enforce stricter console.log and any-type rules"
# 3. Team members pull and sync
git pull
aligntrue sync
# 4. CI validates with stricter rules
aligntrue check --ciScenario 4: Team - Disable risky autofix
Goal: Keep check but disable autofix that conflicts with framework.
Setup:
sources:
- git: https://github.com/org/react-standards
ref: v2.0.0
overlays:
overrides:
# Autofix conflicts with React hooks dependencies
# Issue: #123
# Owner: frontend-team
- selector: "rule[id=prefer-const]"
remove:
- "autofix"Result: Check still runs, but doesn’t auto-fix (manual fixes only).
Scenario 5: Team - Gradual rollout of new rule
Goal: Roll out new security rule gradually across team.
Week 1 - Disable:
overlays:
overrides:
# ROLLOUT: Week 1 - Disabled
# New security rule, giving team time to review
- selector: "rule[id=new-security-check]"
set:
severity: "off"Week 2 - Warning:
overlays:
overrides:
# ROLLOUT: Week 2 - Warning
# Team reviewing violations
- selector: "rule[id=new-security-check]"
set:
severity: "warn"Week 3 - Error:
overlays:
overrides:
# ROLLOUT: Week 3 - Error
# All violations fixed, enforcing now
- selector: "rule[id=new-security-check]"
set:
severity: "error"Week 4 - Remove overlay:
# Remove overlay, use upstream default (error)
overlays:
overrides: []Scenario 6: Fork-safe customization
Goal: Customize third-party pack without forking, preserve updates.
Setup:
sources:
- git: https://github.com/thirdparty/standards
ref: v3.0.0
overlays:
overrides:
# Customize for our needs
- selector: "rule[id=line-length]"
set:
"check.inputs.maxLength": 120 # We use 120, they use 80
- selector: "rule[id=max-complexity]"
set:
"check.inputs.threshold": 15 # We allow 15, they allow 10
- selector: "rule[id=prefer-const]"
remove:
- "autofix" # Conflicts with our frameworkUpdate workflow:
# 1. Update upstream
aligntrue update check
# 2. Review changes
aligntrue override status # Check overlay health
# 3. Apply update
aligntrue update apply
# 4. Overlays preserved, applied to new version
aligntrue syncResult: Get upstream updates while keeping customizations.
Conflict resolution
What causes conflicts?
Stale selectors: Upstream renamed or removed a rule.
# Upstream renamed "no-console-log" → "no-console-statements"
overlays:
overrides:
- selector: "rule[id=no-console-log]" # ❌ No longer exists
set:
severity: "error"Resolution: Run aligntrue override status to detect stale selectors, update to new rule ID.
Duplicate overlays: Multiple overlays target same rule.
overlays:
overrides:
- selector: "rule[id=no-console-log]"
set:
severity: "error"
- selector: "rule[id=no-console-log]"
set:
severity: "warning" # ❌ Conflicts with aboveResolution: Last matching overlay wins. Consolidate into single overlay or remove duplicate.
Handling upstream changes
When upstream changes may conflict with your overlay:
# Check overlay health after update
aligntrue sync
aligntrue override status
# Shows if overlays still match rules
# View overlay effects
aligntrue override diff 'rule[id=no-console-log]'
# Shows: original IR → modified IR with overlay appliedIf rule ID changed upstream:
- Remove old overlay:
aligntrue override remove 'rule[id=old-name]' - Add new overlay:
aligntrue override add --selector 'rule[id=new-name]' --set severity=error
If overlay now redundant (upstream matches your override):
- Verify match:
aligntrue override diff - Remove overlay:
aligntrue override remove 'rule[id=rule-name]'
Team workflows
Overlay approval
Team mode tracks overlays in lockfile for review:
// .aligntrue.lock.json
{
"dependencies": {
"acme-standards": {
"content_hash": "sha256:upstream...",
"overlay_hash": "sha256:local-mods...",
"final_hash": "sha256:combined..."
}
}
}See Team Mode Guide for team mode workflows.
Overlay dashboard
Audit all overlays:
aligntrue override status
# Output:
# Overlays (3 active, 1 stale)
#
# ✓ rule[id=no-console-log]
# Set: severity=error
# Healthy: yes
#
# ✓ rule[id=max-complexity]
# Set: check.inputs.threshold=15
# Healthy: yes
#
# ❌ rule[id=old-rule-name]
# Set: severity=off
# Healthy: stale (no match in IR)Overlay hashing and lockfile
Triple-hash lockfile
Overlays are deterministic and hashed separately:
{
"spec_version": "1",
"generated_at": "2025-10-31T12:00:00Z",
"dependencies": {
"@acme/standards": {
"version": "1.2.0",
"source": {
"type": "git",
"url": "https://github.com/acme/standards",
"ref": "v1.2.0",
"commit": "abc123"
},
"base_hash": "sha256:upstream-content-hash",
"overlay_hash": "sha256:overlay-modifications-hash",
"result_hash": "sha256:combined-hash"
}
}
}base_hash: Upstream pack content
overlay_hash: Your overlay modifications
result_hash: Combined result after overlays applied
Drift detection
Detect overlay staleness:
aligntrue drift
# Output:
# Drift detected (2 categories)
#
# Overlay drift:
# rule[id=no-console-log]
# - overlay_hash changed (local modifications)
# - Recommendation: Review overlay changes
#
# Upstream drift:
# @acme/standards
# - base_hash changed (upstream updated)
# - Recommendation: Run aligntrue sync to apply latestSee Drift Detection for full drift capabilities.
CLI commands
Add overlay
# Add overlay to change severity
aligntrue override add \
--selector 'rule[id=no-console-log]' \
--set severity=error
# Add overlay with nested property (dot notation)
aligntrue override add \
--selector 'rule[id=max-complexity]' \
--set check.inputs.threshold=15
# Remove property
aligntrue override add \
--selector 'rule[id=prefer-const]' \
--remove autofix
# Combined set and remove
aligntrue override add \
--selector 'rule[id=line-length]' \
--set severity=warning \
--set check.inputs.max=120 \
--remove autofixView overlays
# Dashboard of all overlays
aligntrue override status
# JSON output for CI
aligntrue override status --jsonDiff overlays
# Show effect of specific overlay
aligntrue override diff 'rule[id=no-console-log]'
# Show all overlay effects
aligntrue override diffRemove overlay
# Interactive removal (select from list)
aligntrue override remove
# Direct removal by selector
aligntrue override remove 'rule[id=no-console-log]'
# Skip confirmation
aligntrue override remove 'rule[id=no-console-log]' --forceIntegration with other commands
# Sync applies overlays automatically
aligntrue sync
# Update preserves overlays
aligntrue updateSee CLI Reference for complete command documentation.
Best practices
Keep overlays minimal
Only override what you must. Fewer overlays = easier updates.
❌ Bad: Override many rules:
overlays:
overrides:
- selector: "rule[id=check-1]"
set: { severity: "error" }
- selector: "rule[id=check-2]"
set: { severity: "error" }
# ... 20 more overlays✅ Good: Fork and customize:
# Create your own pack based on upstream
# Maintain in your repo, or request changes upstreamDocument reasons
Always explain why using YAML comments:
overlays:
overrides:
# CLI tool requires console output for user feedback
# Owner: cli-team
- selector: "rule[id=no-console-log]"
set:
severity: "off"Track expiration
For temporary overrides, use YAML comments:
overlays:
overrides:
# TEMPORARY: Gradual rollout
# Expires: 2025-12-31
- selector: "rule[id=new-rule]"
set:
severity: "warning"Use aligntrue override status to review active overlays regularly.
Review regularly
Audit overlays monthly:
# Check all overlays health
aligntrue override status
# View overlay effects
aligntrue override diff
# Detect drift
aligntrue driftFor solo developers
- Use for experimentation - Try different severity levels
- Temporary adjustments - Disable strict rules during refactoring
- Document decisions - Add comments explaining why
- Clean up - Remove overlays when no longer needed
For teams
- Require approval - PR review for overlay changes
- Document ownership - Add owner comments
- Set expiration dates - Review temporary overlays
- Audit regularly - Monthly overlay review
- Validate in CI - Run
aligntrue override statusin CI
Troubleshooting
Overlay not applied
Symptom: Overlay defined but check still uses upstream settings.
Diagnosis:
aligntrue override status
# Look for "Healthy: no" entriesCommon causes:
- Typo in rule ID
- Rule no longer exists in upstream
- Selector too specific (no matches)
Fix: Run aligntrue override status for health status and detailed errors.
Overlay conflicts
Symptom: Multiple overlays target same rule.
Diagnosis:
aligntrue override status
# Lists all active overlays
aligntrue override diff
# Shows combined effectFix: Consolidate overlays into single definition. Last overlay wins if multiple target same rule.
Update breaks overlays
Symptom: After aligntrue update, overlays fail to apply.
Diagnosis:
aligntrue override status
# Shows health after update
aligntrue override diff
# Shows current effectsFix: Update selectors to match new upstream rule IDs. Run aligntrue override remove for stale overlays and re-add with correct selectors.
See Troubleshooting Overlays for comprehensive troubleshooting.
Related documentation
- Customization Overview - When to use overlays vs plugs vs scopes
- Plugs Guide - Stack-specific customization
- Scopes Guide - Path-based rule application
- Team Mode Guide - Overlay policies and approval workflows
- Drift Detection - Detect overlay staleness
- CLI Reference - Complete CLI reference
- Solo Developer Guide - Solo workflow with overlays
- Team Guide - Team collaboration with overlays
Summary
Overlays let you customize without forking:
- Quick: Add overlay in 60 seconds
- Safe: Preserve upstream updates
- Flexible: Change severity, inputs, autofix
- Auditable: Dashboard and drift detection
- Team-ready: Approval policies and expiration tracking
When in doubt:
- Use overlays for pack-level customization (severity, inputs)
- Use plugs for stack-specific values (test commands, paths)
- Use scopes for path-based rules (monorepo)
- Fork when you need fundamental changes
Start with overlays, graduate to forks only when necessary.