OneTwoApps App Ratings & ReviewsAI crash analysis

Optional · AI crash analysis · Apple and Android · step by step

A crash report in, a ticket out. With evidence or not at all.

The report has its own tab “AI crash reports”. There you paste crash reports from Xcode, App Store Connect or the Play Console, one or several, and have an AI analyse them. Out comes a ticket with cause, location in the code, technical fix and steps to verify. The program reads the facts itself, replaces personal data before sending and recognises crashes that were analysed before. The AI must not guess: every statement must appear verbatim in the material, and a second pass checks it.

2platforms, Apple and Android
0data out without your confirmation
1×per crash, then duplicate
2AI passes: analysis and review
Example

This is what the ticket looks like

[Apple] Crash when opening the overview
Error number 3f9a1c2b4d5e · 2026-10-27 · Kasse Nord
Environment  EXC_BAD_ACCESS · SIGSEGV · 4.2.1 (812) · iOS 17.1

Cause (confidence medium)
The list is unwrapped before it has loaded.
Location     KassenView.swift:42
Evidence     “0 KasseNord KassenView.body.getter”

Fix          Unwrap the optional safely, wait for the
             loading state, show an empty state.
Reviewer (AI) qualified · line 12 not proven
AI · anthropic/claude-opus-5-5 · facts from the parser

Why?

Seeing the crash is easy. Finding the cause takes the time.

Xcode, Crashlytics and the Play Console show you that and how often an app crashes. Then the real work begins: read the report, find the right thread, look for the file, understand the context. The AI crash analysis takes over exactly this step, as far as the material allows, and says openly when it does not.

Facts without AIParser

Exception type, signal, app and OS version, top frames, which of them are your code, whether the report is symbolicated or obfuscated. The program computes this, never the AI.

Cause with evidenceAI

Every statement about the cause needs a verbatim quote from report, note, source code or reviews. The program filters out invented quotes.

Second opinionReviewer

A second AI pass checks the analysis against the same material. It may strike and lower the confidence, never raise it.

Never twiceError number

Every crash gets an error number. If the same crash comes from another device, it is a duplicate and costs nothing.

In contextReviews

Reviews of the app with crash keywords go along as context. No other tool has this, because it does not have the reviews.

Pass it onTicket

The result as a ticket to the clipboard for Jira or mail, to print or as PDF, several at once too.

Pros and cons

What you gain, and where it honestly does not help.

The quality of the analysis depends on two things: the report and the model. With a symbolicated report, the matching source code and a strong model, the cause of the common crash types is usually found quickly. Without symbols nobody can determine the cause seriously, no AI either.

Helps a lot
  • symbolicated Apple reports and unobfuscated Android stack traces
  • common crash types: unwrapping nil, index out of range, released object, main-thread violation, NullPointer, fragment lifecycle
  • with a project folder in the request: the AI sees the line where it breaks
  • many identical crashes: analysed once, duplicates afterwards
Helps little or not at all
  • unsymbolicated reports (addresses only): symbolicate with the dSYM first; the report warns beforehand
  • obfuscated Android traces (ProGuard/R8, classes like a.b.c): retrace with mapping.txt first
  • crashes deep in the system without an own frame
  • a weak model: for crashes the best available pays off

No replacement for Crashlytics or the Xcode Organizer. They show frequency and distribution. The AI crash analysis starts after that: it helps to understand a single crash. A human still builds and tests the fix.

Step 1 · Enable

If the AI already runs, the crash analysis is already on.

The crash analysis needs AI switched on (a provider with a key or a local model, see Set up AI). The switch ai.features.crashReports is then on by itself. If AI is off, the tab never appears, whatever the switch says.

1

Open the setup

./ratings.sh admin or short menu 7. The page runs only on your computer (more about the setup).

2

Step AI

Under “What the AI should do” check “AI crash reports in the report”. Below it the box “AI crash reports” appears.

3

Save

The page checks everything with the scripts’ rules, backs up the old version and tells you which running scripts must restart.

Step 2 · Choose the model

A cheap model is enough for reviews. For crashes take the best.

Per provider there are three models, one per AI tool. They are chosen only in the setup in the browser; nobody can change the model in the report. The tab shows at the top which one applies.

1 · Analysis of reviewsproviders[].model

Many reviews in batches, every day. A cheap, fast model is usually enough.

2 · AI questionsproviders[].questionsModel

Single questions to the reviews. Empty means: same as the analysis.

3 · AI crash analysisproviders[].crashModel

Reading stack traces and code correctly is the hardest task. The strongest available model here. Empty means: same as the analysis.

Local works too. With the provider local (Ollama, LM Studio) everything stays on your computer, the source code too. Small local models read stack traces clearly worse though; the review pass catches part of it, it does not replace a strong model.

Step 3 · Set safety

You decide what goes along besides the report. And whether paths are visible.

The box “AI crash reports” in the setup has three switches. They apply to everyone who uses the report; they cannot be changed in the report itself.

Send source code to the AI?sendSource

Off: no source code ever leaves the computer, the “project folder” field is missing from the form. On: only from the project folder you give in the request, and only the files the stack trace names.

Send reviews as context?sendReviews

Off: only report and note go along. On: up to ten reviews of the assigned app with crash keywords.

Show the full path of the project folder?showSourcePath

Off: table, request and ticket show the folder by name only (“…/pos-app”). A full path often contains the user name. When editing, the folder is kept as long as the field stays empty.

Project folder per requestform in the report

Not in the setup: you give the folder in every request, matching app and platform, such as the iOS project for an Apple crash: type it or click through the folders with “Choose folder …” (the service shows folder names only, no files, and marks detected Xcode and Gradle projects). The service checks it before reading: it exists, is a folder, not the whole disk, not the home folder, not a hidden folder.

Agent: request further filesagent · agentRounds

On: the AI may request further files or classes in up to four rounds. Off: only the files the stack trace names go along.

Send without asking?agentAutoApprove

Off (recommended): you approve every requested file in the report one by one. On: the service delivers within the limits by itself; what was sent is listed in the ticket.

Review passreview

On: every analysis is checked by a second AI call. Costs about twice the tokens. Default on.

LimitsmaxSourceFiles · maxSourceChars · maxReportChars

At most 8 source files, 60,000 characters of source and 120,000 characters of report per request. Rarely changed.

Step 4 · Start

One command starts service and report. The tab appears only then.

The crash analysis runs through the same small service as the AI questions. It runs only on your computer (127.0.0.1) and only while you start it. The report on the server never has the tab.

1

Start

./ratings.sh ai-report, in the menu “Bericht mit KI-Fragen” (report with AI questions). The report opens in the browser.

2

Open the tab

Tab “AI crash reports”. At the top it says which model applies; the filter is hidden here, it has nothing to do with crashes.

3

Stop

Ctrl+C in the window. After a change in the setup stop once and start again, otherwise the old setting applies.

The flow

Five stations. Sending happens only at the fourth, and only with your confirmation.

This is how a request runs, from pasting to ticket.

1 · INPUTCreate a requestreport, title, platform,stored locally 2 · READ WITHOUT AIFacts, error numberparser, placeholders,warnings 3 · COMPAREKnown already?yes: duplicate,nothing is sent 4 · PREVIEWSee, then sendexact text, tokens,only then HTTPS 5 · AIAnalysis, reviewevidence checked,ticket
a request on its waycheck before saving
1 · InputCreate a request

“+ New request”. Required: platform (Apple or Google), title, the complete report. Optional: a note (iOS version, feature, architecture, what was already checked), the app and the project folder of this app and platform (empty means: no source code; the field suggests folders of earlier requests). “Save” stores the request in data/crash-reports.json, on your computer. Up to here nothing leaves the computer.

2 · Read without AIFacts and error number

The parser reads exception type, signal, app and OS version, the top frames of the crashed thread and which of them are your code. It detects missing symbolication and obfuscation and warns. From exception type, signal and the app frames without addresses it builds the error number: the same crash from another device has the same number.

3 · CompareAnalysed before?

If the error number is in data/crash-history.json, the request becomes a duplicate at once: it shows the old analysis with a note where it came from and is never sent to the AI. The history stays even if you delete the first request.

4 · PreviewSee first, then send

Tick one or several, “Analyse” (no tick = all open). First the service builds exactly the text that would leave for each request and shows it to you: the redacted report, what was replaced, which source files go along, how many reviews, the estimated tokens and your monthly usage. Only “Submit” in this preview sends.

5 · AnalysisEvidence only

Requests run one after another, a window shows “2 of 5” and can be cancelled. The AI gets the clear order not to guess. The program checks every quote verbatim against the material; what is not there is dropped. Without evidence the confidence becomes “low”, with an unsymbolicated report at most “medium”.

5a · AgentThe AI asks for more

If the stack trace is not enough, the AI may name instead of an answer which file or class it still needs and why, at most five per round. The service looks it up in the request’s project folder, by file name or by the place where the class is defined. A window appears in the report: every file with path and the AI’s reason, to be approved or declined one by one. Only then does it continue, up to four rounds; after that the AI must answer. Declined files are never sent, the AI only learns that they were declined.

6 · ReviewThe second pass

A second AI call gets the same material and the analysis. It checks whether the evidence holds, whether the location exists and whether the mechanism follows from the frames. It may strike and lower the confidence, never raise it. If it says “rejected”, the result reads “not determinable”.

7 · ResultTicket and history

The analysis is written into the request, the error number into the history. If the provider is missing or something aborts, only this request becomes “error”, the others go on. Then: click the row, copy the ticket, print it or save it as PDF.

New request3f9a1c2b4d5ecrash-history.jsona81c0e77f2d43f9a1c2b4d5ec02b9e11aa3f77d1f0b3c9e2AI providerwould be askedAI providernot asked, 0 tokensDuplicateold analysis taken over
Before every call: is the crash already known?The error number of the new request is compared with all analysed so far. If it matches, the request becomes a duplicate, shows the old analysis and costs nothing. The same crash from another device or with other addresses has the same number.
AI answer: evidenceMaterial: report, code, noteThread 0 Crashed:0 KasseNord KassenView.body.getter1 KasseNord KassenViewModel.load()2 SwiftUI ViewGraph.updateOutputs“Thread 0 Crashed”“KassenView.body.getter”“ListCache.reset()”1 quote is not in the material: dropped · confidence drops
After the answer: every quote checked verbatimThe program looks up every piece of AI evidence in the report, the note, the source code and the reviews. If it is not there, it is dropped. Without evidence the confidence drops to “low”. Then a second AI pass checks the whole analysis and may only weaken it.

Privacy and personal data

The AI gets only what it needs for the cause. The program replaces the rest beforehand.

Crash reports rarely contain data of users, but often device identifiers and the developer’s user name in file paths. The AI needs none of this to find a bug. So the program replaces it with placeholders before sending, and the preview shows you exactly what leaves.

Crash report, before sendingPath: /Users/anna.mueller<nutzer>/Library/Developer/KasseNord.app/Library/Developer/KasseNord.appIncident Identifier: 1B2C3D4E-5F60-7A8B-9C0D-1E2F3A4B5C6D<kennung>Android ID: 3fa85f6457174562b3fc2c963f66afa6<kennung>Contact: anna@example.com<e-mail>0 KasseNord 0x0000000104a1c2f0 KassenView.body.getter✓ stays: frames, addresses, binary UUIDs
Before sending: placeholders instead of personal dataUser name in the path, device and incident identifiers, e-mail address: the program marks and replaces them before anything leaves the computer. What the AI needs to read the report stays. If something had to be replaced, the status later reads “Analysed/PD”.
The program replaces with placeholders
  • user names in paths (/Users/…, /home/…, C:\Users\…)
  • app container IDs
  • device and incident identifiers: Incident Identifier, CrashReporter Key, serial number, IMEI, Android ID, Device ID, UDID
  • e-mail, IP and MAC addresses, phone numbers
  • long identifiers from 40 hex characters (tokens, device IDs)
  • the same in your note and in the source code
This leaves the computer, after your confirmation
  • the redacted report and the redacted note
  • the parser’s facts (exception type, signal, versions)
  • only if switched on and a project folder is given: excerpts of the source files the stack trace names, with the path relative to the project folder
  • with the agent: also the files the AI requests and you approve in the window
  • only if switched on and an app is assigned: up to ten reviews with crash keywords (text, stars, date, version; never user names)
Never
  • the path of your project folder
  • files outside the request’s project folder, files without a code suffix, files the stack trace does not name
  • credentials, keys, client names
  • a crash already analysed (duplicate)
  • anything without confirmation in the preview
Where it goes
  • to exactly one provider of your choice (OpenAI, Google, Anthropic, Perplexity, xAI; all USA) directly from your computer via HTTPS
  • or to a local model on your computer: then there is no recipient
  • stored only with you: data/crash-reports.json and data/crash-history.json, permissions 0600
Analysed/PDWhen something had to be replaced

If the program replaced anything, the request ends with the status “Analysed/PD” and names kind and number of the replacements. In a crash report this should not happen; the status makes it visible.

LimitPatterns, not understanding

Redaction recognises patterns. A name somebody types freely into the note, or a client name in an error message, it does not recognise. Hence the preview: read, then send.

Source codeCompany property

If you do not want code in the cloud, switch off “send source code” or use a local model for the crash analysis.

ProviderExclude training

The provider’s API terms apply to the transfer. Choose one whose terms exclude using inputs for training. Details in the privacy policy.

The prompts, verbatim

Exactly this is what the AI reads. None of it is hidden.

Every request consists of a system instruction (the rules) and a user text (the material). The system instruction is fixed and shown here unchanged, exactly as the program sends it. The language follows ai.language; the German version is on the German page and in KI-PROMPTS.md, section 7a. A test checks that this page and the code match.

Pass 1 · system instruction of the analysis

You are a senior mobile engineer analysing one crash report for the development team. Work only with the material given: the report, the engineer's note, the source excerpts and the user reviews. Never guess, never invent frames, files, line numbers or APIs. Every statement about the cause needs evidence quoted verbatim from the material. If the material does not allow a conclusion, say so and name exactly what is missing (symbolication, mapping file, more context, a specific source file). Answer only with valid JSON: {"summary": "one sentence", "cause": "most likely cause, or 'not determinable'", "confidence": "hoch|mittel|niedrig|unbestimmbar", "evidence": [{"source": "report|code|note|review", "text": "verbatim excerpt"}], "location": "file:line or frame, or null", "fix": "technical fix, concrete", "steps": ["how to reproduce or verify"], "openQuestions": ["what remains unclear"], "notChecked": ["what you could not check"], "missing": ["what would be needed"]}. "hoch" only when report and code agree and the mechanism is explained; "mittel" for a plausible mechanism with partial evidence; "niedrig" for a hypothesis; "unbestimmbar" when the report is unsymbolicated, obfuscated or incomplete. Under 250 words in total, in English. Do not output personal data, even if it appears in the material.

Pass 1 · user text (example with placeholders in angle brackets)

Aufgabe: Finde die Ursache dieses Absturzes, soweit das Material es erlaubt, und schlage eine technische Lösung vor. Nenne, was du nicht prüfen konntest.

Plattform: Apple (iOS/macOS)
Titel: <Titel>
Fakten aus dem Parser (nicht von dir): Typ=<Typ>, Signal=<Signal>, Version=<Version>, OS=<OS>

Anmerkung des Entwicklers:
<Anmerkung>

Crash-Report:
<bereinigter Report>

Quelltext-Ausschnitte:
--- Kasse/KassenView.swift (Zeilen 1–122) ---
<Ausschnitt>

Nutzerrezensionen mit Absturz-Stichworten (Kontext, keine Beweise):
[n=1, app=<App>, store=apple, sterne=1, datum=2026-10-20, version=4.2.1] | titel: <Titel der Rezension> | text: <Text>

The line “Fakten aus dem Parser” contains only what the parser found. “Anmerkung”, “Quelltext-Ausschnitte” and “Nutzerrezensionen” are missing when there are none or the setup switches them off. At this point the report is already redacted. The user text is always labelled in German; the system instruction sets the answer language.

Agent · addition to the system instruction while the AI may still request files

Agent mode: if the material is not enough, you may instead request further source files or classes of this project, at most 5 per round. Then answer only with valid JSON: {"need": [{"name": "file name or class name", "why": "what you need it for"}]}. Request only what you really need for the cause; the developer approves every request individually. If the material is enough, answer with the analysis.

Agent · addition to the user text per round (example)

Agentenmodus: Runde 2 von 4.
Bisherige Anforderungen:
- ListCache: übertragen
Letzte Runde: Antworte jetzt mit der Analyse, fordere nichts mehr an.

The line “Letzte Runde” comes only in the last round; then the addition to the system instruction is missing too, the AI has to answer.

Pass 2 · system instruction of the review

You are a second, independent engineer reviewing a colleague's crash analysis. You see the same material and the analysis. Your job is to catch guessing: check that every quoted piece of evidence really appears in the material, that the named location exists in the report or in the source excerpts, and that the mechanism actually follows from the frames. You may lower the confidence or strike statements, never raise it or add new claims. Answer only with valid JSON: {"verdict": "bestaetigt|eingeschraenkt|verworfen", "confidence": "hoch|mittel|niedrig|unbestimmbar", "removed": ["statement you struck and why"], "cause": "the cause as it may stand after your review", "fix": "the fix as it may stand", "notes": "one or two sentences for the team"}. Under 150 words, in English. No personal data.

Pass 2 · user text

Aufgabe: Prüfe die folgende Analyse gegen das Material. Streiche, was nicht belegt ist, und setze die Sicherheit entsprechend.

Analyse des Kollegen:
{…}

Analyse des Kollegen:
{"summary": …, "cause": …, "confidence": …, "evidence": […], "location": …, "fix": …, "steps": […]}

<then the same material as in pass 1>
After pass 1Check evidence

Every quote must appear verbatim in the material, ignoring punctuation and case, or it is dropped. Without evidence “high” or “medium” becomes “low”; with an unsymbolicated or obfuscated report at most “medium”. The named location is looked up in the material.

After pass 2Only lower

The confidence is the lower of the two levels. “rejected” gives “not determinable”. With “qualified” or “rejected” the reviewer’s cause and fix replace those of the analysis.

TruncatedFixed lengths

Summary 400, cause 1,200, fix 2,000 characters, lists eight entries each. Unknown fields of the answer are discarded.

The result

A table with colour stripes. One click, and the ticket is open.

The tab shows all requests: OS, title, date, status, result and error number. A wide colour stripe at the left of every row shows the status. A click opens the request with inputs, facts, analysis and ticket; there it can be changed, analysed again or deleted (with confirmation).

opengrey

Stored, not sent yet.

awaiting approvalyellow dashed

The AI requested further files. Open the row, “Continue approval”.

analysedgreen

Analysis done, no personal data replaced.

Analysed/PDviolet

Analysis done, personal data had to be replaced first.

duplicateyellow

Error number known already, old analysis taken over, nothing sent.

errorred

Provider unreachable, budget exhausted or cancelled. Submitting again works.

Ticketclipboard · print · PDF

Error number, environment, cause with confidence, evidence, location, fix, steps to verify, open questions, what could not be checked, the reviewer’s verdict, stack trace.

Every AI statement carries the mark “AI” with provider, model and date. Error number, facts and status are computed by the program, never by the AI.

Settings

Everything in the setup, step AI. Or in the block ai.crashReports.

The table is also in README.md (section configuration). All prompts verbatim are in KI-PROMPTS.md, section 7a.

KeyMeaningDefault
ai.features.crashReportstab “AI crash reports” on or off; works only with AI switched ontrue
providers[].crashModelmodel for the crash analysis; empty = like modelempty
crashReports.reviewsecond review pass, about double the tokenstrue
crashReports.sendSourcesend source code to the AItrue
crashReports.sendReviewssend the app’s reviews as contexttrue
crashReports.showSourcePathshow full folder paths in the report; off = names only, choice onlytrue
crashReports.agentAI may request further files or classes (only with source code and project folder)true
crashReports.agentRoundsat most this many request rounds, 1 to 104
crashReports.agentAutoApprovesend requested files without askingfalse
crashReports.maxSourceFilessource files per request8
crashReports.maxSourceCharscharacters of source per request60,000
crashReports.maxReportCharscharacters per report, longer ones are rejected120,000

When something goes wrong

Usually the service, a symbol or the right project folder is missing.

The log is in data/logs/ki.log, without keys. An error in one request does not stop the others.

Tab “AI crash reports” is missingreport

The service is not running, AI is off or ai.features.crashReports is off. Start ./ratings.sh ai-report.

“The report is not symbolicated”warning

Addresses only, no function names. Symbolicate the report in Xcode with the matching dSYM and paste it again.

“The app frames are obfuscated”warning

ProGuard/R8. Retrace the stack trace with the version’s mapping.txt (Play Console or retrace).

“Der Ordner ist zu allgemein” or “Versteckte Ordner … nicht erlaubt”saving

Give the folder of the app project, not the whole disk, the home folder or a folder whose name starts with a dot.

“File … not found below the folder”preview

The stack trace names a file that is not there: wrong folder, or the file lives in a framework. The analysis runs without it.

Status “error”after submitting

Provider unreachable, wrong key or monthly limit reached. The message is in the request; then simply submit again.