elixir/SKILL.md
Elixir development: Ash Framework, Phoenix, Credo, LLM interaction safety. Use when working on Elixir/Ash/Phoenix projects.
npx skillsauth add snqb/my-skills elixirInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Specialist in Elixir development with focus on code quality, static analysis, and modern framework patterns (Ash, Phoenix).
Official Guidance: https://hexdocs.pm/ash/working-with-llms.html
Reality Check: LLMs frequently hallucinate Ash APIs, function signatures, and patterns despite training data. Ash evolves rapidly (3.x is very different from 2.x), and LLMs often mix outdated patterns with current APIs.
Common Hallucinations:
:allow_nil? instead of :allow_nil?)Ash.Query.get vs Ash.get)Your Responsibility: Always verify against official docs before using generated code. When it compiles but fails at runtime, suspect hallucination first.
When seeking help in Ash community (Discord/GitHub/Forum), you MUST:
Why: Maintainers need to know if patterns come from hallucination vs misunderstanding. Saves everyone time.
Channels:
Tidewave MCP - Interrogate running Phoenix apps
project_eval: Execute Elixir code in live app contextsearch_package_docs: Search Hexdocs for current package versionsmix phx.server)Ash AI dev MCP - Ash-specific development server
list_generators: Discover available Ash generatorsWhat: Maintainer-approved patterns aggregated from package docs Why: Reduces hallucination by providing vetted examples as context
Setup:
# Install usage_rules package
mix deps.get
# Aggregate rules from all dependencies
mix usage_rules.sync .rules --all
# Or specify packages explicitly
mix usage_rules.sync .rules \
ash ash_postgres ash_phoenix ash_graphql ash_json_api ash_ai
# Include .rules/ in your project for LLM context
Result: .rules/ directory contains markdown files with canonical patterns for each package.
Provide to LLM: When working on Ash code, include relevant .rules/*.md files in context.
Official Hexdocs: https://hexdocs.pm/ash/
Workflow:
search_package_docs (Tidewave) for version-specific APIsproject_eval (Tidewave)Before trusting LLM-generated Ash code:
project_eval or manual).rules/ files (if using usage_rules)Purpose: Code quality, refactoring detection, complexity analysis, consistency enforcement
Installation:
# mix.exs
{:credo, "~> 1.7", only: [:dev, :test], runtime: false}
Usage:
# Run full analysis
mix credo
# Run strict mode (warnings as errors)
mix credo --strict
# Focus on specific checks
mix credo --checks-without-tag formatting
# Explain a specific issue
mix credo explain path/to/file.ex:42
# CI integration (exit code on issues)
mix credo --strict --format=json
Configuration (.credo.exs):
%{
configs: [
%{
name: "default",
files: %{
included: ["lib/", "src/", "test/", "web/", "apps/"],
excluded: [~r"/_build/", ~r"/deps/", ~r"/node_modules/"]
},
checks: [
# Enable/disable specific checks
{Credo.Check.Design.AliasUsage, priority: :low, if_nested_deeper_than: 2},
{Credo.Check.Refactor.CyclomaticComplexity, max_complexity: 12},
{Credo.Check.Refactor.FunctionArity, max_arity: 5},
# Disable checks you don't need
{Credo.Check.Readability.ModuleDoc, false}
]
}
]
}
Key Checks:
Editor Integration:
# Project management
mix new my_app # New project
mix new my_app --sup # With supervision tree
# Dependencies
mix deps.get # Install dependencies
mix deps.update --all # Update all deps
mix deps.clean --unused # Remove unused deps
# Development
mix compile # Compile project
mix compile --warnings-as-errors # Strict compilation
mix test # Run tests
mix test --trace # Slow tests with full output
mix format # Auto-format code
# Release
mix release # Build production release
MIX_ENV=prod mix release # Production release
search_package_docs (Tidewave MCP) or Ash AI dev MCP to find relevant documentationlist_generators (Ash AI MCP) to discover available generators--yes for automation)project_eval (Tidewave MCP) to test code in running app# Combine rules from all dependencies
mix usage_rules.sync .rules --all
# Specific package rules
mix usage_rules.sync .rules \
ash ash_postgres ash_phoenix ash_graphql ash_json_api ash_ai
# Generate a new resource
mix ash.gen.resource MyResource name:string age:integer
# Generate with domain
mix ash.gen.resource MyApp.Accounts.User name:string email:string
# Generate API
mix ash.gen.api MyApi
# Generate flow
mix ash.gen.flow MyFlow
defmodule MyApp.Accounts.User do
use Ash.Resource,
data_layer: AshPostgres.DataLayer,
extensions: [AshJsonApiResource, AshGraphqlResource]
attributes do
uuid_primary_key :id
attribute :name, :string, allow_nil?: false
attribute :email, :string, allow_nil?: false
attribute :age, :integer
timestamps()
end
relationships do
belongs_to :profile, MyApp.Accounts.Profile
has_many :posts, MyApp.Blog.Post
end
actions do
defaults [:read, :create, :update, :destroy]
read :by_name do
argument :name, :string
filter expr(name == ^arg(:name))
end
end
code_interface do
define_for MyApp.Accounts
define :create_user, args: [:name, :email]
define :get_user_by_name, args: [:name], action: :by_name
end
end
defmodule MyApp.Accounts do
use Ash.Domain
resources do
resource MyApp.Accounts.User
resource MyApp.Accounts.Profile
end
end
# mix.exs
defp deps do
[
{:ash, "~> 3.0"},
{:ash_postgres, "~> 2.0"},
{:ash_phoenix, "~> 2.0"},
{:ash_json_api, "~> 1.0"},
{:ash_graphql, "~> 1.0"},
{:phoenix, "~> 1.7"},
{:ecto_sql, "~> 3.10"},
{:credo, "~> 1.7", only: [:dev, :test], runtime: false}
]
end
defmodule MyAppWeb.UserLive do
use MyAppWeb, :live_view
def mount(_params, _session, socket) do
{:ok, assign(socket, :users, MyApp.Accounts.read_user!())}
end
def handle_event("create", %{"user" => params}, socket) do
case MyApp.Accounts.create_user(params) do
{:ok, user} ->
{:noreply, assign(socket, users: [user | socket.assigns.users])}
{:error, _} ->
{:noreply, put_flash(socket, :error, "Failed to create user")}
end
end
end
defmodule MyApp.Accounts.UserTest do
use ExUnit.Case
use MyApp.DataCase
test "creates user with valid attributes" do
attrs = %{name: "John", email: "[email protected]"}
assert {:ok, user} = MyApp.Accounts.create_user(attrs)
assert user.name == "John"
assert user.email == "[email protected]"
end
test "fails with invalid email" do
attrs = %{name: "John", email: "invalid"}
assert {:error, error} = MyApp.Accounts.create_user(attrs)
assert error.errors[:email]
end
end
# Run all tests
mix test
# Run specific test file
mix test test/my_app/accounts_test.exs
# Run specific test line
mix test test/my_app/accounts_test.exs:42
# Run with coverage
mix test --cover
# Run with traces (slower but detailed)
mix test --trace
case MyApp.Accounts.create_user(params) do
{:ok, user} ->
# Success path
{:error, %Ash.Error.Changes.Invalid{} = error} ->
# Handle validation errors
{:error, error} ->
# Handle other errors
end
with {:ok, user} <- MyApp.Accounts.create_user(params),
{:ok, profile} <- MyApp.Accounts.create_profile(user, profile_params) do
{:ok, {user, profile}}
else
{:error, error} -> {:error, error}
end
# config/dev.exs
config :my_app, MyApp.Repo,
username: "postgres",
password: "postgres",
hostname: "localhost",
database: "my_app_dev",
stacktrace: true,
show_sensitive_data_on_connection_error: true
# Runtime configuration
config :my_app, :ash_apis, [MyApp.Api]
# Logger configuration
config :logger, :console,
format: "$time $metadata[$level] $message\n",
metadata: [:request_id]
defmodule MyApp.Repo.Migrations.CreateUsers do
use Ecto.Migration
def change do
create table(:users, primary_key: false) do
add :id, :binary_id, primary_key: true
add :name, :string, null: false
add :email, :string, null: false
add :age, :integer
timestamps()
end
create unique_index(:users, [:email])
end
end
mix credo regularly (integrate into CI)|> for data transformationswith for multiple operationsmix formatBefore committing:
# 1. Format code
mix format
# 2. Run tests
mix test
# 3. Check code quality
mix credo --strict
# 4. Compile with warnings as errors
mix compile --warnings-as-errors
# 5. Check coverage (optional)
mix test --cover
# Start new feature
git checkout -b feature/user-notifications
# Run Credo to see baseline
mix credo
# Write tests first
# test/my_app/notifications_test.exs
# Run tests (they should fail)
mix test
# Implement feature
# lib/my_app/notifications.ex
# Run tests again (should pass)
mix test
# Check code quality
mix credo --strict
# Format code
mix format
# Commit
git add .
git commit -m "Add user notifications feature"
Remember: Verify LLM outputs, use generators first, think "Ash way", leverage MCP tools.
documentation
Enrich Markdown articles with inline Wikipedia links. First mention of each notable entity gets a hyperlink. Use when asked to add wiki links, enrich, or add references to .md files.
development
Structured visual QA: screenshot → batch issues → fix all → verify. Replaces the 300-cycle screenshot→edit death spiral. Optional bishkek review as exit gate. Use when building/polishing UI with browser testing, or when user asks for N iterations/reviews.
development
Find complex code, analyze intent, recommend battle-tested library replacements. Uses radon/eslint for detection, GitHub quality search for alternatives.
research
Research real-world UI patterns from curated galleries (Collect UI, Component Gallery, Mobbin). Use when exploring what exists: dropdowns, accordions, inputs, navigation, cards, modals, etc.