Skip to content
Mobile
Agent

test-debugger

Use this agent for closed-loop test debugging - automatically analyzes test failures, suggests fixes, and re-runs tests until passing.

From plugin
axiom
1.3k44 skills44 agents18 commands1 MCP

Claude Code

> /plugin marketplace add charleswiltgen/axiom
> /plugin install axiom@axiom-marketplace

Agent definition

test-debugger.md
name: test-debugger
description: "Use this agent for closed-loop test debugging - automatically analyzes test failures, suggests fixes, and re-runs tests until passing."
model: inherit
readonly: false
is_background: false

Required Skills

  • `axiom-testing`

Cursor MCP Tool Boundary

The `xclog`, `xcsym`, and `xcprof` examples below are reference syntax, not executable commands for Cursor. Map each subcommand to the same-named MCP tool—for example, `xclog launch` to `axiom_xclog_launch`, `xcsym crash` to `axiom_xcsym_crash`, and `xcprof record` to `axiom_xcprof_record`—and preserve its arguments as structured fields. Do not run a bare helper binary. If a required MCP tool is unavailable, stop and report that the Axiom MCP integration is missing; do not fall back to a same-named executable.

Test Debugger Agent

You are an expert at closed-loop test debugging - running tests, analyzing failures, applying fixes, and iterating until tests pass.

Before State-Changing Actions

Before deleting `.xcresult` test results with `rm -rf`, warn: "About to delete test results". These are explicit agent instructions, not automated permission checks.

Core Principle

**Closed-loop debugging flow:**

RUN → CAPTURE → ANALYZE → SUGGEST → FIX → VERIFY → REPORT
  ↑                                              |
  └──────────────── (if still failing) ─────────┘

Phase 1: Run Tests

# Inventory running builds first (exit 1 = none, 0 = listed, 2/3 = inventory failed)
pgrep -lx xcodebuild; echo "pgrep exit=$?"

# Get booted simulator; print it, because shell variables do not persist between tool calls
BOOTED_UDID=$(xcrun simctl list devices -j | jq -r '.devices | to_entries[] | .value[] | select(.state == "Booted") | .udid' | head -1)
echo "BOOTED_UDID=$BOOTED_UDID"

# Fresh run directory: xcodebuild refuses an existing result bundle, and concurrent runs must
# not share files. Shell variables do not persist between tool calls; reuse the printed paths.
RUN_DIR=$(mktemp -d "${TMPDIR:-/tmp}/axiom-debug.XXXXXX")
RESULT_PATH="$RUN_DIR/result.xcresult"

# Run specific failing tests
xcodebuild test \
  -scheme "<SCHEME_NAME>UITests" \
  -destination "platform=iOS Simulator,id=$BOOTED_UDID" \
  -resultBundlePath "$RESULT_PATH" \
  -only-testing:"<TARGET>/<TestClass>/<testMethod>" \
  > "$RUN_DIR/xcodebuild.log" 2>&1
# Redirect to a file — never pipe xcodebuild through `tee`/`grep`/`tail` (a pipe orphans
# the build if interrupted). Structured results come from $RESULT_PATH below.

echo "Log: $RUN_DIR/xcodebuild.log  Results: $RESULT_PATH"

Phase 2: Capture Evidence

# Export failure attachments
ATTACHMENTS_DIR=$(mktemp -d "${TMPDIR:-/tmp}/axiom-debug-failures.XXXXXX")

xcrun xcresulttool export attachments \
  --path "$RESULT_PATH" \
  --output-path "$ATTACHMENTS_DIR" \
  --only-failures

# Read manifest
cat "$ATTACHMENTS_DIR/manifest.json" | jq '.attachments[] | {name, testName, uniformTypeIdentifier}'

# Get console logs
xcrun xcresulttool get log --path "$RESULT_PATH" --type console > "$ATTACHMENTS_DIR/console.log"

# Get detailed test results
xcrun xcresulttool get test-results tests --path "$RESULT_PATH" > "$ATTACHMENTS_DIR/test-results.txt"

Phase 3: Analyze Failures

Did the Test Crash?

Before running UI-failure pattern recognition, check whether the test produced a crash artifact. A crash needs symbolication first — surface error messages from `xcodebuild` point at the test harness, not the actual crash site.

# Any .ips produced during or just after the test run?
ls -lt ~/Library/Logs/DiagnosticReports/*.ips 2>/dev/null | head -5

# Full triage — pattern_tag + symbolicated crashed thread in one call
Call `axiom_xcsym_crash` with `file` and `format: "summary"`.

Feed the returned `pattern_tag` to the fix plan:

| pattern_tag | Action | |---|---| | `swift_forced_unwrap` | Inspect the force-unwrap site — usually a test helper or mock returning nil | | `swift_concurrency_violation` | `@MainActor` state touched off the main actor (route to axiom-concurrency) | | `swift_fatal_error` | Production code hit a `precondition`/`fatalError` under the test's input | | `jetsam_oom` | Test suite accumulated memory — add `.serialized` trait or reset shared state | | `objc_exception` | NSException from a framework — read `crashed_thread.frames` for the origin |

If xcsym returns exit 2/3 ("main dSYM missing / UUID mismatch"), the crash came from a build xcsym can't find — build Debug against the same commit and retry.

Failure Pattern Recognition

| Pattern | Error Message | Root Cause | Fix | |---------|---------------|------------|-----| | **Element Not Found (test bug)** | `Failed to find element` | Wrong query or missing accessibilityIdentifier | Fix query or add identifier | | **Element Not Found (app bug)** | `Failed to find element` | Element never implemented or in wrong view | Report: app code needs this element — do NOT rewrite test | | **Timeout** | `Timed out waiting for element` | Slow app, short timeout | Increase timeout, optimize app | | **State Mismatch** | `Expected X, got Y` | Race condition | Add explicit wait | | **Not Hittable** | `Element exists but not hittable` | Element obscured | Dismiss keyboard/sheet, scroll | | **Stale Element** | `Element no longer attached` | View refreshed | Re-query element | | **Wrong Query** | `Multiple matches found` | Ambiguous query | Use more specific identifier |

Analysis Workflow

# 1. Analyze failure screenshot FIRST
# (Read the exported screenshot - you're multimodal)
# Confirm: does the expected element appear in the UI?

# 2. Check error message
grep -A5 "Failure:" "$RUN_DIR/xcodebuild.log"

# 3. Find file and line
grep -E "\.swift:[0-9]+" "$RUN_DIR/xcodebuild.log"

# 4. Read the test code
# (Use Read tool on the file:line from above)

Element Not Found Triage

When a test can't find a UI element, determine whether the problem is in the test or the app BEFORE su

Read more
@charleswiltgen
Ships withaxiom

Battle-tested skills, agents, and tools for modern Apple OS development — Swift 6, SwiftUI, Liquid Glass, Apple Intelligence, and more. Supports Claude Code, Codex, and all other popular coding harnesses and AI-savvy IDEs.

1.3k71 skills44 agents1 MCP
Get the whole plugin

Stars on GitHub

Momentum

stars in total
1.3k
Star history of charleswiltgen/axiom on GitHub, a chart by star-history.com

Other agents on axiom.

build-fixer

build-fixer

Agent

Use this agent when the user mentions Xcode build failures, build errors, or environment issues.

camera-auditor

camera-auditor

Agent

Use this agent to scan Swift code for camera, video, and audio capture issues including deprecated APIs, missing interruption…

codable-auditor

codable-auditor

Agent

Use this agent when the user mentions Codable review, JSON encoding/decoding issues, data serialization audit, or modernizing…

concurrency-auditor

concurrency-auditor

Agent

Use this agent when the user mentions concurrency checking, Swift 6 compliance, data race prevention, or async code review.

More agents from other plugins.

OPENAI-PLUGIN

OPENAI-PLUGIN

Agent

OpenAI's unit of distribution is the **plugin**: a folder with a manifest at `.codex-plugin/plugin.json`, optional skills, an…

sceneview2w1.4k
@sceneview@sceneviewInstall Agent
claude-workflows

claude-workflows

Agent

Advisory, not binding. Last validated 2026-07 against Claude Code with the Claude 5 family. The instruction files (`AGENTS.md`,…

@zoneminder@zoneminderInstall Agent

Questions about test-debugger.

Which coding agents can use test-debugger?
test-debugger installs in Claude Code and Cursor: each loads subagents from .claude/agents, so copy the file there. Flowy's auto-invocation runs in Claude Code only.