Optional · AI crash analysis · Apple and Android · step by step
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.
[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?
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.
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.
Every statement about the cause needs a verbatim quote from report, note, source code or reviews. The program filters out invented quotes.
A second AI pass checks the analysis against the same material. It may strike and lower the confidence, never raise it.
Every crash gets an error number. If the same crash comes from another device, it is a duplicate and costs nothing.
Reviews of the app with crash keywords go along as context. No other tool has this, because it does not have the reviews.
The result as a ticket to the clipboard for Jira or mail, to print or as PDF, several at once too.
Pros and cons
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.
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
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.
./ratings.sh admin or short menu 7. The page runs only on your computer (more about the setup).
Under “What the AI should do” check “AI crash reports in the report”. Below it the box “AI crash reports” appears.
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
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.
Many reviews in batches, every day. A cheap, fast model is usually enough.
Single questions to the reviews. Empty means: same as the analysis.
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
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.
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.
Off: only report and note go along. On: up to ten reviews of the assigned app with crash keywords.
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.
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.
On: the AI may request further files or classes in up to four rounds. Off: only the files the stack trace names go along.
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.
On: every analysis is checked by a second AI call. Costs about twice the tokens. Default on.
At most 8 source files, 60,000 characters of source and 120,000 characters of report per request. Rarely changed.
Step 4 · Start
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.
./ratings.sh ai-report, in the menu “Bericht mit KI-Fragen” (report with AI questions). The report opens in the browser.
Tab “AI crash reports”. At the top it says which model applies; the filter is hidden here, it has nothing to do with crashes.
Ctrl+C in the window. After a change in the setup stop once and start again, otherwise the old setting applies.
The flow
This is how a request runs, from pasting to ticket.
“+ 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.
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.
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.
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.
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”.
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.
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”.
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.
Privacy and personal data
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.
/Users/…, /home/…, C:\Users\…)data/crash-reports.json and data/crash-history.json, permissions 0600If 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.
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.
If you do not want code in the cloud, switch off “send source code” or use a local model for the crash analysis.
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
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.
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.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 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.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.
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.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>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.
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.
Summary 400, cause 1,200, fix 2,000 characters, lists eight entries each. Unknown fields of the answer are discarded.
The result
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).
Stored, not sent yet.
The AI requested further files. Open the row, “Continue approval”.
Analysis done, no personal data replaced.
Analysis done, personal data had to be replaced first.
Error number known already, old analysis taken over, nothing sent.
Provider unreachable, budget exhausted or cancelled. Submitting again works.
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
ai.crashReports.The table is also in README.md (section configuration). All prompts verbatim are in KI-PROMPTS.md, section 7a.
| Key | Meaning | Default |
|---|---|---|
ai.features.crashReports | tab “AI crash reports” on or off; works only with AI switched on | true |
providers[].crashModel | model for the crash analysis; empty = like model | empty |
crashReports.review | second review pass, about double the tokens | true |
crashReports.sendSource | send source code to the AI | true |
crashReports.sendReviews | send the app’s reviews as context | true |
crashReports.showSourcePath | show full folder paths in the report; off = names only, choice only | true |
crashReports.agent | AI may request further files or classes (only with source code and project folder) | true |
crashReports.agentRounds | at most this many request rounds, 1 to 10 | 4 |
crashReports.agentAutoApprove | send requested files without asking | false |
crashReports.maxSourceFiles | source files per request | 8 |
crashReports.maxSourceChars | characters of source per request | 60,000 |
crashReports.maxReportChars | characters per report, longer ones are rejected | 120,000 |
When something goes wrong
The log is in data/logs/ki.log, without keys. An error in one request does not stop the others.
The service is not running, AI is off or ai.features.crashReports is off. Start ./ratings.sh ai-report.
Addresses only, no function names. Symbolicate the report in Xcode with the matching dSYM and paste it again.
ProGuard/R8. Retrace the stack trace with the version’s mapping.txt (Play Console or retrace).
Give the folder of the app project, not the whole disk, the home folder or a folder whose name starts with a dot.
The stack trace names a file that is not there: wrong folder, or the file lives in a framework. The analysis runs without it.
Provider unreachable, wrong key or monthly limit reached. The message is in the request; then simply submit again.