Documentation/Buki/Ameba/ skills /ameba-configuration

📖 ameba-configuration

Use when configuring Ameba rules and settings for Crystal projects including .ameba.yml setup, rule management, severity levels, and code quality enforcement.



Overview

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

  1. Start with generated config - Run ameba --gen-config to see all available rules and their defaults
  2. Use version control - Commit .ameba.yml so team members share the same configuration
  3. Enable incrementally - Start permissive, gradually enable more rules as team adapts
  4. Set appropriate severities - Use Error for blocking issues, Warning for important, Convention for style
  5. Document exceptions - Add comments explaining why specific rules are disabled or configured differently
  6. Scope exclusions narrowly - Exclude specific files/directories rather than disabling rules globally
  7. Use inline disables sparingly - Prefer fixing issues over disabling rules; when necessary, be specific
  8. Review generated config - Don't blindly use default config; review and customize for your project
  9. Separate concerns - Use different severity levels for different types of issues (bugs vs style)
  10. Test configuration changes - Run ameba locally before committing configuration changes
  11. Keep config maintainable - Group related rules together and use comments to explain sections
  12. Align with team standards - Configuration should reflect team consensus, not individual preferences
  13. Update regularly - Review and update configuration when upgrading Ameba versions
  14. Use rule-specific exclusions - Exclude files from specific rules rather than globally when possible
  15. Monitor false positives - Adjust rules that generate too many false positives for your codebase

Common Pitfalls

  1. Too strict initially - Enabling all rules at maximum severity in existing projects creates overwhelming technical debt
  2. Too permissive permanently - Never tightening rules means missing valuable code quality improvements
  3. Excluding too broadly - Using Excluded: ["**/*"] defeats the purpose of static analysis
  4. Inconsistent severity - Mixing up severity levels (making style issues errors, making bugs conventions)
  5. Not using version control - Team members using different configurations causes confusion
  6. Ignoring upgrade guides - New Ameba versions may change rule names or behaviors
  7. Disabling without understanding - Turning off rules that flag legitimate issues
  8. Overusing inline disables - Littering code with ameba:disable comments instead of fixing issues
  9. Not excluding generated code - Wasting time analyzing auto-generated files
  10. Forgetting about ECR files - Not including **/*.ecr in Globs for web applications
  11. Conflicting with formatter - Enabling rules that conflict with crystal tool format
  12. Missing test files - Not including spec/**/*.cr in Globs
  13. Global disables in code - Using ameba:disable at file level without re-enabling
  14. Not testing CI integration - Configuration works locally but fails in CI environment
  15. Ignoring performance impact - Enabling every rule without considering analysis time on large codebases

Resources