Ameba Configuration
Configure Ameba, the static code analysis tool for Crystal, to enforce consistent code style and catch code smells in your Crystal projects.
Understanding Ameba
Ameba is a static code analysis tool for the Crystal programming language that:
-
Enforces consistent Crystal code style
-
Catches code smells and wrong code constructions
-
Provides configurable rules organized into categories
-
Supports inline disabling of rules
-
Offers auto-correction for many issues
-
Integrates seamlessly with Crystal development workflows
Core Configuration File: .ameba.yml
Generating Default Configuration
Generate a new configuration file with all defaults
ameba --gen-config
This creates .ameba.yml with all available rules and their default settings
Basic Configuration Structure
.ameba.yml - Complete example configuration
Global source configuration
Globs:
- "**/*.cr" # Include all Crystal files
- "**/*.ecr" # Include Embedded Crystal files
- "!lib" # Exclude dependencies
Excluded:
- src/legacy/** # Exclude legacy code
- spec/fixtures/** # Exclude test fixtures
Rule categories and individual rules
Lint/UnusedArgument: Enabled: true Severity: Warning
Style/RedundantReturn: Enabled: true Severity: Convention
Performance/AnyInsteadOfEmpty: Enabled: true Severity: Warning
Source File Configuration
Globs: Defining What to Analyze
Include specific patterns
Globs:
- "**/*.cr" # All Crystal source files
- "**/*.ecr" # All Embedded Crystal templates
- "!lib/**" # Exclude lib directory
- "!vendor/**" # Exclude vendor directory
Common patterns
- "src/**/*.cr" # Only src directory
- "spec/**/*.cr" # Only spec directory
- "!**/*_test.cr" # Exclude test files
Excluded: Fine-Grained Exclusions
Global exclusions (applied to all rules)
Excluded:
- src/compiler/** # Exclude specific directories
- src/legacy/**
- spec/fixtures/**
- db/migrations/** # Often excluded from style checks
Real-world example
Globs:
- "**/*.cr"
- "!lib"
Excluded:
- src/external/generated/** # Generated code
- src/legacy/** # Legacy code being refactored
- spec/support/fixtures/** # Test data
Source Configuration Examples
Example 1: Standard web application
Globs:
- "src/**/*.cr"
- "spec/**/*.cr"
- "!lib"
Excluded:
- src/assets/**
- spec/fixtures/**
Example 2: Library/Shard
Globs:
- "src/**/*.cr"
- "spec/**/*.cr"
- "examples/**/*.cr"
- "!lib"
Excluded:
- spec/support/**
Example 3: Monorepo
Globs:
- "apps//src//*.cr"
- "apps//spec//*.cr"
- "packages//src//*.cr"
- "!lib"
- "!/node_modules/"
Excluded:
- apps/legacy/**
Rule Categories
Lint Rules (Code Correctness)
Lint rules catch potential bugs and incorrect code:
Unused variables and arguments
Lint/UnusedArgument: Enabled: true Severity: Warning
Catches: def process(data, unused_param)
Lint/UselessAssign: Enabled: true Severity: Warning
Catches: x = 5; x = 10 # First assignment never used
Shadowed variables
Lint/ShadowingOuterLocalVar: Enabled: true Severity: Warning
Catches: x = 1; proc { |x| x } # x shadows outer x
Unreachable code
Lint/UnreachableCode: Enabled: true Severity: Error
Catches: return x; do_something() # Never executes
Syntax issues
Lint/Syntax: Enabled: true Severity: Error
Catches syntax errors before compilation
Empty blocks
Lint/EmptyBlock: Enabled: true Severity: Warning ExcludeEmptyBlocks: false
Catches: items.each { }
Debugger statements
Lint/DebuggerStatement: Enabled: true Severity: Warning
Catches: debugger; pp value
Style Rules (Code Conventions)
Style rules enforce Crystal code conventions:
Naming conventions
Style/ConstantNames: Enabled: true Severity: Convention
Enforces: CONSTANT_NAME not Constant_Name
Style/MethodNames: Enabled: true Severity: Convention
Enforces: method_name not methodName
Style/TypeNames: Enabled: true Severity: Convention
Enforces: ClassName not Class_Name
Predicate methods
Style/PredicateName: Enabled: true Severity: Convention
Enforces: empty? not is_empty
Redundant code
Style/RedundantReturn: Enabled: true Severity: Convention AllowMultipleReturnValues: true
Catches: def foo; return 42; end
Prefers: def foo; 42; end
Style/RedundantBegin: Enabled: true Severity: Convention
Catches: def foo; begin; 42; end; end
Prefers: def foo; 42; end
Large numbers
Style/LargeNumbers: Enabled: true Severity: Convention IntMinDigits: 5
Enforces: 100_000 not 100000
Parentheses
Style/ParenthesesAroundCondition: Enabled: true Severity: Convention
Enforces: if x > 5 not if (x > 5)
String literals
Style/StringLiterals: Enabled: true Severity: Convention
Catches inconsistent quote usage
Variable names
Style/VariableNames: Enabled: true Severity: Convention
Enforces: snake_case not camelCase
Performance Rules
Performance rules identify inefficient code patterns:
Inefficient any? usage
Performance/AnyInsteadOfEmpty: Enabled: true Severity: Warning FilterFirstNegativeCondition: true
Catches: array.any?
Prefers: !array.empty?
Size after filter
Performance/SizeAfterFilter: Enabled: true Severity: Warning FilterNames: [select, reject]
Catches: items.select(&.active?).size
Prefers: items.count(&.active?)
Compact after map
Performance/CompactAfterMap: Enabled: true Severity: Warning
Catches: items.map(&.value?).compact
Prefers: items.compact_map(&.value?)
Flatten after map
Performance/FlattenAfterMap: Enabled: true Severity: Warning
Catches: items.map(&.children).flatten
Prefers: items.flat_map(&.children)
Rule Configuration Options
Per-Rule Configuration
Enable/disable individual rules
Style/LargeNumbers: Enabled: true # or false to disable
Set severity levels
Style/RedundantReturn: Enabled: true Severity: Warning # Error, Warning, Convention
Configure rule-specific options
Style/LargeNumbers: Enabled: true Severity: Convention IntMinDigits: 5 # Minimum digits before requiring underscores
Lint/UnusedArgument: Enabled: true IgnoreTypeDeclarations: false IgnoreParameterNames: [] # Parameter names to ignore
Exclude files from specific rules
Style/RedundantBegin: Enabled: true Excluded: - src/server/processor.cr - src/server/api.cr
Advanced Rule Configuration Examples
Custom severity levels
Lint/UselessAssign: Enabled: true Severity: Error # Make this an error, not warning
Style/RedundantReturn: Enabled: true Severity: Convention AllowMultipleReturnValues: true # Allow: return x, y
Ignore specific parameter patterns
Lint/UnusedArgument: Enabled: true IgnoreParameterNames: - "*" # Ignore params starting with underscore - "unused*" # Ignore params prefixed with unused_
Configure numeric formatting
Style/LargeNumbers: Enabled: true IntMinDigits: 5 # 10000 requires underscores
1000 is fine, 10000 should be 10_000
Performance tuning
Performance/SizeAfterFilter: Enabled: true FilterNames: - select - reject - filter
Severity Levels
Understanding Severity
Error: Must be fixed (blocks CI typically)
Lint/Syntax: Severity: Error
Warning: Should be fixed (important issues)
Lint/UnusedArgument: Severity: Warning
Convention: Style preference (less critical)
Style/RedundantReturn: Severity: Convention
Severity Configuration Strategy
Conservative approach (CI-friendly)
Only errors block builds
Lint/Syntax: Severity: Error
Lint/UnreachableCode: Severity: Error
Style/RedundantReturn: Severity: Warning
Style/LargeNumbers: Severity: Convention
Strict approach (enforce everything)
All issues treated as errors
Lint/UnusedArgument: Severity: Error
Style/RedundantReturn: Severity: Error
Style/VariableNames: Severity: Error
Progressive approach (gradually increase strictness)
Start with warnings, move to errors over time
Lint/UselessAssign: Severity: Warning # Will become Error after cleanup
Style/RedundantBegin: Severity: Convention # Will become Warning after team adapts
Inline Rule Control
Disabling Rules in Code
Disable single rule for one line
time = Time.epoch(1483859302) # ameba:disable Style/LargeNumbers
Disable multiple rules for one line
result = calculate() # ameba:disable Style/RedundantReturn, Lint/UselessAssign
Disable rule categories
ameba:disable Style, Lint
def legacy_method
Old code with known issues
end
ameba:enable Style, Lint
Disable specific rule for block
ameba:disable Style/RedundantBegin
def process begin perform_operation rescue handle_error end end
ameba:enable Style/RedundantBegin
Common patterns
class LegacyService
ameba:disable Lint/UnusedArgument
def process(data, context) # Only using data for now data.process end
ameba:enable Lint/UnusedArgument
end
Inline Disable Best Practices
GOOD - Specific and temporary
def parse_timestamp(value) Time.epoch(1483859302) # ameba:disable Style/LargeNumbers end
GOOD - With explanation
This API requires exact numeric format
ameba:disable Style/LargeNumbers
LEGACY_TIMESTAMP = 1483859302
ameba:enable Style/LargeNumbers
BAD - Too broad
ameba:disable Style
Disables all style rules - too permissive
def messy_method
...
end
BAD - Never re-enabled
ameba:disable Lint/UselessAssign
Disables for rest of file
GOOD - Scoped to minimum area
def external_api_call
ameba:disable Style/VariableNames
responseData = call_api() # External API uses camelCase
ameba:enable Style/VariableNames
response_data = responseData # Convert to Crystal convention end
Complete Configuration Examples
Minimal Configuration (Permissive)
.ameba.yml - Minimal setup for new projects
Globs:
- "**/*.cr"
- "!lib"
Only enable critical rules
Lint/Syntax: Enabled: true Severity: Error
Lint/UnreachableCode: Enabled: true Severity: Error
Standard Configuration (Balanced)
.ameba.yml - Standard configuration for most projects
Globs:
- "**/*.cr"
- "**/*.ecr"
- "!lib"
Excluded:
- spec/fixtures/**
Lint rules (errors and warnings)
Lint/Syntax: Enabled: true Severity: Error
Lint/UnusedArgument: Enabled: true Severity: Warning
Lint/UselessAssign: Enabled: true Severity: Warning
Lint/UnreachableCode: Enabled: true Severity: Error
Style rules (conventions)
Style/RedundantReturn: Enabled: true Severity: Convention
Style/RedundantBegin: Enabled: true Severity: Convention
Style/LargeNumbers: Enabled: true Severity: Convention IntMinDigits: 5
Style/VariableNames: Enabled: true Severity: Warning
Performance rules
Performance/AnyInsteadOfEmpty: Enabled: true Severity: Warning
Performance/SizeAfterFilter: Enabled: true Severity: Warning
Strict Configuration (Comprehensive)
.ameba.yml - Strict configuration for production code
Globs:
- "src/**/*.cr"
- "spec/**/*.cr"
- "!lib"
Excluded:
- spec/fixtures/**
- spec/support/mocks/**
All lint rules enabled as errors
Lint/Syntax: Enabled: true Severity: Error
Lint/UnusedArgument: Enabled: true Severity: Error
Lint/UselessAssign: Enabled: true Severity: Error
Lint/UnreachableCode: Enabled: true Severity: Error
Lint/ShadowingOuterLocalVar: Enabled: true Severity: Error
Lint/DebuggerStatement: Enabled: true Severity: Error
Style rules as warnings or errors
Style/RedundantReturn: Enabled: true Severity: Error
Style/RedundantBegin: Enabled: true Severity: Error
Style/LargeNumbers: Enabled: true Severity: Error IntMinDigits: 4
Style/VariableNames: Enabled: true Severity: Error
Style/MethodNames: Enabled: true Severity: Error
Style/ConstantNames: Enabled: true Severity: Error
Style/PredicateName: Enabled: true Severity: Warning
Performance rules as warnings
Performance/AnyInsteadOfEmpty: Enabled: true Severity: Warning
Performance/SizeAfterFilter: Enabled: true Severity: Warning
Performance/CompactAfterMap: Enabled: true Severity: Warning
Performance/FlattenAfterMap: Enabled: true Severity: Warning
When to Use This Skill
Use the ameba-configuration skill when:
-
Setting up Ameba for a new Crystal project
-
Configuring code quality standards for a team
-
Customizing rule severity levels for CI/CD
-
Excluding legacy code or generated files from analysis
-
Troubleshooting rule conflicts or false positives
-
Migrating from one Ameba version to another
-
Establishing project-specific coding standards
-
Balancing code quality with development velocity
-
Integrating Ameba into existing Crystal projects
-
Creating configuration templates for multiple projects
Best Practices
-
Start with generated config - Run ameba --gen-config to see all available rules and their defaults
-
Use version control - Commit .ameba.yml so team members share the same configuration
-
Enable incrementally - Start permissive, gradually enable more rules as team adapts
-
Set appropriate severities - Use Error for blocking issues, Warning for important, Convention for style
-
Document exceptions - Add comments explaining why specific rules are disabled or configured differently
-
Scope exclusions narrowly - Exclude specific files/directories rather than disabling rules globally
-
Use inline disables sparingly - Prefer fixing issues over disabling rules; when necessary, be specific
-
Review generated config - Don't blindly use default config; review and customize for your project
-
Separate concerns - Use different severity levels for different types of issues (bugs vs style)
-
Test configuration changes - Run ameba locally before committing configuration changes
-
Keep config maintainable - Group related rules together and use comments to explain sections
-
Align with team standards - Configuration should reflect team consensus, not individual preferences
-
Update regularly - Review and update configuration when upgrading Ameba versions
-
Use rule-specific exclusions - Exclude files from specific rules rather than globally when possible
-
Monitor false positives - Adjust rules that generate too many false positives for your codebase
Common Pitfalls
-
Too strict initially - Enabling all rules at maximum severity in existing projects creates overwhelming technical debt
-
Too permissive permanently - Never tightening rules means missing valuable code quality improvements
-
Excluding too broadly - Using Excluded: ["**/*"] defeats the purpose of static analysis
-
Inconsistent severity - Mixing up severity levels (making style issues errors, making bugs conventions)
-
Not using version control - Team members using different configurations causes confusion
-
Ignoring upgrade guides - New Ameba versions may change rule names or behaviors
-
Disabling without understanding - Turning off rules that flag legitimate issues
-
Overusing inline disables - Littering code with ameba:disable comments instead of fixing issues
-
Not excluding generated code - Wasting time analyzing auto-generated files
-
Forgetting about ECR files - Not including **/*.ecr in Globs for web applications
-
Conflicting with formatter - Enabling rules that conflict with crystal tool format
-
Missing test files - Not including spec/**/*.cr in Globs
-
Global disables in code - Using ameba:disable at file level without re-enabling
-
Not testing CI integration - Configuration works locally but fails in CI environment
-
Ignoring performance impact - Enabling every rule without considering analysis time on large codebases
Resources
-
Ameba GitHub Repository
-
Ameba Official Documentation
-
Writing Custom Rules Tutorial
-
Ameba Internals Guide
-
Crystal Language Documentation