Elixir/Phoenix development companion. Run and interpret mix test, mix credo, mix dialyzer, mix format. Generate modules following OTP conventions: contexts, schemas, GenServers, supervisors, tasks. Debug compilation errors and warnings. Help with Ecto migrations, queries, changesets, and associations. Use for any Elixir or Phoenix development task including writing modules, fixing tests, refactoring code, or understanding OTP patterns.
数据来源:ClawHub。 在 ClawSkills 查看
选择你使用的 Agent
方法一:命令行安装(推荐)
推荐(无需提前安装 clawhub)
npx clawhub@latest --dir ~/.claude/skills install elixir-dev或使用 clawhub CLI(需提前安装)
clawhub --dir ~/.claude/skills install elixir-dev⚠️ 需要 Node.js 18+,没有 Node?请使用下方方法二直接下载 ZIP。 安装 Node.js →
方法二:手动下载安装(无需 Node)
下载 ZIP,解压后将文件夹放到以下路径,重启 Agent 即可:
安装路径
~/.claude/skills/elixir-dev/💡解压后将文件夹放到上方路径,重启 Agent 即可生效
--- name: elixir-dev description: "Elixir/Phoenix development companion. Run and interpret mix test, mix credo, mix dialyzer, mix format. Generate modules following OTP conventions: contexts, schemas, GenServers, supervisors, tasks. Debug compilation errors and warnings. Help with Ecto migrations, queries, changesets, and associations. Use for any Elixir or Phoenix development task including writing modules, fixing tests, refactoring code, or understanding OTP patterns." ---
See references/mix-commands.md for full command reference.
# Run all tests
mix test
# Specific file or line
mix test test/my_app/accounts_test.exs:42
# By tag
mix test --only integration
# Failed only (requires --failed flag from prior run)
mix test --failed
# With coverage
mix test --cover
Interpreting failures:
** (MatchError) — Pattern match failed; check return value shape.** (Ecto.NoResultsError) — Repo.get! with non-existent ID; use Repo.get or seed data.** (DBConnection.OwnershipError) — Missing async: true or sandbox setup.no function clause matching — Wrong arity or unexpected arg type.mix credo --strict
mix credo suggest --format json
mix credo explain MyApp.Module # Explain issues for specific module
Common Credo fixes:
Credo.Check.Readability.ModuleDoc — Add @moduledoc.Credo.Check.Refactor.CyclomaticComplexity — Extract helper functions.Credo.Check.Design.TagTODO — Address or remove TODO comments.mix dialyzer
mix dialyzer --format short
Common Dialyzer warnings:
The pattern can never match — Dead code or wrong type in pattern.Function has no local return — Crashes on all paths; check internal calls.The call will never return — Calling a function that always raises.@spec annotations; use @dialyzer {:nowarn_function, func: arity} as last resort.mix format
mix format --check-formatted # CI mode — exit 1 if unformatted
Always include @moduledoc, @doc, and @spec on public functions.
defmodule MyApp.Notifications do
@moduledoc """
Manages notification delivery and preferences.
"""
import Ecto.Query
alias MyApp.Repo
alias MyApp.Notifications.Notification
@doc "List notifications for a user, most recent first."
@spec list_notifications(String.t(), keyword()) :: [Notification.t()]
def list_notifications(user_id, opts \\ []) do
limit = Keyword.get(opts, :limit, 50)
Notification
|> where(user_id: ^user_id)
|> order_by(desc: :inserted_at)
|> limit(^limit)
|> Repo.all()
end
end
defmodule MyApp.Notifications.Notification do
@moduledoc """
Schema for push/email/sms notifications.
"""
use Ecto.Schema
import Ecto.Changeset
@type t :: %__MODULE__{}
@primary_key {:id, :binary_id, autogenerate: true}
@foreign_key_type :binary_id
@timestamps_opts [type: :utc_datetime_usec]
schema "notifications" do
field :channel, Ecto.Enum, values: [:push, :email, :sms]
field :title, :string
field :body, :string
field :delivered_at, :utc_datetime_usec
field :user_id, :binary_id
timestamps()
end
@required ~w(channel title body user_id)a
@doc false
def changeset(notification, attrs) do
notification
|> cast(attrs, @required ++ [:delivered_at])
|> validate_required(@required)
|> validate_length(:title, max: 255)
end
end
See references/otp-patterns.md for GenServer, Supervisor, Agent, Task patterns.
| Pattern | Use When | |---------|----------| | GenServer | Stateful process with sync/async calls (cache, rate limiter, connection pool) | | Agent | Simple state wrapper with no complex logic | | Task | One-off async work, fire-and-forget or awaited | | Task.Supervisor | Supervised fire-and-forget tasks | | Supervisor | Managing child process lifecycles | | Registry | Process lookup by name/key | | DynamicSupervisor | Starting children at runtime |
defmodule MyApp.RateLimiter do
@moduledoc "Token bucket rate limiter."
use GenServer
# Client API
def start_link(opts) do
name = Keyword.get(opts, :name, __MODULE__)
GenServer.start_link(__MODULE__, opts, name: name)
end
@spec check_rate(String.t()) :: :ok | {:error, :rate_limited}
def check_rate(key), do: GenServer.call(__MODULE__, {:check, key})
# Server callbacks
@impl true
def init(opts) do
{:ok, %{limit: Keyword.get(opts, :limit, 100), window_ms: 60_000, buckets: %{}}}
end
@impl true
def handle_call({:check, key}, _from, state) do
now = System.monotonic_time(:millisecond)
{count, state} = increment(state, key, now)
if count <= state.limit, do: {:reply, :ok, state}, else: {:reply, {:error, :rate_limited}, state}
end
defp increment(state, key, now) do
# Implementation
end
end
| Error | Cause | Fix | |-------|-------|-----| | module X is not available | Missing dep or typo | Check mix.exs deps, verify module name | | undefined function X/N | Not imported/aliased | Add import, alias, or full module path | | (CompileError) redefining module | Duplicate module name | Rename one of them | | protocol not implemented | Missing protocol impl | Add defimpl for your struct | | cannot use ^x outside of match | Pin in wrong position | Move to pattern match context |
def list(filters) do
Enum.reduce(filters, base_query(), fn
{:status, val}, q -> where(q, [r], r.status == ^val)
{:since, dt}, q -> where(q, [r], r.inserted_at >= ^dt)
{:search, term}, q -> where(q, [r], ilike(r.name, ^"%#{term}%"))
_, q -> q
end)
|> Repo.all()
end
# Query-time preload (single query with join)
from(p in Post, join: a in assoc(p, :author), preload: [author: a])
# Separate query preload
Post |> Repo.all() |> Repo.preload(:author)
# Nested
Repo.preload(posts, [comments: :author])
from(o in Order,
where: o.tenant_id == ^tenant_id,
group_by: o.status,
select: {o.status, count(o.id), sum(o.amount)}
)
|> Repo.all()
defmodule MyAppWeb.DashboardLive do
use MyAppWeb, :live_view
@impl true
def mount(_params, _session, socket) do
{:ok, assign(socket, items: [], loading: true)}
end
@impl true
def handle_event("delete", %{"id" => id}, socket) do
MyApp.Items.delete_item!(id)
{:noreply, assign(socket, items: MyApp.Items.list_items())}
end
@impl true
def render(assigns) do
~H"""
<div :for={item <- @items}>
<span><%= item.name %></span>
<button phx-click="delete" phx-value-id={item.id}>Delete</button>
</div>
"""
end
end
# Subscribe in mount
def mount(_, _, socket) do
if connected?(socket), do: Phoenix.PubSub.subscribe(MyApp.PubSub, "items")
{:ok, assign(socket, items: list_items())}
end
# Broadcast from context
def create_item(attrs) do
with {:ok, item} <- %Item{} |> Item.changeset(attrs) |> Repo.insert() do
Phoenix.PubSub.broadcast(MyApp.PubSub, "items", {:item_created, item})
{:ok, item}
end
end
# Handle in LiveView
def handle_info({:item_created, item}, socket) do
{:noreply, update(socket, :items, &[item | &1])}
end安装 Elixir Dev 后,可以对 AI 说这些话来触发它
Help me get started with Elixir Dev
Explains what Elixir Dev does, walks through the setup, and runs a quick demo based on your current project
Use Elixir Dev to elixir/Phoenix development companion
Invokes Elixir Dev with the right parameters and returns the result directly in the conversation
What can I do with Elixir Dev in my developer & devops workflow?
Lists the top use cases for Elixir Dev, with example commands for each scenario
将技能文件夹放到 ~/.claude/skills/elixir-dev/ 目录(个人级,所有项目可用),或 .claude/skills/elixir-dev/(项目级)。重启 AI 客户端后,用 /elixir-dev 主动调用,或让 AI 根据上下文自动发现并使用。
Elixir Dev 支持 Claude、Cursor、OpenClaw,可与这些 AI 平台无缝集成,扩展其能力。
Elixir Dev 可免费安装使用。请查阅仓库了解许可证信息。
Elixir/Phoenix development companion. Run and interpret mix test, mix credo, mix dialyzer, mix format. Generate modules following OTP conventions: contexts, schemas, GenServers, supervisors, tasks. Debug compilation errors and warnings. Help with Ecto migrations, queries, changesets, and associations. Use for any Elixir or Phoenix development task including writing modules, fixing tests, refactoring code, or understanding OTP patterns.
Automate my developer & devops tasks using Elixir Dev
Identifies repetitive steps in your workflow and sets up Elixir Dev to handle them automatically
Elixir Dev 属于「Developer & DevOps」分类,该分类的技能帮助 AI 智能体在此领域执行专业任务。