npx claudepluginhub himattm/skills --plugin androidThis skill uses the workspace's default tool permissions.
- "It crashes sometimes" — intermittent failure with no reliable repro
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Guides code writing, review, and refactoring with Karpathy-inspired rules to avoid overcomplication, ensure simplicity, surgical changes, and verifiable success criteria.
Executes ctx7 CLI to fetch up-to-date library documentation, manage AI coding skills (install/search/generate/remove/suggest), and configure Context7 MCP. Useful for current API refs, skill handling, or agent setup.
Share bugs, ideas, or general feedback.
android-probe-loggingandroid-snapshot-diffandroid-regression-diff-scan or read recent crash reports# 1. adb device authorized
adb devices # expect "<id> device"
# 2. Package and main activity name (the script needs both)
adb shell pm list packages | grep -i <fragment>
adb shell cmd package resolve-activity --brief <pkg> | tail -1
# 3. The build is installed (and ideally debuggable so you can see logcat
# with full tag visibility)
adb shell dumpsys package <pkg> | grep -i 'flags=.*DEBUGGABLE'
Stressors require API-level awareness:
| Stressor command | Min API |
|---|---|
settings put system user_rotation | 17 |
setprop debug.cpu.throttle | 21 (some devices ignore on prod builds) |
am send-trim-memory <pkg> COMPLETE | 21 |
wm density <dpi> | 21 |
svc data disable / enable | always |
User-debug vs prod build. Some setprop flags are ignored on locked-down production OS images (ro.build.type=user). Check adb shell getprop ro.build.type — userdebug or eng images honor the full set; user images may silently no-op debug.cpu.throttle and others. The settings put and wm commands work on every build type.
Skip force-stop if your scenario depends on warm process state. The default loop force-stops between iterations to test cold-start paths. If your bug only repros warm (e.g. after several swipes during the same process lifetime), drop am force-stop from the trigger script and let process state persist.
You need a deterministic action sequence. "Open the app and click around" is not a sequence. Specify:
Use verify-android-layout first to find element coordinates, then translate to adb shell input.
#!/usr/bin/env bash
# /tmp/repro-trigger.sh
set -e
PKG=com.example.app
ACT=.MainActivity
adb shell am force-stop "$PKG"
adb shell am start -W -n "$PKG/$ACT" >/dev/null
sleep 2
adb shell input tap 540 1200 # open detail
sleep 1
adb shell input tap 100 100 # back
sleep 1
adb shell input keyevent KEYCODE_APP_SWITCH
sleep 1
adb shell input keyevent KEYCODE_APP_SWITCH # back to app
The -W on am start waits for launch to settle. The sleeps are critical — too fast and you're testing your adb throughput, not the app.
The canonical shape:
adb logcat -c
N=50
for i in $(seq 1 "$N"); do
echo "--- iteration $i ---"
bash /tmp/repro-trigger.sh
if adb logcat -d | grep -qE 'FATAL EXCEPTION|ANR in|tombstone'; then
echo "REPRO ON ITERATION $i"
adb logcat -d > /tmp/repro-crash.log
break
fi
done
After the loop, /tmp/repro-crash.log has the full crash output for the iteration that hit. If the loop completes clean, that's also signal — see "Stop rule" below.
Latent races often need help to surface. Layer one stressor at a time:
| Stressor | Command | Surfaces |
|---|---|---|
| Rotation | adb shell settings put system accelerometer_rotation 0 && adb shell settings put system user_rotation 1 (cycle 0/1/2/3 between iterations) | Lifecycle / config-change races |
| Density change | adb shell wm density 320 (reset with adb shell wm density reset) | Configuration-change recreation paths |
| Slow CPU | adb shell setprop debug.cpu.throttle 50 (reset with "") | Timing-dependent bugs |
| Network drop | adb shell svc data disable; sleep 3; adb shell svc data enable | Connectivity edge cases |
| Low memory | adb shell am send-trim-memory <pkg> COMPLETE | Process-death restoration |
| Background/foreground | adb shell input keyevent KEYCODE_HOME then re-launch | Lifecycle restoration |
| Slow animations | adb shell settings put global window_animation_scale 5 (reset to 1) | Animation-frame races |
Add the stressor inside the loop body, not outside it. Reset any toggled property at the end of each iteration so iteration N+1 starts clean.
Crash logs include AndroidRuntime + StackTrace + ProcessRecord — typically 50+ lines. Spawn a Sonnet sub-agent:
Read
/tmp/repro-crash.log. Find the FATAL EXCEPTION block (or ANR in block). Return: (a) exception class, (b) message, (c) the first 3 stack frames inside our package (filter outandroid.*,kotlin.*,java.*), (d) any "Caused by" chain. Under 80 words.model: "sonnet".
android-probe-logging.For "is it really fixed?" verification, 100 clean iterations under realistic stress is the gold standard — but 50 is usually convincing.
# Reset any system properties / settings you toggled
adb shell setprop debug.cpu.throttle ""
adb shell settings put global window_animation_scale 1
adb shell settings put system accelerometer_rotation 1
adb shell settings put system user_rotation 0
adb shell wm density reset
adb shell svc data enable
# Delete scratch files
rm -f /tmp/repro-trigger.sh /tmp/repro-crash.log
# Kill any background loop processes (if you ran in background)
jobs -p | xargs -r kill 2>/dev/null
The most common failure: leaving window_animation_scale 5 or svc data disable on the device, which then confuses every subsequent investigation. Reset everything.
| Mistake | Fix |
|---|---|
| Skipping the cleanup gate | Reset toggled props/settings; delete scratch files; orphaned disable data will haunt the next session |
| Sleeps too short between actions | You're testing adb round-trip, not the app; use 1–2s minimum, more for animations |
No am force-stop between iterations | Stale process state masks process-restoration bugs |
| Reading the crash log inline | Delegate to Sonnet; crash logs are 50+ lines of mostly framework noise |
| Layering all stressors at once | One stressor at a time; otherwise you can't attribute the repro |
for i in {1..50}; do ... done without logcat -c first | Stale crashes from earlier runs trigger false positives |
| Stopping at first iteration's crash and assuming it's the same bug | Compare with the original symptom — repro loops sometimes surface unrelated crashes |
| Loop completes clean, declaring bug "fixed" without the fix | Clean repro after a fix is meaningful; clean repro without a fix means your trigger is wrong |