Agent skill

Idiomatic Elixir

by georgeguimaraes in georgeguimaraes/elixir-agent-tools

Writes and refactors idiomatic Elixir modules and functions, with rules for pattern matching, error handling, protocols and when a process is really needed.

Apache-2.0Auto-check passedDevelopment

Install Idiomatic Elixir

skills CLI
$ npx skills add georgeguimaraes/elixir-agent-tools --skill elixir -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install georgeguimaraes/elixir-agent-tools elixir --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/georgeguimaraes/elixir-agent-tools.git skills-src && mkdir -p .claude/skills && cp -r skills-src/plugins/elixir-dev/skills/elixir .claude/skills/elixir && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
elixir
GitHub stars
184
Token cost
~2.1k tokens
SKILL.md length
879 words
Files
1
Skills in repo
5
Repo updated
First seen
Licence
Apache-2.0

At a glance

Writes and refactors idiomatic Elixir modules and functions, with rules for pattern matching, error handling, protocols and when a process is really needed.

  • Works in 3 steps: Do I need mutable state persisting… → Do I need concurrent execution? → Do I need fault isolation?
  • Writing a new Elixir module with clear data structures and functions
  • SKILL.md covers The Iron Law, The Three Decoupled Dimensions, "Let It Crash" = "Let It Heal" and Control Flow, plus 8 more sections
  • Calls brew and apt

What it does

Its guiding rule is no process without a runtime reason: before creating a GenServer, Agent or any process, the code must need persistent mutable state, concurrent execution or fault isolation. If all three answers are no, plain functions and modules are the answer, since modules organize code and processes manage runtime. A table contrasts OOP's coupling of behavior, state and mutability with Elixir's split into modules, data and processes.

Control flow starts with pattern matching in function heads rather than if and case in bodies, notes that an empty map pattern matches any map, avoids nested case in favor of with or separate functions, and uses ok and error tuples for expected failures instead of exceptions. It warns against catch-all clauses that return nil and against nil-punning with the and operator. Let it crash is explained as supervisors restarting processes after unexpected errors.

For polymorphism it prefers behaviours for modules, protocols only when composing data types and message passing only for state that is stateful by design, using the simplest abstraction that works. Process design and supervision are handed to a separate otp skill.

When your agent uses it

  • Writing a new Elixir module with clear data structures and functions
  • Refactoring nested case expressions into with or function heads
  • Deciding whether a feature needs a GenServer at all
  • Choosing between behaviours and protocols

Example prompts

  • “Refactor this nested case in the order import module using with.”
  • “Do I need a GenServer for caching exchange rates, or will plain functions do?”
  • “Design a behaviour for our payment providers and write two implementations.”

Requirements

  • Elixir and Mix for compiling and testing the code

Workflow steps

3 steps, taken from the first numbered list in SKILL.md.

  1. Do I need mutable state persisting across calls?
  2. Do I need concurrent execution?
  3. Do I need fault isolation?

What it can do on your machine

Read from SKILL.md and the folder at commit ac3a5a1. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • brew
    • apt

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Idiomatic Elixir loads about 2.1k tokens when it runs. Until then it costs about 62 tokens; SKILL.md has 879 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~62
When it runs · the whole SKILL.md, loaded when a task matches
~2.1k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from georgeguimaraes/elixir-agent-tools at commit ac3a5a1, republished under its Apache-2.0 licence (© georgeguimaraes). 879 words, ~2,079 tokens.

Download SKILL.mdSave it as .claude/skills/elixir/SKILL.md (or your agent's skills folder).
name
elixir
description
Write and refactor idiomatic Elixir functions, modules, and data structures. Use for pattern matching, control flow, error handling, protocols, behaviours, and deciding whether a process is needed. Use otp for process design and supervision.

Elixir

Design modules, model data, and handle errors with Elixir's functional idioms.

The Iron Law

NO PROCESS WITHOUT A RUNTIME REASON

Before creating a GenServer, Agent, or any process, answer YES to at least one:

  1. Do I need mutable state persisting across calls?
  2. Do I need concurrent execution?
  3. Do I need fault isolation?

All three are NO? Use plain functions. Modules organize code; processes manage runtime.

The Three Decoupled Dimensions

OOP couples behavior, state, and mutability together. Elixir decouples them:

OOP DimensionElixir Equivalent
BehaviorModules (functions)
StateData (structs, maps)
MutabilityProcesses (GenServer)

Pick only what you need. "I only need data and functions" = no process needed.

"Let It Crash" = "Let It Heal"

The misconception: Write careless code. The truth: Supervisors START processes.

  • Handle expected errors explicitly ({:ok, _} / {:error, _})
  • Let unexpected errors crash → supervisor restarts

Control Flow

Pattern matching first:

  • Match on function heads instead of if/else or case in bodies
  • %{} matches ANY map—use map_size(map) == 0 guard for empty maps
  • Avoid nested case—refactor to single case, with, or separate functions

Error handling:

  • Use {:ok, result} / {:error, reason} for operations that can fail
  • Avoid raising exceptions for control flow
  • Use with for chaining {:ok, _} / {:error, _} operations

Be explicit about expected cases:

  • Avoid _ -> nil catch-alls—they silently swallow unexpected cases
  • Avoid value && value.field nil-punning—obscures actual return types
  • When a case has {:ok, nil} -> nil alongside {:ok, value} -> value.field, use with instead:
elixir
# Verbose
case get_run(id) do
  {:ok, nil} -> nil
  {:ok, run} -> run.recommendations
end

# Prefer
with {:ok, %{recommendations: recs}} <- get_run(id), do: recs

Polymorphism

For Polymorphism Over...UseContract
ModulesBehaviorsUpfront callbacks
DataProtocolsUpfront implementations
ProcessesMessage passingImplicit (send/receive)

Behaviors = default for module polymorphism (very cheap at runtime) Protocols = only when composing data types, especially built-ins Message passing = only when stateful by design (IO, file handles)

Use the simplest abstraction: pattern matching → anonymous functions → behaviors → protocols → message passing. Each step adds complexity.

When justified: Library extensibility, multiple implementations, test swapping. When to stay coupled: Internal module, single implementation, pattern matching handles all cases.

Data Modeling Replaces Class Hierarchies

OOP: Complex class hierarchy + visitor pattern. Elixir: Model as data + pattern matching + recursion.

elixir
{:sequence, {:literal, "rain"}, {:repeat, {:alternation, "dogs", "cats"}}}

def interpret({:literal, text}, input), do: ...
def interpret({:sequence, left, right}, input), do: ...
def interpret({:repeat, pattern}, input), do: ...

Defaults and Options

Use /3 variants (Keyword.get/3, Map.get/3) instead of case statements branching on nil:

elixir
# WRONG
case Keyword.get(opts, :chunker) do
  nil -> chunker()
  config -> parse_chunker_config(config)
end

# RIGHT
Keyword.get(opts, :chunker, :default) |> parse_chunker_config()

Don't create helper functions to merge config defaults. Inline the fallback:

elixir
# WRONG
defp merge_defaults(opts), do: Keyword.merge([repo: Application.get_env(:app, :repo)], opts)

# RIGHT
def some_function(opts) do
  repo = opts[:repo] || Application.get_env(:app, :repo)
end

Idioms

  • Process dictionary is typically unidiomatic—pass state explicitly
  • Reserve is_thing names for guards only
  • Use structs over maps when shape is known: defstruct [:name, :age]
  • Prepend to lists [new | list] not list ++ [new]
  • Use dbg/1 for debugging—prints formatted value with context
  • Use built-in JSON module (Elixir 1.18+) instead of Jason

Verification

Inside coding agents, always prefix mix commands with unbuffer to get ANSI colors and prevent stdout block-buffering in non-TTY environments (e.g. unbuffer mix test). Install: brew install expect (macOS) or apt install expect (Linux). If unbuffer is unavailable, report the missing prerequisite instead of silently dropping it.

After changing Elixir code, verify the completed change before reporting it as done. Run commands from the relevant Mix project using its pinned Elixir/OTP versions. Follow the repository's contribution instructions and existing check aliases. Prefer an alias when it covers the checks below, and run any uncovered checks separately:

  1. Format changed files with unbuffer mix format path/to/file.ex path/to/test.exs, following the project's formatter configuration.
  2. Compile with unbuffer mix compile --warnings-as-errors to catch compilation errors and warnings.
  3. Run relevant tests with unbuffer mix test test/path/to/affected_test.exs. Run the broader suite when the change affects shared behavior or the repository requires it.
  4. Run unbuffer mix credo when Credo is configured, using the repository's flags and configuration.

Fix failures introduced by the change and rerun the affected checks. Report the commands actually run and their results, including any checks that were skipped or blocked and why. An unrun or blocked check hasn't passed.

Show full SKILL.md (276 more words)Show less

Testing

Prefer pattern matching over imperative assertions. Never use assert length + Enum.at/List.last/hd. Pattern match checks length and content in one shot:

elixir
# Bad
assert length(students) == 2
assert Enum.at(students, 0).name == "Alice"
assert Enum.at(students, 1).name == "Bob"

# Good
assert [%{name: "Alice"}, %{name: "Bob"}] = students

Same goes for type-only predicates: assert is_map(user) / assert is_list(posts) pass for almost any non-error return. Pattern match the shape and content together: assert %User{email: "a@b.com"} = user. is_nil/1 is fine when nil-ness is the whole point.

Test behavior, not implementation. Test use cases / public API. Refactoring shouldn't break tests.

Test your code, not the framework. If deleting your code doesn't fail the test, it's tautological.

Keep tests async. async: false means you've coupled to global state. Fix the coupling:

ProblemSolution
Application.put_envPass config as function argument
Feature flagsInject via process dictionary or context
ETS tablesCreate per-test tables with unique names
External APIsUse Mox with explicit allowances
File system operationsUse @tag :tmp_dir (see below)

Use tmp_dir for file tests. ExUnit creates unique temp directories per test, async-safe:

elixir
@tag :tmp_dir
test "writes file", %{tmp_dir: tmp_dir} do
  path = Path.join(tmp_dir, "test.txt")
  File.write!(path, "content")
  assert File.read!(path) == "content"
end

Directory is auto-cleaned before each run. Works with @moduletag :tmp_dir for all tests in module.

Common Rationalizations

ExcuseReality
"I need a process to organize this code"Modules organize code. Processes are for runtime.
"GenServer is the Elixir way"Plain functions are also the Elixir way.
"I'll need state eventually"YAGNI. Add process when you need it.
"It's just a simple wrapper process"Simple wrappers become bottlenecks.
"This is how I'd structure it in OOP"Rethink from data flow.

Red Flags - STOP and Reconsider

  • Creating process without answering the three questions
  • Using GenServer for stateless operations
  • Wrapping a library in a process "for safety"
  • One process per entity without runtime justification
  • Reaching for protocols when pattern matching works

Any of these? Re-read The Iron Law.

© georgeguimaraes, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in plugins/elixir-dev/skills/elixir of georgeguimaraes/elixir-agent-tools.

Open the folder on GitHubat commit ac3a5a1

Compare with similar skills

Idiomatic Elixir next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Idiomatic Elixir compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Idiomatic Elixir this skillgeorgeguimaraes/elixir-agent-tools184—~2.1kAutomated safety check: PassApache-2.0
Clean Codejd-solanki/slidev-theme-dracula1611 repos~3.8kAutomated safety check: PassMIT
Elixir AntipatternsGentleman-Programming/Gentleman-Skills657—~2.1kAutomated safety check: PassMIT
fp-go Functional Programming for GoIBM/fp-go2k—~8.5kAutomated safety check: PassApache-2.0
Swiftui View RefactorDimillian/Skills4k5 repos~2kAutomated safety check: PassMIT
Rust Best Practicesfarm-fe/farm5.6k3 repos~1.1kAutomated safety check: PassMIT

Similar skills

  • Clean Code

    jd-solanki/slidev-theme-dracula

    Write readable, maintainable code through disciplined naming, small functions, and clean error handling.

    161 GitHub starsUsed in 1 repo~3.8k tokens
    DevelopmentAuto-check passed
  • Elixir Antipatterns

    Gentleman-Programming/Gentleman-Skills

    Core catalog of 8 critical Elixir/Phoenix anti-patterns covering error handling, separation of concerns, Ecto queries, and testing.

    657 GitHub stars~2.1k tokensUpdated 6 mo ago
    DevelopmentAuto-check passed
  • Entry point for writing and reviewing Go code with the fp-go v2 library: core monad types, data-last composition, type parameter order and import conventions.

    2k GitHub stars~8.5k tokensUpdated yesterday
    DevelopmentAuto-check passed
  • Swiftui View Refactor

    Dimillian/Skills

    Refactor and review SwiftUI view files with strong defaults for small dedicated subviews, MV-over-MVVM data flow, stable view trees, explicit dependency injection, and correct Observation usage.

    4k GitHub starsUsed in 5 repos~2k tokens
    DevelopmentAuto-check passed
  • Guide for writing idiomatic Rust code based on Apollo GraphQL's best practices handbook.

    5.6k GitHub starsUsed in 3 repos~1.1k tokens
    DevelopmentAuto-check passed
  • Describes seven Rust design patterns for the RTK CLI filter modules, with when to use each, RTK examples, and notes on when a pattern is overkill.

    83k GitHub stars~1.9k tokensUpdated yesterday
    DevelopmentAuto-check passed

More from georgeguimaraes/elixir-agent-tools

  • Ecto Persistence Patterns

    georgeguimaraes/elixir-agent-tools

    Designs and debugs Elixir persistence with Ecto: schemas, changesets, queries, preloads, migrations and multi-tenancy, kept within application contexts.

    184 GitHub stars~1.2k tokensUpdated 18 days ago
    Auto-check passed
  • Oban Background Jobs

    georgeguimaraes/elixir-agent-tools

    Guidance for building and debugging durable background jobs in Elixir with Oban and Oban Pro, covering serialization, retries, uniqueness, chaining, chunking and workflows.

    184 GitHub stars~2.2k tokensUpdated 18 days ago
    Auto-check passed
  • Elixir OTP Concurrency

    georgeguimaraes/elixir-agent-tools

    Guides choices among GenServer, Supervisor, Task, Registry, ETS and Broadway when designing or debugging Elixir concurrency, state and fault recovery.

    184 GitHub stars~1.2k tokensUpdated 18 days ago
    Auto-check passed
  • Phoenix LiveView Patterns

    georgeguimaraes/elixir-agent-tools

    Guidance for building and debugging Phoenix web interfaces: where LiveView loads data, scopes, PubSub topics, external polling and component state.

    184 GitHub stars~1.3k tokensUpdated 18 days ago
    Auto-check passed

Works with

Categories

Questions about Idiomatic Elixir

What does Idiomatic Elixir do?

Writes and refactors idiomatic Elixir modules and functions, with rules for pattern matching, error handling, protocols and when a process is really needed. Its guiding rule is no process without a runtime reason: before creating a GenServer, Agent or any process, the code must need persistent mutable state, concurrent execution or fault isolation. If all three answers are no, plain functions and modules are the answer, since modules organize code and processes manage runtime.

When should I use Idiomatic Elixir?

Idiomatic Elixir fits situations like: writing a new Elixir module with clear data structures and functions; refactoring nested case expressions into with or function heads; deciding whether a feature needs a GenServer at all; choosing between behaviours and protocols.

How do I install Idiomatic Elixir in Claude Code?

Run `npx skills add georgeguimaraes/elixir-agent-tools --skill elixir -a claude-code`. Or copy the skill folder (plugins/elixir-dev/skills/elixir in georgeguimaraes/elixir-agent-tools) into .claude/skills/elixir in your project. Claude Code loads it when a task matches its description.

How do I install Idiomatic Elixir in Codex?

Run `npx skills add georgeguimaraes/elixir-agent-tools --skill elixir -a codex`. Or copy the skill folder (plugins/elixir-dev/skills/elixir in georgeguimaraes/elixir-agent-tools) into .agents/skills/elixir in your project. Codex loads it when a task matches its description.

Can I use Idiomatic Elixir in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add georgeguimaraes/elixir-agent-tools --skill elixir -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/elixir, .gemini/skills/elixir, .github/skills/elixir and .opencode/skills/elixir in your project.

What does Idiomatic Elixir need to run?

Going by SKILL.md and its folder, Idiomatic Elixir needs the command-line tools its instructions call (brew and apt). Our summary lists: Elixir and Mix for compiling and testing the code.

Does Idiomatic Elixir access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Idiomatic Elixir safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Idiomatic Elixir use?

Idiomatic Elixir is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Idiomatic Elixir use?

About 2.1k tokens (SKILL.md is roughly 8.3k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Idiomatic Elixir?

Skills that share tags, products or a category with Idiomatic Elixir: Clean Code (jd-solanki/slidev-theme-dracula, 161 stars), Elixir Antipatterns (Gentleman-Programming/Gentleman-Skills, 657 stars), fp-go Functional Programming for Go (IBM/fp-go, 2k stars) and Swiftui View Refactor (Dimillian/Skills, 4k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Idiomatic Elixir?

georgeguimaraes (a GitHub user) maintains it in georgeguimaraes/elixir-agent-tools, which has 184 GitHub stars. The repository holds 5 skills in this directory. The repository was last updated on September 20, 2026.

Source: georgeguimaraes/elixir-agent-tools on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.