Skip to content
Skillv1.0.0

elixir-expert

Expert-level Elixir, Phoenix, OTP, and concurrent systems. Use when the user mentions Phoenix, OTP, Erlang, concurrent, or functional, or when the task involves Elixir Fundamentals or Phoenix Framewor

by personamanagmentlayer(0) 0 installs
Free
Sign in to install

Free account. Installing gives you the manifest plus copy-paste snippets.

See reviews

About

Imported from personamanagmentlayer/pcl (stdlib/languages/elixir-expert/SKILL.md). Install upstream with npx skills add personamanagmentlayer/pcl --skill elixir-expert. Copyright stays with the author.

Elixir Expert

Expert guidance for Elixir programming, Phoenix framework, OTP, and building highly concurrent, fault-tolerant systems.

Core Concepts

Elixir Fundamentals

  • Functional programming
  • Pattern matching
  • Immutability
  • Pipe operator
  • Modules and functions
  • Structs and maps

OTP (Open Telecom Platform)

  • GenServer
  • Supervisors
  • Applications
  • Tasks
  • Agents
  • ETS (Erlang Term Storage)

Phoenix Framework

  • Contexts and schemas
  • LiveView
  • Channels (WebSockets)
  • Plug
  • Ecto (database)
  • Testing

Elixir Basics

# Pattern matching
{:ok, result} = {:ok, 42}
[head | tail] = [1, 2, 3, 4]

# Functions
defmodule Math do
  def add(a, b), do: a + b

  def factorial(0), do: 1
  def factorial(n) when n > 0, do: n * factorial(n - 1)
end

# Pipe operator
"hello"
|> String.upcase()
|> String.reverse()
# "OLLEH"

# Anonymous functions
add = fn a, b -> a + b end
add.(1, 2)  # 3

# Capture operator
add = &(&1 + &2)
Enum.map([1, 2, 3], &(&1 * 2))

# Structs
defmodule User do
  defstruct [:id, :name, :email, age: 0]
end

user = %User{id: "123", name: "John", email: "john@example.com"}

# Pattern matching with structs
%User{name: name} = user

# Maps
user_map = %{id: "123", name: "John", email: "john@example.com"}
%{name: name} = user_map

# Conditionals
if user.age >= 18 do
  "Adult"
else
  "Minor"
end

# Case
case user.role do
  :admin -> "Administrator"
  :user -> "Regular user"
  _ -> "Unknown"
end

# Cond
cond do
  user.age < 13 -> "Child"
  user.age < 18 -> "Teen"
  user.age < 65 -> "Adult"
  true -> "Senior"
end

# With
with {:ok, user} <- fetch_user(id),
     {:ok, posts} <- fetch_posts(user.id) do
  {:ok, user, posts}
else
  {:error, reason} -> {:error, reason}
end

GenServer

defmodule UserCache do
  use GenServer

  # Client API
  def start_link(opts \\ []) do
    GenServer.start_link(__MODULE__, %{}, opts)
  end

  def get(server, key) do
    GenServer.call(server, {:get, key})
  end

  def put(server, key, value) do
    GenServer.cast(server, {:put, key, value})
  end

  # Server Callbacks
  @impl true
  def init(initial_state) do
    {:ok, initial_state}
  end

  @impl true
  def handle_call({:get, key}, _from, state) do
    {:reply, Map.get(state, key), state}
  end

  @impl true
  def handle_cast({:put, key, value}, state) do
    {:noreply, Map.put(state, key, value)}
  end

  @impl true
  def handle_info(:cleanup, state) do
    # Periodic cleanup
    {:noreply, state}
  end
end

# Usage
{:ok, cache} = UserCache.start_link()
UserCache.put(cache, :user1, %User{name: "John"})
UserCache.get(cache, :user1)

Supervisors

defmodule MyApp.Application do
  use Application

  @impl true
  def start(_type, _args) do
    children = [
      # Database connection pool
      {MyApp.Repo, []},

      # GenServer workers
      {UserCache, name: UserCache},
      {SessionManager, name: SessionManager},

      # Task supervisor
      {Task.Supervisor, name: MyApp.TaskSupervisor},

      # Phoenix endpoint
      MyAppWeb.Endpoint
    ]

    opts = [strategy: :one_for_one, name: MyApp.Supervisor]
    Supervisor.start_link(children, opts)
  end
end

# Custom supervisor
defmodule WorkerSupervisor do
  use Supervisor

  def start_link(init_arg) do
    Supervisor.start_link(__MODULE__, init_arg, name: __MODULE__)
  end

  @impl true
  def init(_init_arg) do
    children = [
      {Worker, id: :worker1, restart: :permanent},
      {Worker, id: :worker2, restart: :temporary},
      {Worker, id: :worker3, restart: :transient}
    ]

    Supervisor.init(children, strategy: :one_for_one)
  end
end

Ecto

# Schema
defmodule MyApp.Accounts.User do
  use Ecto.Schema
  import Ecto.Changeset

  schema "users" do
    field :name, :string
    field :email, :string
    field :age, :integer
    field :role, Ecto.Enum, values: [:admin, :user, :guest]

    has_many :posts, MyApp.Blog.Post

    timestamps()
  end

  def changeset(user, attrs) do
    user
    |> cast(attrs, [:name, :email, :age, :role])
    |> validate_required([:name, :email])
    |> validate_format(:email, ~r/@/)
    |> validate_number(:age, greater_than: 0, less_than: 150)
    |> unique_constraint(:email)
  end
end

# Queries
import Ecto.Query

# Simple query
Repo.all(from u in User, where: u.age > 18)

# With preload
Repo.all(from u in User, preload: [:posts])

# Complex query
query =
  from u in User,
    join: p in assoc(u, :posts),
    where: u.age > 18,
    group_by: u.id,
    having: count(p.id) > 5,
    select: {u, count(p.id)}

Repo.all(query)

# Dynamic queries
defmodule UserQueries do
  import Ecto.Query

  def base_query, do: from(u in User)

  def filter_by_age(query, min_age) do
    from u in query, where: u.age >= ^min_age
  end

  def filter_by_role(query, role) do
    from u in query, where: u.role == ^role
  end

  def with_posts(query) do
    from u in query, preload: [:posts]
  end
end

# Usage
User
|> UserQueries.base_query()
|> UserQueries.filter_by_age(18)
|> UserQueries.filter_by_role(:admin)
|> UserQueries.with_posts()
|> Repo.all()

Phoenix LiveView

defmodule MyAppWeb.UserLive.Index do
  use MyAppWeb, :live_view

  alias MyApp.Accounts

  @impl true
  def mount(_params, _session, socket) do
    if connected?(socket) do
      Phoenix.PubSub.subscribe(MyApp.PubSub, "users")
    end

    {:ok, assign(socket, users: Accounts.list_users())}
  end

  @impl true
  def handle_event("delete", %{"id" => id}, socket) do
    user = Accounts.get_user!(id)
    {:ok, _} = Accounts.delete_user(user)

    {:noreply, assign(socket, users: Accounts.list_users())}
  end

  @impl true
  def handle_info({:user_created, user}, socket) do
    {:noreply, update(socket, :users, fn users -> [user | users] end)}
  end

  @impl true
  def render(assigns) do
    ~H"""
    <div>
      <h1>Users</h1>
      <table>
        <thead>
          <tr>
            <th>Name</th>
            <th>Email</th>
            <th>Actions</th>
          </tr>
        </thead>
        <tbody>
          <%= for user <- @users do %>
            <tr>
              <td><%= user.name %></td>
              <td><%= user.email %></td>
              <td>
                <button phx-click="delete" phx-value-id={user.id}>
                  Delete
                </button>
              </td>
            </tr>
          <% end %>
        </tbody>
      </table>
    </div>
    """
  end
end

Concurrency

# Tasks
task = Task.async(fn -> expensive_computation() end)
result = Task.await(task)

# Parallel processing
results =
  [1, 2, 3, 4, 5]
  |> Enum.map(&Task.async(fn -> process(&1) end))
  |> Enum.map(&Task.await/1)

# Task supervisor
Task.Supervisor.async_nolink(MyApp.TaskSupervisor, fn ->
  perform_background_job()
end)

# Agents
{:ok, agent} = Agent.start_link(fn -> %{} end)
Agent.update(agent, fn state -> Map.put(state, :key, "value") end)
Agent.get(agent, fn state -> Map.get(state, :key) end)

# ETS
table = :ets.new(:my_table, [:set, :public])
:ets.insert(table, {:key, "value"})
:ets.lookup(table, :key)

Best Practices

Elixir

  • Use pattern matching extensively
  • Leverage pipe operator
  • Write small, focused functions
  • Handle all pattern match cases
  • Use proper error handling
  • Follow naming conventions
  • Write documentation

OTP

  • Use GenServers for state
  • Implement supervisors properly
  • Design for failure
  • Keep processes focused
  • Use process monitoring
  • Implement timeouts
  • Log appropriately

Phoenix

  • Follow context boundaries
  • Use changesets for validation
  • Implement proper authentication
  • Handle errors gracefully
  • Test thoroughly
  • Use LiveView for interactivity
  • Optimize queries

Anti-Patterns

❌ Using mutable state ❌ Long-running GenServer calls ❌ Not supervising processes ❌ Ignoring errors ❌ Large modules ❌ N+1 query problems ❌ Not using pattern matching

Reference Documentation

Detailed material lives alongside this skill and is read on demand:

Resources

Use it

Copy one of these into your project. Installing also returns the manifest and these snippets.

yaml
targets:
  - https://api.opensmartroute.ai/api/v1/registry/personamanagmentlayer-pcl-elixir-expert/manifest   # or paste the manifest below

Manifest

An Open Capability Manifest: the router reads it to know what this does, what it costs and when to pick it.

personamanagmentlayer-pcl-elixir-expert.ocm.jsonjson
{
  "ocm": "1",
  "id": "personamanagmentlayer-pcl-elixir-expert",
  "kind": "skill",
  "name": "elixir-expert",
  "description": "Expert-level Elixir, Phoenix, OTP, and concurrent systems. Use when the user mentions Phoenix, OTP, Erlang, concurrent, or functional, or when the task involves Elixir Fundamentals or Phoenix Framework.",
  "publisher": "personamanagmentlayer",
  "version": "1.0.0",
  "capabilities": {
    "domains": [
      "general"
    ],
    "tags": [
      "skill-md",
      "elixir",
      "phoenix",
      "otp",
      "erlang",
      "concurrent",
      "functional",
      "skills-sh"
    ],
    "languages": [
      "en"
    ]
  },
  "quality_prior": 0.6,
  "examples": [
    "Expert-level Elixir, Phoenix, OTP, and concurrent systems. Use when the user mentions Phoenix, OTP, Erlang, concurrent, or functional, or when the task involves Elixir Fundamentals or Phoenix Framework."
  ],
  "primary": false,
  "metadata": {
    "source": {
      "provider": "skills.sh",
      "repository": "https://github.com/personamanagmentlayer/pcl",
      "path": "stdlib/languages/elixir-expert/SKILL.md",
      "ref": "HEAD",
      "url": "https://github.com/personamanagmentlayer/pcl/blob/HEAD/stdlib/languages/elixir-expert/SKILL.md",
      "key": "personamanagmentlayer/pcl/stdlib/languages/elixir-expert/SKILL.md"
    },
    "allowed_tools": [
      "Read",
      "Write",
      "Edit",
      "Bash(elixir:*, mix:*)"
    ]
  },
  "instructions": "# Elixir Expert\n\nExpert guidance for Elixir programming, Phoenix framework, OTP, and building highly concurrent, fault-tolerant systems.\n\n## Core Concepts\n\n### Elixir Fundamentals\n\n- Functional programming\n- Pattern matching\n- Immutability\n- Pipe operator\n- Modules and functions\n- Structs and maps\n\n### OTP (Open Telecom Platform)\n\n- GenServer\n- Supervisors\n- Applications\n- Tasks\n- Agents\n- ETS (Erlang Term Storage)\n\n### Phoenix Framework\n\n- Contexts and schemas\n- LiveView\n- Channels (WebSockets)\n- Plug\n- Ecto (database)\n- Testing\n\n## Elixir Basics\n\n```elixir\n# Pattern matching\n{:ok, result} = ",
  "cost": {
    "context_tokens": 2053
  }
}

Fetch it by URL: GET /api/v1/registry/personamanagmentlayer-pcl-elixir-expert/manifest?version=1.0.0

Reviews

Star ratings from people who tried it. One review per account; edit yours any time.

No reviews yet. Install it, try it, and be the first to rate it.