Skip to content

Shankulkarni/Crash-Pilot

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🛩️ crash-pilot

AI autopilot for Firebase Crashlytics.
Reads crashes → fixes code → opens PRs. Automatically. Every day.

iOS Android React Native Firebase BigQuery Claude License


✨ How it works

🔥 Firebase Crashlytics
         │
         │  BigQuery export
         ▼
📊 BigQuery Table
         │
         │  fetch-crashlytics.py  (new · unresolved · regressed)
         ▼
📋 crash_issues.json
         │
         │  claude -p "..."  →  Read · Grep · Edit your source files
         ▼
🔧 Code changes  +  confidence rating
         │
         │  HIGH / MEDIUM  →  open PR
         │  LOW / SKIP     →  discard
         ▼
📬 Pull Request  (impact table · root cause · Firebase Console link)

Each daily run:

  1. 🔍 Fetches top crashes from BigQuery — new issues, high-impact unresolved, and regressions
  2. 🤖 Runs Claude Code per crash — reads your source files, traces the call path, attempts a fix
  3. 🎯 Rates confidence as HIGH, MEDIUM, LOW, or SKIP — you set the bar
  4. 📬 Opens a PR with impact stats, root cause analysis, and a direct Firebase Console link

📱 Platform Support

Platform Stack Trace
iOS ✅ Supported threads[] crashed thread frames
Android ✅ Supported exceptions[].frames
React Native ✅ Supported Native frames + JS source files when readable (see details)
Flutter 🔜 Coming soon

🚀 Quick Start

Step 1 — Enable Crashlytics BigQuery Export

In the Firebase Console:

CrashlyticsBigQuery Export → Enable both toggles

  • ✅ Export Crashlytics data to BigQuery
  • ✅ Enable streaming export (for near real-time data, otherwise ~24h delay)

Firebase auto-creates the firebase_crashlytics dataset in your GCP project.


Step 2 — Create a GCP Service Account

# Create the service account
gcloud iam service-accounts create crash-pilot \
  --display-name "Crash Pilot"

# Grant read access to BigQuery
gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \
  --member="serviceAccount:crash-pilot@YOUR_PROJECT_ID.iam.gserviceaccount.com" \
  --role="roles/bigquery.dataViewer"

gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \
  --member="serviceAccount:crash-pilot@YOUR_PROJECT_ID.iam.gserviceaccount.com" \
  --role="roles/bigquery.jobUser"

# Download the key
gcloud iam service-accounts keys create key.json \
  --iam-account=crash-pilot@YOUR_PROJECT_ID.iam.gserviceaccount.com

💡 The project_id is extracted automatically from the key — no extra variable needed.


Step 3 — Find your BigQuery table name

Replace dots with underscores in your bundle / package ID:

Platform Bundle ID BigQuery Table
iOS com.mycompany.myapp com_mycompany_myapp
Android com.mycompany.myapp com_mycompany_myapp

Verify in BigQuery Studio → your project → firebase_crashlytics dataset.


Step 4 — Get a Claude Code token

claude auth login
cat ~/.claude/credentials.json | jq -r '.claudeAiOauth.accessToken'

Requires a Claude Code subscription.


Step 5 — Add secrets & variables

Go to Settings → Secrets and variables → Actions in your repo:

Name Type Value
GCP_SA_KEY 🔒 Secret Contents of key.json
CLAUDE_CODE_OAUTH_TOKEN 🔒 Secret Claude Code OAuth token
BIGQUERY_TABLE 📦 Variable e.g. com_mycompany_myapp
BUNDLE_ID 📦 Variable (optional) e.g. com.mycompany.myapp

Step 6 — Add the workflow

Copy examples/workflow.yml to .github/workflows/crash-pilot.yml:

- uses: your-org/crash-pilot@v1
  with:
    bigquery_table:       ${{ vars.BIGQUERY_TABLE }}
    gcp_credentials_json: ${{ secrets.GCP_SA_KEY }}
    claude_token:         ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
    github_token:         ${{ secrets.GITHUB_TOKEN }}
    platform:             ios   # ios | android | react-native

⚠️ Required: checkout must use fetch-depth: 0

- uses: actions/checkout@v4
  with:
    fetch-depth: 0

⚙️ Inputs

Input Required Default Description
bigquery_table BigQuery table name (e.g. com_myapp_ios)
gcp_credentials_json Service account JSON — project_id extracted automatically
claude_token Claude Code OAuth token
github_token secrets.GITHUB_TOKEN
bigquery_dataset firebase_crashlytics BigQuery dataset name
platform ios ios · android · react-native
bundle_id "" App bundle ID — enables Firebase Console deep links in PRs
lookback_hours 24 Hours to look back for new / regressed crashes
max_issues 5 Max issues per run (keep low to control costs)
min_confidence MEDIUM Minimum confidence to open a PR: HIGH · MEDIUM · LOW
default_branch main Base branch for fix branches and PRs
pr_label crash-pilot Label applied to generated PRs
claude_timeout 300 Seconds before killing Claude per issue
dry_run false Analyse crashes but skip PR creation
allow_new_files false Allow Claude to create new source files

🎯 Confidence Levels

Claude self-rates every fix before a PR is opened:

Level Meaning Action
🟢 HIGH Exact crash site found, fix is unambiguous PR opened
🟡 MEDIUM Likely cause understood, minor uncertainty PR opened
🟠 LOW Cannot confidently identify root cause Skipped
SKIP Third-party crash, runtime-only, or no source found Skipped

Set min_confidence: HIGH for a conservative setup. LOW is not recommended for production repos.


💰 Cost Estimates

Service Cost per run
BigQuery ~$0.01–$0.10 · 3 queries with partition pruning
Claude Code ~$0.05–$0.50 per issue · 5k–50k tokens depending on codebase size
Total (5 issues/day) ~$0.25–$2.60/day

⚛️ React Native

React Native stacks mix native (ObjC/Java/C++) and JavaScript frames. crash-pilot handles both layers:

Crash Layer Blame Frame Looks Like Result
✅ JS source src/screens/Home.tsx:42 Claude reads the file and attempts a fix
✅ Native module MyModule.java:88, RCTCamera.m:34 Claude reads the native file and fixes it
⛔ Compiled bundle index.android.bundle:1:234567 SKIP — source maps not in repo
⛔ Hermes bytecode .hbc file or very large column offset SKIP — compiled binary

💡 JS crashes are fixable when your source files are readable from the blame frame. This works for apps that don't minify in CI, monorepos where the RN source is in the same repo, and any setup where the .tsx/.ts/.js path in the stack trace matches a real file in the codebase.


🔒 Security

  • Runs entirely inside your GitHub Actions runner
  • Claude only has Read, Glob, Grep, Edit, Write access — no shell execution
  • Fix branches are crash-pilot/* — PRs require human review before merge
  • Service account credentials are never written to disk

🛠️ Troubleshooting

BigQuery schema error — error_type / is_fatal not found

crash-pilot auto-detects which column your export uses (error_type vs is_fatal). If detection fails it falls back to error_type = 'FATAL'. Check the logs for Fatality SQL: to see which path was taken.

Claude didn't produce /tmp/fix_summary.md

Claude timed out or errored. The action emits a ::warning:: annotation with the last 20 lines of output. Increase claude_timeout or check if the codebase is too large to traverse within the limit.

PR step is skipped silently

Ensure fetch-depth: 0 is set in your checkout step. Without it git rev-list can't compare the fix branch with the remote default branch.

BigQuery permission denied

The service account needs both roles/bigquery.dataViewer and roles/bigquery.jobUser. dataViewer alone is not enough to run queries.

PR label creation fails

The action auto-creates the label. If it fails, the PR is still opened without a label. Verify your github_token has pull-requests: write.


🤝 Contributing

To add a new platform:

  1. Add scripts/prompts/<platform>.txt — must end with $BASE_TEMPLATE
  2. Add a case in scripts/process-crashes.sh for PLATFORM_TEMPLATE
  3. Add the stack trace SQL variant in get_stack_trace_sql() in scripts/fetch-crashlytics.py
  4. Update the platform input in action.yml and this README

📄 License

MIT

About

Stop shipping crashy apps — AI reads Crashlytics, fixes code, and opens PRs automatically.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors