skillZs
★ LIVE SKILL TAGS ★
>>> LIVE SKILLS INDEX <<<
* OPEN SOURCE *
NO LOGIN, NO TRACKING
※ REAL INSTALL DATA ※
← back to all skills
personamanagmentlayer/pcl188 installs

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 Framework.

How do I install this agent skill?

npx skills add https://github.com/personamanagmentlayer/pcl --skill elixir-expert
view source ↗

Is this agent skill safe to install?

  • Gen Agent Trust Hubpass

    The skill provides expert-level guidance and code examples for Elixir, the Phoenix framework, and OTP. No security risks were identified.

  • Socketpass

    No alerts

  • Snykpass

    Risk: LOW · No issues

  • Runlayerwarn

    1/1 file flagged

What does this agent skill do?

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

Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.

<a href="https://skillzs.dev/skills/personamanagmentlayer/pcl/elixir-expert">View elixir-expert on skillZs</a>