npx claudepluginhub ivanlutsenko/awac-claude-code-plugins --plugin crashlyticsWant just this command?
Then install: npx claudepluginhub u/[userId]/[slug]
Analyze iOS Crashlytics logs with mandatory git blame analysis and code-level fixes. Multi-agent architecture: classifier-ios → firebase-fetcher → forensics-ios → reviewer.
iOS Crash Analysis - Multi-Agent Edition
Analyze crash errors from Firebase Crashlytics using specialized agents.
Configuration
Before starting, check if a config file exists at .claude/crashlytics.local.md.
If it exists, read and use these settings:
language— output language (default: English)default_branch— branch for git blame (default: master)default_platform— should be ios for this commandforensics_model— model for forensics agent (default: opus)output_format— both / detailed_only / jira_only (default: both)firebase_project_id— pre-configured project ID (skip auto-detection if set)firebase_app_id_ios— pre-configured app ID (skip auto-detection if set)
If config doesn't exist, auto-create it with defaults and continue:
Bash: mkdir -p .claude && cat <<'EOF' > .claude/crashlytics.local.md
---
language: en
default_branch: master
default_platform: ios
forensics_model: opus
output_format: both
firebase_project_id: ""
firebase_app_id_android: ""
firebase_app_id_ios: ""
---
# Crashlytics Plugin Config
Auto-created with defaults. Run `/crash-config` to customize.
EOF
Inform user: "Config created at .claude/crashlytics.local.md (defaults: ios, master, opus). Run /crash-config to customize."
Multi-Agent Architecture
┌─────────────────────────────────────────────────────────────────┐
│ /crash-report-ios │
└─────────────────────────────────────────────────────────────────┘
│
┌──────────────┬───────────┼───────────┬──────────────┐
▼ ▼ ▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│classifier│→│ fetcher │→│forensics │→│ reviewer │→│ output │
│ iOS │ │ (Haiku) │ │ (Opus) │ │ (Haiku) │ │ │
│ (Haiku) │ │ │ │ │ │ │ │ Detailed │
│Component │ │REST API │ │Git blame │ │Quality │ │+ JIRA │
│Trigger │ │+ MCP disc│ │Code fix │ │Gate │ │ Brief │
│ │ │ │ │Assignee │ │Checklist │ │ │
└──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘
Workflow
Prerequisites Check (runs first!)
Run ALL checks in a single Bash call. Display results as a checklist to the user.
Bash: ${CLAUDE_PLUGIN_ROOT}/scripts/check-prerequisites.sh
Parse output and show checklist to user:
For each line:
OK ...→ show as passing checkMISSING ...→ show as failing check with fix instruction
Fix instructions by item:
| Missing | Instruction |
|---|---|
node | brew install node (macOS) / sudo apt install nodejs (Linux) / download from nodejs.org (Windows) |
firebase | npm install -g firebase-tools — offer to run automatically if npm is available |
firebase-auth | Run firebase login in terminal (opens browser, requires manual action) |
python3 | brew install python3 (macOS) / sudo apt install python3 (Linux) / download from python.org (Windows) |
Behavior:
- If
firebaseis MISSING andnpmis available → ask: "Install firebase-tools? (npm install -g firebase-tools)" and run if confirmed - If
firebase-authis MISSING → tell user to runfirebase loginin terminal, then re-run the command - If only
nodeorpython3missing → show instructions, continue in Manual mode - If ALL OK → proceed silently
- If any MISSING → show the checklist, then continue with whatever is available (degrade gracefully)
STEP 0: Firebase Auto-Init (runs automatically!)
Before starting check and configure Firebase. Two access levels: CLI REST API → Manual.
NEVER use mcp__plugin_crashlytics_firebase__firebase_login — MCP auth is broken ("Unable to verify client"). If CLI is not authorized, ask the user to run firebase login in terminal.
NOTE: Crashlytics data tools (crashlytics_get_issue, crashlytics_list_events, etc.) do NOT exist in Firebase MCP server. Do not attempt to call them. MCP is used only for project/app discovery.
If firebase_project_id and firebase_app_id_ios are set in config — skip auto-detection and use those values directly.
Discovery: MCP or CLI
1. Try MCP discovery first:
ToolSearch: "+firebase get_environment"
mcp__plugin_crashlytics_firebase__firebase_get_environment
If works → extract project_id, then:
mcp__plugin_crashlytics_firebase__firebase_list_apps (platform: "ios")
Extract app_id.
If MCP fails → retry once, then use CLI discovery:
2. CLI discovery fallback:
Bash: which firebase 2>/dev/null && firebase login:list 2>/dev/null
If CLI not authorized → go to Level 2 (Manual)
Bash: firebase projects:list --json 2>/dev/null | python3 -c "
import sys,json
data = json.load(sys.stdin)
for p in (data.get('results') or data.get('result', [])):
print(f\"{p['projectId']} — {p.get('displayName','')}\")"
Bash: firebase apps:list --project {PROJECT_ID} --json 2>/dev/null | python3 -c "
import sys,json
for a in json.load(sys.stdin)['result']:
if a.get('platform')=='IOS':
print(f\"{a['appId']} | {a.get('displayName','')}\")"
3. Build console_url immediately after getting project_id and app_id:
console_url = "https://console.firebase.google.com/project/{PROJECT_ID}/crashlytics/app/ios:{APP_ID}/issues/{ISSUE_ID}"
Level 1: CLI REST API (primary data fetch)
1. Get crash data via REST API (single script — token never printed to stdout):
NOTE: client_id and client_secret are public OAuth credentials from Firebase CLI
(embedded in firebase-tools source code, this is an installed app OAuth flow).
The access token MUST stay inside the script — never print or log it.
Bash: python3 ${CLAUDE_PLUGIN_ROOT}/scripts/fetch-crash-data.py "{APP_ID}" "{ISSUE_ID}" "{PROJECT_ID}"
2. Parse output:
- Lines starting with `ISSUE_DATA:` contain issue JSON
- Lines starting with `EVENTS_DATA:` contain events JSON
- `API_NOT_ENABLED` → show enable instructions, then go to Level 2
- `REST_FALLBACK_FAILED` → go to Level 2
- Extract: title, type (FATAL/NON_FATAL), status, stack traces, device info, event count
Level 2: Enhanced Manual Fallback
If REST API failed or Firebase not configured:
1. If API_NOT_ENABLED was detected:
Show: "Firebase Crashlytics API is not enabled for project {PROJECT_ID}.
Enable it:
- GCP Console: https://console.cloud.google.com/apis/library/firebasecrashlytics.googleapis.com?project={PROJECT_ID}
- gcloud: gcloud services enable firebasecrashlytics.googleapis.com --project={PROJECT_ID}
After enabling, re-run the command."
2. MUST generate a Firebase Console link (if project_id and app_id known):
https://console.firebase.google.com/project/{PROJECT_ID}/crashlytics/app/ios:{APP_ID}/issues/{ISSUE_ID}
3. Step-by-step instructions for the user:
a. Open the Console URL above (or go to https://console.firebase.google.com/ → Crashlytics)
b. Find the issue (by ID or search)
c. Go to the "Events" tab
d. Copy the full stack trace from the latest event
e. Also note: crash title, event count, % affected users, app version, device
4. Ask user to paste:
- Stack trace (required)
- Crash title
- Event count, % users, version
General rules:
- MCP is for project/app discovery only — crash data tools don't exist
- CLI REST API is the primary method for fetching crash data
- Always generate Console URL if project_id and app_id are available
- If Issue ID exists — always try to get data automatically via REST API
STEP 1: Get data
If user provided a Firebase Issue ID — first try loading data automatically (Level 1). Only ask for stack trace and context if auto-loading failed.
If no Issue ID — ask to provide:
- Stack trace (required)
- Context: crash count, % users, device, iOS version
STEP 2: Call crash-classifier-ios
Task(
subagent_type="crash-classifier-ios",
model="haiku",
prompt="Classify this iOS crash:
Stack trace:
{stack_trace}
Context:
- Events: {event_count}
- Users: {user_count}%
- Version: {app_version}
- Device: {device}
- iOS: {ios_version}
"
)
Expected output:
crash_type: Fatal error / SIGABRT / NSException
component: UI/Network/Database/Services/Background
trigger: user_action/background_task/lifecycle_event/async_operation
STEP 3: Get data from Firebase (optional)
If a Firebase Issue ID was provided, load crash data using this priority:
Option A: CLI REST API (primary)
Use the Python script from Step 0, Level 1 (token stays internal, never printed).
Substitute {APP_ID}, {PROJECT_ID}, {ISSUE_ID} with actual values.
Option B: Via firebase-fetcher agent (alternative)
Task(
subagent_type="firebase-fetcher",
model="haiku",
prompt="Get crash details from Firebase:
Issue ID: {issue_id}
App ID: {app_id} (iOS)
Project ID: {project_id}
Platform: ios
"
)
Option C: Enhanced Manual fallback
If REST API failed — generate Console URL and ask for manual input with step-by-step instructions (see Step 0, Level 2).
STEP 4: Call crash-forensics-ios
Use forensics_model from config (default: opus). If opus is unavailable, fall back to sonnet.
Task(
subagent_type="crash-forensics-ios",
model="{forensics_model from config, default opus}",
prompt="Analyze this iOS crash with git blame:
Classification: {classifier_output}
Firebase data: {firebase_output}
Stack trace: {stack_trace}
console_url: {console_url}
branch: {default_branch from config, default master}
"
)
The agent will:
- Search Swift/Objective-C files in the codebase
- Git blame analysis (on the configured branch)
- Determine assignee
- Propose a fix (Swift/Objective-C)
STEP 4.5: Call crash-report-reviewer (Quality Gate)
After receiving the result from forensics, before outputting to user:
Task(
subagent_type="crash-report-reviewer",
model="haiku",
prompt="Validate this crash report against mandatory fields:
{forensics_output}
console_url: {console_url}
"
)
Handling the reviewer result:
- If
pass: true— output the report as-is - If
pass: false— fill in missing fields yourself:- Use data from previous steps (classifier, firebase, forensics)
- If data for a field is unavailable — mark as
[DATA UNAVAILABLE] - DO NOT re-call forensics — fill in at the command level
STEP 5: Output results
The crash-forensics-ios agent returns two formats:
Format 1: Detailed Analysis
- Basic info
- Stack trace analysis
- Checked files with git blame
- Root cause
- Fix (before/after in Swift/Objective-C)
- Assignee with justification
- Context and prevention
Format 2: JIRA Brief
- Name and problem
- Key stack trace lines
- Root cause (1-2 sentences)
- Code fix (ready to copy-paste)
- Component, assignee
- Reproduction steps
Fallback mode (if agents unavailable)
If Task tool cannot call agents, perform analysis directly:
- Classification: Determine type, component, trigger
- File search: Glob/Grep by classes from stack trace
- Git blame:
git blame master -- file.swift -L X,Y - Assignee: Select 2-3 candidates with justification
- Fix: Propose code-level solution (Swift/Objective-C)
- Output: Detailed analysis + JIRA Brief
Pre-submit checklist
MUST verify:
- Classification completed (component, trigger)
- .swift/.m files found via Glob/Grep or reason explained
- git blame executed on configured branch with real commands
- Assignee determined with source (git blame line X)
- Report formats match config (both by default)
- Reviewer passed (
pass: true) or missing fields filled in - console_url included in JIRA Brief
DO NOT SUBMIT IF:
- Code search was not performed
- No git blame for found files
- Assignee = "TBD" without analysis
- Only one report format (when both required)
- Reviewer returned
pass: falseand fields were NOT filled in
Usage example
User: /crash-report-ios
Claude: iOS Crash Analysis - Multi-Agent
Please provide:
1. Stack trace (required)
2. Firebase Issue ID (if available)
3. Crash count and % users
4. Device and iOS version
---
[User provides data]
Claude:
Step 1: Classification...
[Calls crash-classifier-ios]
Step 2: Loading from Firebase...
[REST API fetch]
Step 3: Git blame analysis...
[Calls crash-forensics-ios]
Step 4: Quality check...
[Calls report-reviewer]
Analysis complete.
### Detailed Analysis
[...(detailed analysis)]
### JIRA Brief
[...(JIRA format)]
Important
Git blame + code search = MANDATORY
"TBD" = "I analyzed and ownership is unclear", NOT "I didn't check"
Document exact executed commands
Every report must have git blame with output