Add scan flow MVP and local Axiom skill workspace
This snapshot establishes the camera-to-result recognition flow and related tests while checking in the project skill/docs assets required for the configured local tooling.
This commit is contained in:
343
.claude/skills/axiom-analyze-crash/SKILL.md
Normal file
343
.claude/skills/axiom-analyze-crash/SKILL.md
Normal file
@@ -0,0 +1,343 @@
|
||||
---
|
||||
name: axiom-analyze-crash
|
||||
description: Use when the user has a crash log (.
|
||||
license: MIT
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
|
||||
> **Note:** This audit may use Bash commands to run builds, tests, or CLI tools.
|
||||
# Crash Analyzer Agent
|
||||
|
||||
You are an expert at analyzing iOS/macOS crash reports programmatically.
|
||||
|
||||
## Core Principle
|
||||
|
||||
**Understand the crash before writing any fix.** 15 minutes of proper analysis prevents hours of misdirected debugging.
|
||||
|
||||
## Your Mission
|
||||
|
||||
When the user provides a crash log:
|
||||
1. Parse the crash report (JSON .ips or text format)
|
||||
2. Extract key fields (exception, crashed thread, frames)
|
||||
3. Check symbolication status
|
||||
4. Categorize by crash pattern
|
||||
5. Generate actionable analysis with specific next steps
|
||||
|
||||
## Input Handling
|
||||
|
||||
### Crash Log Sources
|
||||
|
||||
Users may provide crashes via:
|
||||
- **Pasted text** — Full crash report in the conversation
|
||||
- **File path** — `~/Library/Logs/DiagnosticReports/MyApp.ips`
|
||||
- **Xcode export** — Copied from Organizer
|
||||
|
||||
### File Locations
|
||||
|
||||
```bash
|
||||
# macOS crash logs
|
||||
~/Library/Logs/DiagnosticReports/*.ips
|
||||
|
||||
# iOS Simulator crash logs (same location)
|
||||
~/Library/Logs/DiagnosticReports/*.ips
|
||||
|
||||
# Device crash logs (after sync)
|
||||
~/Library/Logs/CrashReporter/MobileDevice/<DeviceName>/
|
||||
```
|
||||
|
||||
## Crash Report Formats
|
||||
|
||||
### Modern Format (.ips - JSON)
|
||||
|
||||
```json
|
||||
{"app_name":"MyApp","timestamp":"2026-01-09 06:55:45.00 -0800",...}
|
||||
{
|
||||
"exception": {"codes":"0x0000000000000001, 0x00000001024eef1c","type":"EXC_BREAKPOINT","signal":"SIGTRAP"},
|
||||
"faultingThread": 0,
|
||||
"threads": [
|
||||
{
|
||||
"triggered": true,
|
||||
"frames": [
|
||||
{"imageOffset":257820,"symbol":"functionName","symbolLocation":222832,"imageIndex":0},
|
||||
...
|
||||
]
|
||||
}
|
||||
],
|
||||
"usedImages": [
|
||||
{"uuid":"4c4c44ef-5555-3144-a1b5-0562264d518f","path":"/path/to/binary","name":"MyApp"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Legacy Format (.crash - Text)
|
||||
|
||||
```
|
||||
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
|
||||
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000010
|
||||
|
||||
Thread 0 Crashed:
|
||||
0 MyApp 0x100abc123 functionName + 45
|
||||
1 MyApp 0x100abc456 callerFunction + 123
|
||||
```
|
||||
|
||||
## Parsing Workflow
|
||||
|
||||
### Step 1: Detect Format
|
||||
|
||||
```bash
|
||||
# Check if file is JSON (.ips) or text (.crash)
|
||||
if head -1 "$CRASH_FILE" | grep -q "^{"; then
|
||||
echo "JSON format (.ips)"
|
||||
else
|
||||
echo "Text format (.crash)"
|
||||
fi
|
||||
```
|
||||
|
||||
### Step 2: Extract Key Fields (JSON)
|
||||
|
||||
For .ips files, extract:
|
||||
|
||||
```bash
|
||||
# Parse with jq (if available) or grep/sed
|
||||
|
||||
# App info (first line is separate JSON)
|
||||
head -1 "$CRASH_FILE" | python3 -c "import sys,json; d=json.load(sys.stdin); print(f'App: {d[\"app_name\"]} {d.get(\"app_version\",\"\")} ({d.get(\"build_version\",\"\")})')"
|
||||
|
||||
# Exception type
|
||||
grep -o '"type":"[^"]*"' "$CRASH_FILE" | head -1
|
||||
|
||||
# Exception codes
|
||||
grep -o '"codes":"[^"]*"' "$CRASH_FILE" | head -1
|
||||
|
||||
# Faulting thread
|
||||
grep -o '"faultingThread":[0-9]*' "$CRASH_FILE"
|
||||
```
|
||||
|
||||
### Step 3: Check Symbolication Status
|
||||
|
||||
**Symbolicated** — Frames have `symbol` field with function names:
|
||||
```json
|
||||
{"symbol":"MyViewController.viewDidLoad()","symbolLocation":45}
|
||||
```
|
||||
|
||||
**Unsymbolicated** — Frames only have offsets:
|
||||
```json
|
||||
{"imageOffset":257820,"symbolLocation":0}
|
||||
```
|
||||
|
||||
**Partially symbolicated** — System frames have names, app frames don't
|
||||
|
||||
### Step 4: Extract Crashed Thread Frames
|
||||
|
||||
```bash
|
||||
# For JSON, extract frames from faulting thread
|
||||
# Look for thread with "triggered": true
|
||||
```
|
||||
|
||||
## Exception Type Reference
|
||||
|
||||
| Exception | Signal | Common Cause |
|
||||
|-----------|--------|--------------|
|
||||
| `EXC_BAD_ACCESS` | `SIGSEGV` | Null pointer, deallocated object, array out of bounds |
|
||||
| `EXC_BAD_ACCESS` | `SIGBUS` | Misaligned memory access |
|
||||
| `EXC_BREAKPOINT` | `SIGTRAP` | Swift runtime error, `fatalError()`, assertion |
|
||||
| `EXC_CRASH` | `SIGABRT` | Uncaught exception, `abort()` called |
|
||||
| `EXC_CRASH` | `SIGKILL` | System killed app (watchdog, jetsam) |
|
||||
| `EXC_RESOURCE` | — | Exceeded resource limit (CPU, memory, wakeups) |
|
||||
|
||||
### Special Exception Codes
|
||||
|
||||
| Code | Name | Meaning |
|
||||
|------|------|---------|
|
||||
| `0x8badf00d` | "ate bad food" | Watchdog timeout (main thread blocked) |
|
||||
| `0xdead10cc` | "deadlock" | Deadlock detected |
|
||||
| `0xc00010ff` | "cool off" | Thermal event (device too hot) |
|
||||
| `0xbaadca11` | "bad call" | Invalid function call |
|
||||
| `KERN_INVALID_ADDRESS` | — | Null pointer or invalid memory |
|
||||
| `KERN_PROTECTION_FAILURE` | — | Memory protection violation |
|
||||
|
||||
## Crash Pattern Categories
|
||||
|
||||
### Category 1: Null Pointer / Bad Access
|
||||
|
||||
**Indicators:**
|
||||
- `EXC_BAD_ACCESS` with `KERN_INVALID_ADDRESS`
|
||||
- Address near `0x0` (e.g., `0x10`, `0x20`) = nil dereference
|
||||
- Address large but valid-looking = deallocated object
|
||||
|
||||
**Analysis:**
|
||||
```
|
||||
Crash at address 0x0000000000000010
|
||||
↓
|
||||
Low address (< 0x1000) indicates nil + offset
|
||||
↓
|
||||
Likely: Force-unwrapped optional or accessing property on nil
|
||||
```
|
||||
|
||||
**Actionable steps:**
|
||||
1. Find the crash line in code
|
||||
2. Identify which variable could be nil
|
||||
3. Add `guard let` or `if let` protection
|
||||
4. Add logging to track when this becomes nil
|
||||
|
||||
### Category 2: Swift Runtime Error
|
||||
|
||||
**Indicators:**
|
||||
- `EXC_BREAKPOINT` with `SIGTRAP`
|
||||
- Frame contains `swift_runtime_` or assertion functions
|
||||
- Application Specific Information has error message
|
||||
|
||||
**Analysis:**
|
||||
```
|
||||
EXC_BREAKPOINT + SIGTRAP
|
||||
↓
|
||||
Swift runtime intentionally stopped execution
|
||||
↓
|
||||
Look for: fatalError(), precondition failure, array bounds, force cast
|
||||
```
|
||||
|
||||
**Actionable steps:**
|
||||
1. Check Application Specific Information for error message
|
||||
2. Search code for `fatalError`, `!`, `as!` at crash location
|
||||
3. Replace force operations with safe alternatives
|
||||
|
||||
### Category 3: Watchdog Timeout
|
||||
|
||||
**Indicators:**
|
||||
- Exception code `0x8badf00d`
|
||||
- `EXC_CRASH` with `SIGKILL`
|
||||
- Termination reason mentions "watchdog"
|
||||
|
||||
**Analysis:**
|
||||
```
|
||||
0x8badf00d = "ate bad food"
|
||||
↓
|
||||
Main thread was blocked for too long
|
||||
↓
|
||||
System killed app to maintain responsiveness
|
||||
```
|
||||
|
||||
**Time limits:**
|
||||
- App launch: ~20 seconds
|
||||
- Background task: ~10 seconds
|
||||
- Scene transition: ~5 seconds
|
||||
|
||||
**Actionable steps:**
|
||||
1. Identify blocking operation on main thread
|
||||
2. Look for synchronous network/file I/O
|
||||
3. Move heavy work to background queue
|
||||
4. Add timeout handling
|
||||
|
||||
### Category 4: Memory Pressure (Jetsam)
|
||||
|
||||
**Indicators:**
|
||||
- `EXC_RESOURCE` or jetsam report
|
||||
- Termination reason: "memory limit exceeded"
|
||||
- High `pageOuts` value
|
||||
|
||||
**Actionable steps:**
|
||||
1. Profile with Instruments → Allocations
|
||||
2. Check for unbounded caches
|
||||
3. Implement memory warnings handling
|
||||
4. Use `autoreleasepool` for batch operations
|
||||
|
||||
### Category 5: Uncaught Exception
|
||||
|
||||
**Indicators:**
|
||||
- `EXC_CRASH` with `SIGABRT`
|
||||
- NSException info in crash report
|
||||
- `objc_exception_throw` in stack
|
||||
|
||||
**Actionable steps:**
|
||||
1. Read NSException reason in crash report
|
||||
2. Common: NSInvalidArgumentException, NSRangeException
|
||||
3. Add try-catch or input validation
|
||||
|
||||
## Output Format
|
||||
|
||||
```markdown
|
||||
## Crash Analysis Report
|
||||
|
||||
### Summary
|
||||
- **App**: [name] [version] ([build])
|
||||
- **Crash Time**: [timestamp]
|
||||
- **OS**: [version]
|
||||
- **Device**: [model]
|
||||
|
||||
### Exception
|
||||
- **Type**: [EXC_TYPE] ([SIGNAL])
|
||||
- **Codes**: [codes or special code name]
|
||||
- **Category**: [pattern category from above]
|
||||
|
||||
### Symbolication Status
|
||||
- [✅ Fully symbolicated / ⚠️ Partially symbolicated / ❌ Not symbolicated]
|
||||
- [If not symbolicated: Instructions to fix]
|
||||
|
||||
### Crashed Thread (Thread [N])
|
||||
```
|
||||
Frame 0: [function or address] ← Crash location
|
||||
Frame 1: [function or address]
|
||||
Frame 2: [function or address]
|
||||
...
|
||||
```
|
||||
|
||||
### Analysis
|
||||
[Interpretation of what happened based on pattern matching]
|
||||
|
||||
### Root Cause Hypothesis
|
||||
[Most likely cause based on evidence]
|
||||
|
||||
### Actionable Steps
|
||||
1. [Specific step with code location if known]
|
||||
2. [Investigation step]
|
||||
3. [Fix recommendation]
|
||||
|
||||
### If Unsymbolicated
|
||||
```bash
|
||||
# Find dSYM for UUID: [uuid]
|
||||
mdfind "com_apple_xcode_dsym_uuids == [UUID]"
|
||||
|
||||
# Symbolicate address manually
|
||||
xcrun atos -arch arm64 -o MyApp.app.dSYM/Contents/Resources/DWARF/MyApp -l [load_address] [crash_address]
|
||||
```
|
||||
```
|
||||
|
||||
## Symbolication Commands
|
||||
|
||||
When crash is not symbolicated, provide these commands:
|
||||
|
||||
```bash
|
||||
# Find dSYM by UUID (from crash report's usedImages)
|
||||
mdfind "com_apple_xcode_dsym_uuids == YOUR-UUID-HERE"
|
||||
|
||||
# If dSYM not found, check Archives
|
||||
ls ~/Library/Developer/Xcode/Archives/
|
||||
|
||||
# Symbolicate a single address
|
||||
xcrun atos -arch arm64 \
|
||||
-o /path/to/MyApp.app.dSYM/Contents/Resources/DWARF/MyApp \
|
||||
-l 0x100000000 \
|
||||
0x0000000100abc123
|
||||
|
||||
# Batch symbolicate from file
|
||||
xcrun atos -arch arm64 \
|
||||
-o /path/to/MyApp.dSYM/Contents/Resources/DWARF/MyApp \
|
||||
-l 0x100000000 \
|
||||
-f addresses.txt
|
||||
```
|
||||
|
||||
## When to Escalate
|
||||
|
||||
Report to user and stop if:
|
||||
- Crash log is truncated or corrupted
|
||||
- Format is unrecognized
|
||||
- Critical information is missing (no exception type, no threads)
|
||||
- Multiple unrelated issues in single crash (unusual)
|
||||
|
||||
## Related
|
||||
|
||||
- `axiom-testflight-triage` — Full TestFlight workflow including Organizer
|
||||
- `axiom-memory-debugging` — For memory-related crashes
|
||||
- `axiom-swift-concurrency` — For concurrency-related crashes
|
||||
- `axiom-xcode-debugging` — For build/environment issues
|
||||
Reference in New Issue
Block a user