typescript-utility-types
Use when typeScript utility types, mapped types, and advanced type manipulation. Use when creating flexible, type-safe TypeScript code.
ameba-integration
Use when integrating Ameba into development workflows including CI/CD pipelines, pre-commit hooks, GitHub Actions, and automated code review processes.
Full skill instructions
Integrate Ameba into your development workflow for automated Crystal code quality checks in CI/CD pipelines, pre-commit hooks, and code review processes.
Ameba can be integrated at multiple points in your development workflow:
# Run Ameba on entire project
ameba
# Run on specific files
ameba src/models/user.cr
# Run on specific directories
ameba src/services/
# Run with specific configuration
ameba --config .ameba.custom.yml
# Generate default configuration
ameba --gen-config
# Auto-fix correctable issues
ameba --fix
# Only check specific rules
ameba --only Style/RedundantReturn
# Exclude specific rules
ameba --except Style/LargeNumbers
# Format output
ameba --format json
ameba --format junit
ameba --format flycheck
# Explain issues at specific location
ameba --explain src/models/user.cr:10:5
# Run with all output
ameba --all
# Fail silently on no issues
ameba --silent
# Default: Human-readable
ameba
# Output:
# src/user.cr:10:5: Style/RedundantReturn: Redundant return detected
# JSON format (for parsing)
ameba --format json
# Output: {"sources": [...], "summary": {...}}
# JUnit XML (for CI integration)
ameba --format junit > ameba-results.xml
# Flycheck format (for Emacs)
ameba --format flycheck
# Check only changed files (git)
git diff --name-only --diff-filter=ACM | grep '\.cr$' | xargs ameba
# Check only staged files
git diff --cached --name-only --diff-filter=ACM | grep '\.cr$' | xargs ameba
# Run with parallel processing (if available)
ameba --parallel
# Set exit code based on severity
ameba --fail-level error # Only fail on errors
ameba --fail-level warning # Fail on warnings and errors
ameba --fail-level convention # Fail on everything
# Generate formatted report
ameba --format json | jq '.summary'
Create .git/hooks/pre-commit:
#!/bin/sh
# .git/hooks/pre-commit - Run Ameba on staged Crystal files
echo "Running Ameba on staged files..."
# Get staged Crystal files
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep '\.cr$')
if [ -z "$STAGED_FILES" ]; then
echo "No Crystal files staged, skipping Ameba"
exit 0
fi
# Run Ameba on staged files
echo "$STAGED_FILES" | xargs ameba
# Capture exit code
AMEBA_EXIT=$?
if [ $AMEBA_EXIT -ne 0 ]; then
echo "❌ Ameba found issues. Please fix them before committing."
echo "Run 'ameba --fix' to auto-correct some issues."
exit 1
fi
echo "✅ Ameba checks passed"
exit 0
Make it executable:
chmod +x .git/hooks/pre-commit
#!/bin/sh
# Advanced pre-commit hook with auto-fix option
echo "Running Ameba on staged files..."
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep '\.cr$')
if [ -z "$STAGED_FILES" ]; then
exit 0
fi
# Run Ameba
echo "$STAGED_FILES" | xargs ameba
AMEBA_EXIT=$?
if [ $AMEBA_EXIT -ne 0 ]; then
echo ""
echo "❌ Ameba found issues."
echo ""
read -p "Would you like to auto-fix correctable issues? (y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "Running ameba --fix..."
echo "$STAGED_FILES" | xargs ameba --fix
# Re-add fixed files
echo "$STAGED_FILES" | xargs git add
echo "✅ Auto-fixed issues and re-staged files"
echo "⚠️ Please review the changes before committing again"
exit 1 # Exit to allow review
else
echo "Please fix issues manually before committing"
exit 1
fi
fi
echo "✅ Ameba checks passed"
exit 0
Using the pre-commit framework:
Create .pre-commit-config.yaml:
# .pre-commit-config.yaml
repos:
- repo: local
hooks:
- id: ameba
name: Ameba (Crystal Linter)
entry: ameba
language: system
files: \.cr$
pass_filenames: true
- repo: local
hooks:
- id: crystal-format
name: Crystal Format
entry: crystal tool format
language: system
files: \.cr$
pass_filenames: true
Install and use:
# Install pre-commit
pip install pre-commit # or brew install pre-commit
# Install hooks
pre-commit install
# Run manually
pre-commit run --all-files
# Run on specific files
pre-commit run --files src/user.cr
# .pre-commit-config.yaml with options
repos:
- repo: local
hooks:
- id: ameba
name: Ameba
entry: ameba
language: system
files: \.cr$
pass_filenames: true
- id: ameba-strict
name: Ameba (Strict)
entry: ameba --fail-level convention
language: system
files: ^src/.*\.cr$ # Only src directory
pass_filenames: true
- id: ameba-autofix
name: Ameba Auto-fix
entry: ameba --fix
language: system
files: \.cr$
pass_filenames: true
Create .github/workflows/ameba.yml:
name: Ameba
user-invocable: false
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Crystal
uses: crystal-lang/install-crystal@v1
with:
crystal: latest
- name: Install dependencies
run: shards install
- name: Run Ameba
uses: crystal-ameba/[email protected]
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
name: Code Quality
user-invocable: false
on:
push:
branches: [ main ]
pull_request:
types: [ opened, synchronize, reopened ]
jobs:
ameba:
name: Ameba Linting
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history for better analysis
- name: Install Crystal
uses: crystal-lang/install-crystal@v1
with:
crystal: 1.11.0 # Pin version for consistency
- name: Cache shards
uses: actions/cache@v3
with:
path: lib
key: ${{ runner.os }}-shards-${{ hashFiles('shard.lock') }}
restore-keys: |
${{ runner.os }}-shards-
- name: Install dependencies
run: shards install
- name: Run Ameba
uses: crystal-ameba/[email protected]
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload Ameba results
if: always()
uses: actions/upload-artifact@v3
with:
name: ameba-results
path: ameba-results.json
name: Quality Across Versions
user-invocable: false
on: [push, pull_request]
jobs:
ameba:
strategy:
matrix:
crystal: [1.10.0, 1.11.0, latest]
os: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Install Crystal ${{ matrix.crystal }}
uses: crystal-lang/install-crystal@v1
with:
crystal: ${{ matrix.crystal }}
- name: Install dependencies
run: shards install
- name: Run Ameba
run: |
crystal run bin/ameba.cr -- --format json > ameba-results.json
- name: Check results
run: |
if [ $(jq '.summary.issues_count' ameba-results.json) -gt 0 ]; then
echo "❌ Found issues"
jq '.summary' ameba-results.json
exit 1
fi
name: PR Code Review
user-invocable: false
on:
pull_request:
types: [ opened, synchronize ]
jobs:
review:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Crystal
uses: crystal-lang/install-crystal@v1
- name: Install dependencies
run: shards install
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v40
with:
files: |
**/*.cr
- name: Run Ameba on changed files
if: steps.changed-files.outputs.any_changed == 'true'
run: |
echo "${{ steps.changed-files.outputs.all_changed_files }}" | \
xargs ameba --format json > ameba-results.json
- name: Comment PR
if: steps.changed-files.outputs.any_changed == 'true'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const results = JSON.parse(fs.readFileSync('ameba-results.json', 'utf8'));
if (results.summary.issues_count > 0) {
const body = `## Ameba Report
Found ${results.summary.issues_count} issue(s):
${results.sources.flatMap(s =>
s.issues.map(i =>
\`- \${s.path}:\${i.location.line}:\${i.location.column} - \${i.rule.name}: \${i.message}\`
)
).join('\\n')}`;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: body
});
}
# .gitlab-ci.yml
stages:
- quality
- test
- build
ameba:
stage: quality
image: crystallang/crystal:latest
before_script:
- shards install
script:
- crystal run bin/ameba.cr -- --format junit > ameba-results.xml
artifacts:
reports:
junit: ameba-results.xml
paths:
- ameba-results.xml
when: always
expire_in: 1 week
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_BRANCH == "main"'
ameba-strict:
extends: ameba
script:
- crystal run bin/ameba.cr -- --fail-level convention
only:
- main
# .circleci/config.yml
version: 2.1
orbs:
crystal: manastech/[email protected]
jobs:
ameba:
executor:
name: crystal/default
tag: "1.11"
steps:
- checkout
- restore_cache:
keys:
- shards-v1-{{ checksum "shard.lock" }}
- shards-v1-
- run:
name: Install dependencies
command: shards install
- save_cache:
key: shards-v1-{{ checksum "shard.lock" }}
paths:
- lib
- run:
name: Run Ameba
command: |
crystal run bin/ameba.cr -- --format junit > ameba-results.xml
- store_test_results:
path: ameba-results.xml
- store_artifacts:
path: ameba-results.xml
workflows:
version: 2
quality:
jobs:
- ameba
// Jenkinsfile
pipeline {
agent {
docker {
image 'crystallang/crystal:latest'
}
}
stages {
stage('Setup') {
steps {
sh 'shards install'
}
}
stage('Ameba') {
steps {
sh '''
crystal run bin/ameba.cr -- --format junit > ameba-results.xml || true
'''
}
post {
always {
junit 'ameba-results.xml'
}
}
}
stage('Ameba Strict') {
when {
branch 'main'
}
steps {
sh 'crystal run bin/ameba.cr -- --fail-level error'
}
}
}
post {
failure {
emailext(
subject: "Ameba Failures in ${env.JOB_NAME}",
body: "Check console output at ${env.BUILD_URL}",
to: "${env.CHANGE_AUTHOR_EMAIL}"
)
}
}
}
# .travis.yml
language: crystal
crystal:
- latest
- 1.11.0
install:
- shards install
script:
- crystal spec
- crystal run bin/ameba.cr -- --fail-level warning
cache:
directories:
- lib
notifications:
email:
on_success: never
on_failure: change
Install the Crystal Language extension and configure:
// .vscode/settings.json
{
"crystal-lang.server": "crystalline",
"crystal-lang.problems": "build",
// Run Ameba on save
"emeraldwalk.runonsave": {
"commands": [
{
"match": "\\.cr$",
"cmd": "ameba ${file}"
}
]
},
// Format on save
"editor.formatOnSave": true,
"[crystal]": {
"editor.defaultFormatter": "crystal-lang-tools.crystal-lang"
}
}
Create .vscode/tasks.json:
{
"version": "2.0.0",
"tasks": [
{
"label": "Ameba",
"type": "shell",
"command": "ameba",
"problemMatcher": {
"owner": "crystal",
"fileLocation": ["relative", "${workspaceFolder}"],
"pattern": {
"regexp": "^(.+):(\\d+):(\\d+):\\s+(.+):\\s+(.+)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "Ameba Fix",
"type": "shell",
"command": "ameba --fix",
"group": "build"
}
]
}
Using ALE (Asynchronous Lint Engine):
" .vimrc or init.vim
let g:ale_linters = {
\ 'crystal': ['ameba', 'crystal'],
\}
let g:ale_fixers = {
\ 'crystal': ['ameba'],
\}
" Enable auto-fixing on save
let g:ale_fix_on_save = 1
" Ameba options
let g:ale_crystal_ameba_executable = 'ameba'
;; .emacs or init.el
(require 'flycheck)
(flycheck-define-checker crystal-ameba
"Crystal linter using Ameba."
:command ("ameba" "--format" "flycheck" source)
:error-patterns
((error line-start (file-name) ":" line ":" column ": E: " (message) line-end)
(warning line-start (file-name) ":" line ":" column ": W: " (message) line-end)
(info line-start (file-name) ":" line ":" column ": I: " (message) line-end))
:modes crystal-mode)
(add-to-list 'flycheck-checkers 'crystal-ameba)
#!/bin/bash
# scripts/quality-gate.sh
echo "Running quality gates..."
# Gate 1: Critical errors only
echo "Gate 1: Critical errors"
ameba --only Lint/Syntax,Lint/UnreachableCode --fail-level error
if [ $? -ne 0 ]; then
echo "❌ Critical errors found"
exit 1
fi
# Gate 2: All errors
echo "Gate 2: All errors"
ameba --fail-level error
if [ $? -ne 0 ]; then
echo "❌ Errors found"
exit 1
fi
# Gate 3: Warnings (non-blocking for now)
echo "Gate 3: Warnings (informational)"
ameba --fail-level warning || echo "⚠️ Warnings found (not blocking)"
echo "✅ All quality gates passed"
# .github/workflows/quality-gates.yml
name: Quality Gates
user-invocable: false
on: [push, pull_request]
jobs:
critical:
name: Critical Issues
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: crystal-lang/install-crystal@v1
- run: shards install
- name: Check critical
run: ameba --only Lint/Syntax --fail-level error
errors:
name: All Errors
needs: critical
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: crystal-lang/install-crystal@v1
- run: shards install
- name: Check errors
run: ameba --fail-level error
warnings:
name: Warnings (Main Only)
needs: errors
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: crystal-lang/install-crystal@v1
- run: shards install
- name: Check warnings
run: ameba --fail-level warning
#!/bin/bash
# scripts/ameba-ratchet.sh
# Only fail on new issues, not existing ones
# Get baseline issue count (from main branch)
git fetch origin main
BASELINE=$(git show origin/main:.ameba-baseline.json 2>/dev/null || echo '{"count": 0}')
BASELINE_COUNT=$(echo "$BASELINE" | jq '.count')
# Run Ameba and count current issues
ameba --format json > current-results.json
CURRENT_COUNT=$(jq '.summary.issues_count' current-results.json)
echo "Baseline issues: $BASELINE_COUNT"
echo "Current issues: $CURRENT_COUNT"
if [ "$CURRENT_COUNT" -gt "$BASELINE_COUNT" ]; then
echo "❌ New issues introduced ($((CURRENT_COUNT - BASELINE_COUNT)) new issues)"
exit 1
fi
if [ "$CURRENT_COUNT" -lt "$BASELINE_COUNT" ]; then
echo "✅ Issues reduced! ($((BASELINE_COUNT - CURRENT_COUNT)) fewer issues)"
fi
echo "✅ No new issues"
#!/bin/bash
# scripts/generate-report.sh
ameba --format json > ameba-results.json
# Convert to HTML using jq and template
cat > ameba-report.html <<'EOF'
<!DOCTYPE html>
<html>
<head>
<title>Ameba Report</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
.summary { background: #f0f0f0; padding: 20px; margin-bottom: 20px; }
.issue { border-left: 3px solid red; padding: 10px; margin: 10px 0; }
.error { border-color: #d32f2f; }
.warning { border-color: #f57c00; }
.convention { border-color: #fbc02d; }
</style>
</head>
<body>
<h1>Ameba Code Quality Report</h1>
<div class="summary">
EOF
jq -r '.summary | "
<h2>Summary</h2>
<p>Total Issues: \(.issues_count)</p>
<p>Files Analyzed: \(.target_sources_count)</p>
"' ameba-results.json >> ameba-report.html
echo '<h2>Issues</h2>' >> ameba-report.html
jq -r '.sources[] | select(.issues | length > 0) | .path as $path | .issues[] | "
<div class=\"issue \(.rule.severity | ascii_downcase)\">
<strong>\($path):\(.location.line):\(.location.column)</strong><br>
\(.rule.name): \(.message)
</div>
"' ameba-results.json >> ameba-report.html
echo '</body></html>' >> ameba-report.html
echo "Report generated: ameba-report.html"
#!/bin/bash
# scripts/track-metrics.sh
# Track Ameba metrics over time
TIMESTAMP=$(date +%Y-%m-%d)
ameba --format json > "metrics/ameba-$TIMESTAMP.json"
# Extract key metrics
jq '{
date: "'$TIMESTAMP'",
issues: .summary.issues_count,
files: .summary.target_sources_count,
errors: [.sources[].issues[] | select(.rule.severity == "Error")] | length,
warnings: [.sources[].issues[] | select(.rule.severity == "Warning")] | length
}' "metrics/ameba-$TIMESTAMP.json" >> metrics/history.jsonl
# Generate trend chart (requires gnuplot or similar)
echo "Metrics tracked for $TIMESTAMP"
Use the ameba-integration skill when:
--fail-level to match pipeline requirements--no-verify option for emergenciesUse when typeScript utility types, mapped types, and advanced type manipulation. Use when creating flexible, type-safe TypeScript code.
Use when writing shell scripts that need to run across different systems, shells, or environments. Covers POSIX compatibility and platform differences.
Use when optimizing Tailwind CSS for production, reducing bundle size, and improving performance. Covers PurgeCSS, JIT mode, and build optimization.
Generate production-ready code from a Figma component or frame using the Figma MCP server
Use when integrating Dialyzer into development workflows and CI/CD pipelines for Erlang/Elixir projects.
Use when ruboCop configuration including YAML config, departments, inheritance, and customization.
Use when Elixir OTP patterns including GenServer, Supervisor, Agent, and Task. Use when building concurrent, fault-tolerant Elixir applications.
Use when creating custom Ameba rules for Crystal code analysis including rule development, AST traversal, issue reporting, and rule testing.
Use when swift's optional handling patterns including optional binding, chaining, nil coalescing, and modern approaches to safely working with optional values while avoiding common pitfalls and force unwrapping.
Use when annotating code with structured metadata, tags, and markers for AI-assisted development workflows. Covers annotation formats, semantic tags, and integration with development tools.
Use when scala collections including immutable/mutable variants, List, Vector, Set, Map operations, collection transformations, lazy evaluation with views, parallel collections, and custom collection builders for efficient data processing.
Use when creating custom React Flow nodes, edges, and handles. Covers custom node components, resizable nodes, toolbars, and advanced customization.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience