Install any skill in seconds. Free to start, no credit card required.
Get Started Free →OTP/BEAM patterns and Elixir idioms — GenServer, Supervisor, Task, Registry, pattern matching, with chains, pipes. Use when designing processes or debugging BEAM issues.
.claude/skills/oliver-kriska-elixir-idioms/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-10 | ✗→✓ | ▲ Improved | -9% | 0% |
| case-14 | ✗→✓ | ▲ Improved | -20% | 0% |
| case-21 | ✗→✓ | ▲ Improved | 130% | 0% |
| case-01 | ✓→✓ | = Same ✓ | 49% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 37% | 0% |
Reference for writing idiomatic Elixir code with BEAM-aware patterns.
and/or/not — Never use short-circuit operators in guards (guards require boolean operands)cast/4 for user input, change/2 for internalString.to_atom(user_input) causes memory leak (atoms aren't GC'd)@external_resourceGenServer.start_link/Agent.start_link in production. Use supervision treesMix.Task.run("app.config") + Application.ensure_all_started/1, never Mix.Task.run("app.start") (boots the FULL tree: endpoint port, Oban consuming)case, then cond{:ok, _}/{:error, _} for expected errors, raise for bugsNeed patterns? → case (or function heads)
Multiple operations? → with
Boolean conditions? → cond (multiple) or if (single)Expected failure? → {:ok, _}/{:error, _} tuples
Unexpected/bug? → raise exception (let supervisor handle)
External library? → rescue (only here!)Need state?
├─ No → Plain functions
├─ Simple get/update → Agent or ETS
├─ Complex messages/timeouts → GenServer
└─ One-off async → Taskelixir# Pattern match in function head def process(%{status: :active} = user), do: activate(user) def process(%{status: :inactive} = user), do: deactivate(user) # with for happy path with {:ok, user} <- get_user(id), {:ok, order} <- create_order(user) do {:ok, order} end # Task for async Task.Supervisor.async_nolink(TaskSup, fn -> work() end) |> Task.yield(5000) || Task.shutdown(task)
| Wrong | Right | |-------|-------| | length(list) == 0 | list == [] or Enum.empty?(list) | | list ++ [item] | [item \| list] \|> Enum.reverse() | | String.to_atom(input) | String.to_existing_atom(input) | | spawn(fn -> log(conn) end) | ip = conn.ip; spawn(fn -> log(ip) end) | | unless condition | if !condition (unless deprecated in 1.18) |
For detailed patterns, see:
references/pattern-matching.md - Pattern matching, guards, binary matchingreferences/otp-patterns.md - GenServer, Supervisor, Task, Registryreferences/error-handling.md - Tagged tuples, rescue, withreferences/with-and-pipes.md - When to use with and |> (idiomatic patterns)references/troubleshooting.md - Production BEAM debugging (memory, performance, crashes)references/anti-patterns.md - Common mistakes and fixesreferences/mix-tasks.md - Mix task naming, option parsing, shell outputreferences/elixir-118-features.md - Duration module, dbg improvements (1.18+)references/elixir-120-type-system.md - Gradual type checker, dynamic(), verified bugs as compile warnings (1.20+, OTP 27+)| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | pass→pass | 11,663 | 10,427 | -11% | 1 | 1 | 0% | 2,142 | 3,194 | +49% | 0 | 0 | — |
case-02 | pass→pass | 12,452 | 9,723 | -22% | 1 | 1 | 0% | 2,052 | 2,811 | +37% | 0 | 0 | — |
case-03 | pass→pass | 12,078 | 8,578 | -29% | 1 | 1 | 0% | 2,205 | 2,736 | +24% | 0 | 0 | — |
case-04 | pass→pass | 11,602 | 9,280 | -20% | 1 | 1 | 0% | 1,930 | 2,833 | +47% | 0 | 0 | — |
case-05 | pass→pass | 11,547 | 5,929 | -49% | 1 | 1 | 0% | 1,944 | 2,301 | +18% | 0 | 0 | — |
case-06 | pass→pass | 10,443 | 7,740 | -26% | 1 | 1 | 0% | 1,817 | 2,620 | +44% | 0 | 0 | — |
case-07 | pass→pass | 2,820 | 2,637 | -6% | 1 | 1 | 0% | 445 | 1,656 | +272% | 0 | 0 | — |
case-08 | pass→pass | 10,234 | 9,610 | -6% | 1 | 1 | 0% | 1,650 | 2,914 | +77% | 0 | 0 | — |
case-09 | pass→pass | 12,983 | 6,953 | -46% | 1 | 1 | 0% | 2,431 | 2,472 | +2% | 0 | 0 | — |
case-10 | fail→pass | 17,553 | 8,464 | -52% | 1 | 1 | 0% | 2,918 | 2,662 | -9% | 0 | 0 | — |
case-11 | pass→pass | 9,711 | 9,270 | -5% | 1 | 1 | 0% | 1,684 | 2,875 | +71% | 0 | 0 | — |
case-12 | pass→pass | 8,383 | 5,132 | -39% | 1 | 1 | 0% | 1,455 | 2,086 | +43% | 0 | 0 | — |
case-13 | pass→pass | 11,286 | 6,182 | -45% | 1 | 1 | 0% | 2,003 | 2,235 | +12% | 0 | 0 | — |
case-14 | fail→pass | 12,814 | 2,633 | -79% | 1 | 1 | 0% | 2,100 | 1,672 | -20% | 0 | 0 | — |
case-15 | pass→pass | 4,072 | 5,027 | +23% | 1 | 1 | 0% | 700 | 2,188 | +213% | 0 | 0 | — |
case-16 | pass→pass | 9,035 | 7,920 | -12% | 1 | 1 | 0% | 1,492 | 2,642 | +77% | 0 | 0 | — |
case-17 | pass→pass | 11,602 | 6,909 | -40% | 1 | 1 | 0% | 2,010 | 2,456 | +22% | 0 | 0 | — |
case-18 | pass→pass | 4,892 | 4,660 | -5% | 1 | 1 | 0% | 784 | 2,000 | +155% | 0 | 0 | — |
case-19 | pass→pass | 15,445 | 12,096 | -22% | 1 | 1 | 0% | 2,508 | 3,310 | +32% | 0 | 0 | — |
case-20 | pass→pass | 10,927 | 7,197 | -34% | 1 | 1 | 0% | 1,967 | 2,591 | +32% | 0 | 0 | — |
case-21 | fail→pass | 5,405 | 5,839 | +8% | 1 | 1 | 0% | 977 | 2,245 | +130% | 0 | 0 | — |
case-22 | pass→pass | 6,410 | 3,839 | -40% | 1 | 1 | 0% | 1,082 | 1,906 | +76% | 0 | 0 | — |
case-23 | pass→pass | 2,090 | 2,184 | +4% | 1 | 1 | 0% | 391 | 1,571 | +302% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +13 percentage points is the difference between those two pass rates over the 23 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.