This skill should be used when the user asks to "add a LiveView page", "create a form", "handle real-time updates", "broadcast changes to users", "add a new route", "create an API endpoint", "fix this LiveView bug", "why is mount called twice?", or mentions handle_event, handle_info, handle_params, mount, channels, controllers, components, assigns, sockets, or PubSub. Essential for avoiding duplicate queries in mount.
Enforces Phoenix LiveView best practices to prevent duplicate queries and common pitfalls.
npx claudepluginhub georgeguimaraes/claude-code-elixirThis skill inherits all available tools. When active, it can use any tool Claude has access to.
Mental shifts for Phoenix applications. These insights challenge typical web framework patterns.
NO DATABASE QUERIES IN MOUNT
mount/3 is called TWICE (HTTP request + WebSocket connection). Queries in mount = duplicate queries.
def mount(_params, _session, socket) do
# NO database queries here! Called twice.
{:ok, assign(socket, posts: [], loading: true)}
end
def handle_params(params, _uri, socket) do
# Database queries here - once per navigation
posts = Blog.list_posts(socket.assigns.scope)
{:noreply, assign(socket, posts: posts, loading: false)}
end
mount/3 = setup only (empty assigns, subscriptions, defaults) handle_params/3 = data loading (all database queries, URL-driven state)
No exceptions: Don't query "just this one small thing" in mount. Don't "optimize later". LiveView lifecycle is non-negotiable.
Scopes address OWASP #1 vulnerability: Broken Access Control. Authorization context is threaded automatically—no more forgetting to scope queries.
def list_posts(%Scope{user: user}) do
Post |> where(user_id: ^user.id) |> Repo.all()
end
def subscribe(%Scope{organization: org}) do
Phoenix.PubSub.subscribe(@pubsub, "posts:org:#{org.id}")
end
Unscoped topics = data leaks between tenants.
Bad: Every connected user makes API calls (multiplied by users). Good: Single GenServer polls, broadcasts to all via PubSub.
Use assign_async/3 for data that can load after mount:
def mount(_params, _session, socket) do
{:ok, assign_async(socket, :user, fn -> {:ok, %{user: fetch_user()}} end)}
end
terminate/2 only fires if you're trapping exits—which you shouldn't do in LiveView.
Fix: Use a separate GenServer that monitors the LiveView process via Process.monitor/1, then handle :DOWN messages to run cleanup.
Calling start_async with the same name while a task is in-flight: the later one wins, the previous task's result is ignored.
Fix: Call cancel_async/3 first if you want to abort the previous task.
The socket in handle_out intercept is a snapshot from subscription time, not current state.
Why: Socket is copied into fastlane lookup at subscription time for performance.
Fix: Use separate topics per role, or fetch current state explicitly.
When merging classes on components, precedence is determined by stylesheet order, not HTML order. If btn-primary appears later in the compiled CSS than bg-red-500, it wins regardless of HTML order.
Fix: Use variant props instead of class merging.
The :content_type in %Plug.Upload{} is user-provided. Always validate actual file contents (magic bytes) and rewrite filename/extension.
To verify webhook signatures, you need the raw body. But Plug.Parsers consumes it.
{:ok, body, conn} = Plug.Conn.read_body(conn)
verify_signature!(conn, body)
%{conn | body_params: JSON.decode!(body)}
Don't use preserve_req_body: true—it keeps the entire body in memory for ALL requests.
%Plug.Upload{}.content_type for securityAny of these? Re-read The Iron Law and the Gotchas section.
Activates when the user asks about AI prompts, needs prompt templates, wants to search for prompts, or mentions prompts.chat. Use for discovering, retrieving, and improving prompts.
Search, retrieve, and install Agent Skills from the prompts.chat registry using MCP tools. Use when the user asks to find skills, browse skill catalogs, install a skill for Claude, or extend Claude's capabilities with reusable AI agent components.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.