Claude Skill

investigate

Find the root cause of Elixir/Phoenix bugs — crashes, exceptions, stack traces, compile errors, LiveView that won't update, silent failures. Use when something is broken or misbehaves. --parallel for 4 tracks.

LLM Mart · 0 points · 0 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download oliver-kriska-claude-elixir-phoenix-plugins_elixir-phoenix_skills_investigate-9767a82.zip · 5 KB
Part of oliver-kriska/claude-elixir-phoenix — 93 skills

Install

skills CLI npx skills add https://github.com/oliver-kriska/claude-elixir-phoenix/tree/main/plugins/elixir-phoenix/skills/investigate
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install oliver-kriska-claude-elixir-phoenix@llmmart
Git git clone https://github.com/oliver-kriska/claude-elixir-phoenix.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole oliver-kriska/claude-elixir-phoenix collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

Investigate Bug

Investigate bugs using the Ralph Wiggum approach: check the obvious, read errors literally.

Usage

/phx:investigate Users can't log in after password reset
/phx:investigate FunctionClauseError in UserController.show
/phx:investigate Complex auth bug --parallel

Arguments

$ARGUMENTS = Bug description or error message. Add --parallel for deep 4-track investigation.

Mode Selection

Use parallel mode (spawn deep-bug-investigator) when: bug mentions 3+ modules, spans multiple contexts, is intermittent or involves concurrency, or user says --parallel/deep.

Before spawning it, determine the effective maximum nesting depth. Use an explicit positive-integer CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH value first; when it is unset, inspect claude --version (the default is 1 in 2.1.217–2.1.218 and 3 in 2.1.219+). If the version is unavailable, conservatively use 1. At depth 3+, use the deep-bug-investigator orchestrator. At depth 1 or 2, keep orchestration in this main session: spawn the four focused tracks (reproduction, root cause, impact, fix strategy) directly in one parallel batch, wait for all four, then synthesize their evidence. Never spawn an orchestrator that cannot delegate.

Otherwise: Run the sequential workflow below.

Avoid confirmatory subagents: once Steps 3-4 identify the root cause with high confidence, present it directly — four subagents (~80K tokens) re-verifying a finding already made in this context add cost, not evidence.

Iron Laws

  1. Read the error message literally first — Most bugs tell you exactly what's wrong; resist the urge to theorize before reading what the system is saying
  2. Check the obvious before going deep — Compile errors, missing migrations, atom/string mismatches explain 80% of bugs; exhausting the Ralph Wiggum checklist saves hours
  3. Check changeset errors before UI debugging — Silent form saves are almost always {:error, changeset} with validation failures, not viewport or JS issues
  4. Consult compound docs before investigating fresh — A previously solved problem saves the entire investigation cycle; always search .claude/solutions/ first
  5. NEVER guess at a fix before reproducing — Reproduce first, then identify root cause, then fix. Skipping steps causes wrong fixes
  6. DO NOT apply a fix without confirming root cause — Verify your hypothesis with evidence (logs, tests, IO.inspect) before changing code

Investigation Workflow

Step 0: Consult Compound Docs

Search .claude/solutions/ for relevant keywords using Grep.

If matching solution exists, present it and ask: "Apply this fix, or investigate fresh?"

Step 0a: Runtime Auto-Capture (Tidewave -- PRIMARY when available)

If Tidewave MCP is detected, start here instead of asking the user to paste errors. Auto-capture runtime context:

  1. mcp__tidewave__get_logs level: :error -- capture recent errors
  2. Parse stacktraces, correlate with source via mcp__tidewave__get_source_location
  3. For data bugs: mcp__tidewave__execute_sql_query to inspect state
  4. For logic bugs: mcp__tidewave__project_eval to test hypotheses
  5. For UI bugs: mcp__tidewave__get_source_location with component name

Present pre-populated context to the user:

Auto-captured from runtime:

  • Error:
  • Location:

Investigating this. Correct if wrong.

This eliminates copy-pasting errors between app and agent. If Tidewave NOT available: Fall through to Step 1.

Step 1: Sanity Checks

Run mix compile --warnings-as-errors 2>&1 | head -50, then mix ecto.migrations (lists pending migrations without running them — ask before migrating).

Step 2: Reproduce

Run mix test test/path_test.exs --trace. Then read the last 200 lines of log/dev.log and search for "error" or "exception" patterns.

Step 3: Read Error LITERALLY

Parse the error message — check ${CLAUDE_SKILL_DIR}/references/error-patterns.md.

Step 4: Check the Obvious (Ralph Wiggum Checklist)

File saved? Atom vs string? Data preloaded? Pattern match correct? Nil? Return value? Server restarted?

LiveView form saves silently failing? Check changeset errors FIRST — not viewport, click mechanics, or JS. A missing hidden_input for a required embedded field causes {:error, changeset} with no visible UI feedback.

Step 5: IO.inspect / Tidewave project_eval

Step 6: Identify Root Cause

Find what's actually happening vs what should happen.

Step 7: Hand Off

Present root cause + evidence. Then route by fix size:

  • Small, contained fix → offer to apply directly or via /phx:quick
  • Multi-file or risky fix → suggest /phx:plan {root cause summary} so the fix gets task structure and review
  • Non-obvious root cause → after the fix lands, suggest /phx:compound

Autonomous Iteration

Use /ralph-loop:ralph-loop for autonomous debugging with clear completion criteria and --max-iterations.

References

  • ${CLAUDE_SKILL_DIR}/references/error-patterns.md — Common errors and checklist
  • ${CLAUDE_SKILL_DIR}/references/investigation-template.md — Output format
  • ${CLAUDE_SKILL_DIR}/references/debug-commands.md — Debug commands and common fixes
Files (claude-elixir-phoenix)
  • references
    • debug-commands.md 2 KB
      # Quick Debug Commands & Common Fixes
      
      ## Quick Debug Commands
      
      Common debug commands:
      
      - Clean rebuild: `rm -rf _build deps && mix deps.get && mix compile`
      - Check module exports: `mix run -e "IO.inspect MyModule.__info__(:functions)"`
      - Interactive debugging: `iex -S mix phx.server` (then `recompile()`)
      - Run single test with output: `mix test test/file_test.exs:42 --trace`
      
      ## Common Fixes
      
      ### String vs Atom Keys
      
      ```elixir
      # External data (JSON, params) = strings
      params["key"]
      
      # Internal data = atoms
      struct.field
      map.key
      ```
      
      ### Missing Preload
      
      ```elixir
      # Before
      user = Repo.get(User, id)
      user.posts  # BOOM
      
      # After
      user = Repo.get(User, id) |> Repo.preload(:posts)
      ```
      
      ### Nil Propagation
      
      ```elixir
      # Before
      user.profile.name  # Crashes if profile nil
      
      # After
      case user.profile do
        nil -> nil
        profile -> profile.name
      end
      # Or use get_in/2
      ```
      
      ## Telemetry-Based Debugging
      
      When Tidewave is unavailable, use telemetry to diagnose
      performance and behavior issues:
      
      ```elixir
      # Attach a temporary handler to see all Ecto queries
      :telemetry.attach(
        "debug-queries",
        [:my_app, :repo, :query],
        fn _event, measurements, metadata, _config ->
          IO.puts("Query: #{metadata.query}")
          IO.puts("  Time: #{measurements.total_time / 1_000_000}ms")
        end,
        nil
      )
      # Detach when done: :telemetry.detach("debug-queries")
      ```
      
      ### Common Telemetry Events to Attach
      
      | Event | What It Shows |
      |-------|---------------|
      | `[:my_app, :repo, :query]` | All Ecto queries with timing |
      | `[:phoenix, :endpoint, :stop]` | Request duration |
      | `[:phoenix, :router_dispatch, :stop]` | Per-route timing |
      | `[:oban, :job, :stop]` | Oban job execution time |
      | `[:oban, :job, :exception]` | Oban job failures |
      
      ### LiveDashboard in Dev
      
      Add to router for real-time metrics visualization:
      
      ```elixir
      if Mix.env() in [:dev, :test] do
        import Phoenix.LiveDashboard.Router
      
        scope "/" do
          pipe_through :browser
          live_dashboard "/dashboard",
            metrics: MyAppWeb.Telemetry
        end
      end
      ```
      
    • error-patterns.md 1.2 KB
      # Error Patterns - Read Error LITERALLY
      
      ## Common Elixir/Phoenix Errors
      
      | Error | Literal Meaning | Check |
      |-------|-----------------|-------|
      | `UndefinedFunctionError: MyMod.func/2` | Function doesn't exist with that arity | Is it `func/1` not `func/2`? |
      | `KeyError: key :name not found` | Map doesn't have `:name` key | String key `"name"` instead? |
      | `FunctionClauseError` | No pattern matched | `IO.inspect` the actual data |
      | `(Ecto.NoResultsError)` | Query returned nil | Data doesn't exist in DB |
      | `(Protocol.UndefinedError)` | Protocol not implemented | Wrong data type passed |
      
      ## Ralph Wiggum Checklist
      
      Check systematically in the main session (SKILL.md Step 4):
      
      1. Is the file saved?
      2. Atom vs string key mismatch?
      3. Is data preloaded?
      4. Is the pattern match correct?
      5. Is nil being passed somewhere?
      6. Is the return value correct (conn/socket)?
      7. Did you restart the server?
      
      ## IO.inspect Everything
      
      ```elixir
      # Add to suspected location
      |> IO.inspect(label: "DEBUG: data after transform")
      ```
      
      ## When Stuck
      
      1. `IO.inspect(binding(), label: "all variables")`
      2. Add `require IEx; IEx.pry` and step through
      3. Check if code is even being reached (add `IO.puts "HERE"`)
      4. Compare working vs broken path
      
    • investigation-template.md 934 B
      # Investigation Output Template
      
      Create `.claude/plans/{slug}/research/investigation.md`:
      
      ````markdown
      # Bug Investigation: $ARGUMENTS
      
      ## Error
      
      ```
      {exact error message}
      ```
      
      ## Reproduction
      
      ```bash
      {command to reproduce}
      ```
      
      ## Ralph Wiggum Checklist
      
      - [x] File saved? YES
      - [x] Compiled? YES
      - [ ] Correct key type? **NO - FOUND IT**
      - [ ] Data exists? Not checked
      
      ## Root Cause
      
      **What's wrong**: Using string key "user_id" but map has atom :user_id
      
      **Where**: lib/my_app_web/controllers/user_controller.ex:45
      
      **Why missed**: External API returns string keys, internal code uses atoms
      
      ## Fix
      
      ```elixir
      # Before
      def show(conn, %{"user_id" => id}) do
        user = Accounts.get_user(params["user_id"])  # params has string keys!
      
      # After
      def show(conn, %{"user_id" => id}) do
        user = Accounts.get_user(id)  # Already extracted
      ```
      
      ## Prevention
      
      - Add test with external API mock
      - Add typespec to catch at compile time
      ````
      
  • SKILL.md 5.5 KB
    ---
    name: investigate
    description: "Find the root cause of Elixir/Phoenix bugs — crashes, exceptions, stack traces, compile errors, LiveView that won't update, silent failures. Use when something is broken or misbehaves. --parallel for 4 tracks."
    effort: high
    argument-hint: <bug description> [--parallel]
    ---
    
    # Investigate Bug
    
    Investigate bugs using the Ralph Wiggum approach: check the
    obvious, read errors literally.
    
    ## Usage
    
    ```
    /phx:investigate Users can't log in after password reset
    /phx:investigate FunctionClauseError in UserController.show
    /phx:investigate Complex auth bug --parallel
    ```
    
    ## Arguments
    
    `$ARGUMENTS` = Bug description or error message. Add `--parallel`
    for deep 4-track investigation.
    
    ## Mode Selection
    
    Use **parallel mode** (spawn `deep-bug-investigator`) when:
    bug mentions 3+ modules, spans multiple contexts, is intermittent
    or involves concurrency, or user says `--parallel`/`deep`.
    
    Before spawning it, determine the effective maximum nesting depth. Use an
    explicit positive-integer `CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH` value first;
    when it is unset, inspect `claude --version` (the default is 1 in 2.1.217–2.1.218
    and 3 in 2.1.219+). If the version is unavailable, conservatively use 1. At
    depth 3+, use the `deep-bug-investigator` orchestrator. At depth 1 or 2, keep
    orchestration in this main session: spawn the four
    focused tracks (reproduction, root cause, impact, fix strategy) directly in
    one parallel batch, wait for all four, then synthesize their evidence. Never
    spawn an orchestrator that cannot delegate.
    
    **Otherwise**: Run the sequential workflow below.
    
    **Avoid confirmatory subagents**: once Steps 3-4 identify the root cause
    with high confidence, present it directly — four subagents (~80K tokens)
    re-verifying a finding already made in this context add cost, not evidence.
    
    ## Iron Laws
    
    1. **Read the error message literally first** — Most bugs tell you exactly what's wrong; resist the urge to theorize before reading what the system is saying
    2. **Check the obvious before going deep** — Compile errors, missing migrations, atom/string mismatches explain 80% of bugs; exhausting the Ralph Wiggum checklist saves hours
    3. **Check changeset errors before UI debugging** — Silent form saves are almost always `{:error, changeset}` with validation failures, not viewport or JS issues
    4. **Consult compound docs before investigating fresh** — A previously solved problem saves the entire investigation cycle; always search `.claude/solutions/` first
    5. **NEVER guess at a fix before reproducing** — Reproduce first, then identify root cause, then fix. Skipping steps causes wrong fixes
    6. **DO NOT apply a fix without confirming root cause** — Verify your hypothesis with evidence (logs, tests, IO.inspect) before changing code
    
    ## Investigation Workflow
    
    ### Step 0: Consult Compound Docs
    
    Search `.claude/solutions/` for relevant keywords using Grep.
    
    If matching solution exists, present it and ask: "Apply this
    fix, or investigate fresh?"
    
    ### Step 0a: Runtime Auto-Capture (Tidewave -- PRIMARY when available)
    
    If Tidewave MCP is detected, **start here instead of asking
    the user to paste errors**. Auto-capture runtime context:
    
    1. `mcp__tidewave__get_logs level: :error` -- capture recent errors
    2. Parse stacktraces, correlate with source via
       `mcp__tidewave__get_source_location`
    3. For data bugs: `mcp__tidewave__execute_sql_query` to inspect state
    4. For logic bugs: `mcp__tidewave__project_eval` to test hypotheses
    5. For UI bugs: `mcp__tidewave__get_source_location` with component name
    
    Present pre-populated context to the user:
    
    > **Auto-captured from runtime:**
    >
    > - Error: {parsed error from logs}
    > - Location: {file:line from get_source_location}
    >
    > Investigating this. Correct if wrong.
    
    This eliminates copy-pasting errors between app and agent.
    **If Tidewave NOT available**: Fall through to Step 1.
    
    ### Step 1: Sanity Checks
    
    Run `mix compile --warnings-as-errors 2>&1 | head -50`, then `mix ecto.migrations`
    (lists pending migrations without running them — ask before migrating).
    
    ### Step 2: Reproduce
    
    Run `mix test test/path_test.exs --trace`. Then read the last 200 lines of `log/dev.log` and search for "error" or "exception" patterns.
    
    ### Step 3: Read Error LITERALLY
    
    Parse the error message — check `${CLAUDE_SKILL_DIR}/references/error-patterns.md`.
    
    ### Step 4: Check the Obvious (Ralph Wiggum Checklist)
    
    File saved? Atom vs string? Data preloaded? Pattern match
    correct? Nil? Return value? Server restarted?
    
    **LiveView form saves silently failing?** Check changeset errors
    FIRST — not viewport, click mechanics, or JS. A missing
    `hidden_input` for a required embedded field causes `{:error,
    changeset}` with no visible UI feedback.
    
    ### Step 5: IO.inspect / Tidewave project_eval
    
    ### Step 6: Identify Root Cause
    
    Find what's actually happening vs what should happen.
    
    ### Step 7: Hand Off
    
    Present root cause + evidence. Then route by fix size:
    
    - Small, contained fix → offer to apply directly or via `/phx:quick`
    - Multi-file or risky fix → suggest `/phx:plan {root cause summary}` so
      the fix gets task structure and review
    - Non-obvious root cause → after the fix lands, suggest `/phx:compound`
    
    ## Autonomous Iteration
    
    Use `/ralph-loop:ralph-loop` for autonomous debugging with
    clear completion criteria and `--max-iterations`.
    
    ## References
    
    - `${CLAUDE_SKILL_DIR}/references/error-patterns.md` — Common errors and checklist
    - `${CLAUDE_SKILL_DIR}/references/investigation-template.md` — Output format
    - `${CLAUDE_SKILL_DIR}/references/debug-commands.md` — Debug commands and common fixes
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related