Adi's Repo  /  Catalogue  /  Setup guide  /  Internals iOS 6 Siri Remastered  /  v1.4

Technical reference  ·  written to be handed to a machine

How it actually works

Every hook, every file, every endpoint, and what each failure mode really means. This is the companion to the setup guide: that page gets it running, this page is for when it is running and behaving oddly — and for anyone who simply wants to know how a 2012 assistant is talked into answering from a machine in the kitchen.

This page is meant to be copied

Select all of it and paste it into whatever assistant you use, together with the symptom and any log lines you have. It is written so that a model reading it cold has the whole system in front of it — both halves, both logs, and the specific vocabulary each one uses — and can reason about the fault instead of guessing at it.

What follows

  1. 01One request, end to end
  2. 02What is on the device
  3. 03What the tweak hooks
  4. 04What the server answers
  5. 05Why every image is plain http
  6. 06Reading the logs
  7. 07Failure modes and their causes
  8. 08When a card takes SpringBoard down
  9. 09Removing it cleanly

Two conventions throughout. <server-ip> is the LAN address of the computer running the server, and <device-ip> is the iPad's. Commands are marked as belonging to one machine or the other, because half of every confusing symptom here comes from running the right command on the wrong computer.

Section 01One request, end to end

assistantdApple's Siri daemon, with the tweak's hooks in it
——→
Your serverTranscribe, classify, fetch, answer in JSON
——→
Apple's own cardsReal SA objects, injected into the live session

Plain HTTP over the LAN in the middle. Apple's servers are not at either end.

  1. You hold the home button. SpringBoard presents Siri's interface — Apple's, unmodified — and launchd wakes assistantd, the daemon that has always done Siri's actual work. Everything the tweak does happens inside that one process. SpringBoard itself is never hooked.
  2. The dead connection is stubbed. Normally assistantd would now open a connection to Apple's assistant service and refuse to go any further without one. That service was switched off years ago. The tweak replaces -[ADAceConnection startWithAceHost:…] so that it marks itself connected and returns, and isConnected so it agrees. The session proceeds as though the far end answered. No packet is sent, and the three ADCommandCenter methods that would push anything outbound are dropped on the floor.
  3. The microphone is tapped, not replaced. The tweak has hooked CoreAudio's AudioQueueNewInput, so when Siri opens its input queue the tweak's own callback sits in front of Apple's. Each buffer is copied aside and then handed straight on, which means Apple's recording, level metering and endpointing all continue exactly as before. A refId — a fresh UUID — is minted the moment recording starts, and it is what ties this request together from here on.
  4. The utterance is posted. When recording stops, the captured PCM gets a WAV header and is POSTed as multipart form data to <ServerURL>/converse. That is the only network call the device makes for the request, it is plain HTTP, and it stays on your LAN.
  5. The server does the thinking. mynah-server hands the audio to mynah-stt and gets a transcript; asks the local model in Ollama what kind of question this is and what the parameters are; fetches the live data from whichever public source that intent needs; and, if the answer has pictures in it, downloads and downsizes each of them first so that the device is only ever given an address on the server itself.
  6. One JSON object comes back, always the same shape — a transcript, a line to speak, and zero or more cards.
  7. Native objects are built and injected. The tweak turns that JSON into real SA* instances — the same classes iOS 6 builds for itself when Apple's service answers — marks the request outstanding so the session will accept them, and pushes them into the live session through -[ADSession aceConnection:didReceiveAceObject:], the same entry point Apple's own replies came in on.
  8. The interface draws them. Apple's card code, in Apple's interface, drawing objects it believes came from Apple.
Two facts worth being precise about

Apple's servers are never contacted. Not contacted and ignored, not contacted and failing quietly — the calls that would reach them are removed while the tweak is enabled. This is the whole reason the thing still works when the service behind it does not.

The Siri interface is Apple's. There is no reimplementation, no reskin and no custom view anywhere in this project. The weather widget, the sports board with its line score, the athlete card, the ticker, the movie marquee — all of it is code that shipped on the device in 2012, drawn from objects the tweak fills in.

Section 02What is on the device

The package installs eight files in three places, and creates a ninth at runtime:

/Library/MobileSubstrate/DynamicLibraries/
    SiriRemastered.dylib     the tweak itself (armv7, ~40 KB)
    SiriRemastered.plist     the filter -- see below

/Library/PreferenceBundles/SiriRemastered.bundle/
    Info.plist              NSPrincipalClass = SRRootListController
    Root.plist              the Settings pane's schema
    SiriRemastered           the pane's compiled binary
    icon.png, [email protected]

/Library/PreferenceLoader/Preferences/
    SiriRemastered.plist     puts the row into Settings.app

created on first save, and left behind on uninstall:
/var/mobile/Library/Preferences/
    com.aditya.ios6siriremastered.plist

The filter plist

Substrate reads /Library/MobileSubstrate/DynamicLibraries/SiriRemastered.plist to decide where the library goes. It contains exactly one instruction:

{ Filter = { Executables = ( assistantd ); }; }

So the library is loaded into processes named assistantd and into nothing else. Every other process on the device — SpringBoard included — never sees it. The tweak's constructor then checks the process name a second time and returns immediately if it is anything else, which is belt and braces on the same guarantee.

If this plist is missing, the dylib is never loaded and the tweak is simply absent: no log lines, no Settings behaviour, nothing. That makes it the first thing to check when the tweak seems not to exist.

The preferences plist

Every setting lives in one file, /var/mobile/Library/Preferences/com.aditya.ios6siriremastered.plist. The Settings pane reads and writes that file directly rather than going through CFPreferences, and the tweak reads the same file, so there is exactly one source of truth and no cache to disagree with it.

The pane makes no network calls at all. It does not ask the server what models exist, it does not fetch the effective configuration, and it does not push anything back — earlier builds did, and the cost of a LAN round trip on a 2012 device was visible every time the pane opened. That plist is now the only channel between the pane and the tweak, in both directions. It also means the pane works perfectly well with the server switched off.

KeyTypeWhat it does
ServerURLstring The only required setting. A bare host:port is accepted and http:// is prepended. Blank means the tweak stays completely inert, whatever else is set.
Enabledbool Master switch, default on. Only meaningful once ServerURL has a value: the two are ANDed together.
Locationstring Place name for “near me” and unqualified weather. Sent as a form field on every request. A place named in the question beats it.
Unitsstring imperial or metric. Also sent on every request.
CardAnswer
CardWeather
CardSports
CardStocks
CardMovies
CardRestaurants
bool One per card type, all default on. Applied on the device as the reply is unpacked, so turning one off suppresses the card and leaves the spoken answer alone.
Model
OllamaURL
SearXNGURL
TMDBKey
WolframAppID
string Vestigial. loadPrefs() still reads them, nothing ever sends them, and the Settings pane no longer offers rows for them. An older device may still carry values here; they have no effect. Set the model and the keys on the server, in .env.

When a change takes effect

The tweak reads that plist once, in its constructor — that is, at the moment Substrate loads the library into assistantd, and again at the start of every recording — the hook on -[ADSpeechManager voiceControllerDidStartRecording:successfully:] calls loadPrefs() before anything else it does.

So a change made in Settings takes effect on your next question. No respring, and no killall. That matters while debugging: flip a card off, ask again, and the new setting is already in force.

If you want to be certain the library itself has been reloaded — after replacing the dylib, say, rather than after changing a setting — force the daemon to restart:

# on the device, over SSH
killall assistantd

That is a reload, not an outage. assistantd is a launch-on-demand job: launchd starts it again the next time you hold the home button. Nothing is lost and nothing needs restarting afterwards.

A respring is never required for this tweak. SpringBoard has none of it loaded, so there is nothing in SpringBoard to refresh. If a piece of advice tells you to respring for a settings change here, it is wrong.

Section 03What the tweak hooks

The constructor bails out unless the process is assistantd, loads the preferences, and installs two function hooks and nine method hooks. Every one of the method hooks checks the enabled flag first and calls straight through to the original when it is off — turning the switch off makes the tweak transparent rather than absent.

Function hooks, in CoreAudio

Method hooks, in AssistantServices

ClassSelectorWhat the hook does
ADSpeechManager voiceControllerDidStartRecording:
successfully:
Mints a fresh refId and empties the audio buffer. This is where a request begins.
ADSpeechManager voiceControllerDidStopRecording:
forReason:
Wraps the captured PCM in a WAV header and POSTs it to <ServerURL>/converse, with a 45-second timeout.
ADAceConnection startWithAceHost:languageCode:
timeout:preferWWAN:
Stubbed entirely. Calls _setConnected: on itself and returns without dialling anything. The hook that makes a dead service irrelevant.
ADAceConnectionisConnected Returns true, so the session believes it has a live connection.
ADAceConnectionsendCommand:error: Swallowed; reports success and clears the error.
ADCommandCenter _sendRequestToServer:
_sendCommandToServer:
_sendRetryableRequestToServer:
Dropped. Nothing outbound survives while the tweak is enabled.
ADCommandCenter_refIdIsSpeechStart: Returns true for the tweak's own refId, so the session treats the injected reply as belonging to a real speech request.

How the reply is delivered

When the JSON arrives, on the main thread the tweak:

  1. finds the live session — [ADCommandCenter sharedCommandCenter], then its _session, then that session's _serverConnection ivar;
  2. calls _addOutstandingRequestId: with the refId, which is what makes the interface willing to accept objects for it;
  3. injects, in order: an SASSpeechRecognized carrying the transcript — this is what puts your words on the screen — then an SAUIAddViews holding an SAUIAssistantUtteranceView for the spoken line plus one snippet per card, and finally an SARequestCompleted to close the request out.

Each injection is a direct call to -[ADSession aceConnection:didReceiveAceObject:].

Which card type maps to which object, and which switch

The type string on each element of the server's cards array selects a builder. Note that the athlete card is gated by the Sports switch rather than one of its own:

typeSettings switchRoot class built
answerAnswers & MathsSAAnswerSnippet
weatherWeatherSAWeatherForecastSnippet
sportsSportsa sports snippet, with baseball getting its own matchup class
athleteSportsSASportsAthleteSnippet
stockStocksSAStockSnippet
movies, movieMoviesSAMovieMovieListSnippet, falling back to SAMovieMovieSnippet for a single film
restaurants, restaurantRestaurantsa local-search snippet, list or detail depending on the count

Every object is built by KVC and every step is guarded. A class that does not exist on this firmware is logged as MISSING class <name> and that card is dropped; a value of the wrong type is coerced or skipped; arrays that Apple's own code would dereference unguarded are never emitted empty. The design rule throughout is that a missing card is always better than a crash.

Section 04What the server answers

mynah-server is a FastAPI service on port 8807, published on all interfaces because the device has to reach it. mynah-stt's port 8808 is bound to 127.0.0.1 only — it is a debug port, and the device never touches it.

MethodPathWhat it is
POST/converse The one the device calls. Multipart audio in, the reply envelope out.
GET/debug?q= The same pipeline with text in place of audio. The best debugging tool in the system.
GET/healthz Status of the speech container, the model, the search backend and the movies key.
GET/config The effective configuration, secrets redacted. LAN-only.
POST/config Writes per-device overrides. LAN-only.
GET/models What Ollama actually has installed. LAN-only. Nothing on the device calls it; it is for you, with curl.
GET/img/<sha1>.jpg A pre-staged, downsized image served over plain http.
GET/render Server-typeset maths and function plots, staged as images.
GET/go/opentable/<token> 302 redirect to a real OpenTable search.

POST /converse

Multipart form data. The tweak sends codec (pcm_s16le_16k_wav), lang (en-US), session (the refId), location and units when those are set in Settings, and the WAV itself as the audio part. The server additionally accepts lat, lon and client_time, which this tweak does not send.

The reply is always the same envelope, whatever went right or wrong:

{
  "transcript": "what's the weather in london",
  "speak": "It's 14 degrees and cloudy in London.",
  "dialogPhase": "Summary",
  "listenAfterSpeaking": false,
  "cards": [ { "type": "weather", … } ]
}

"dialogPhase": "Error" marks the failure envelopes. An empty cards array is a normal, correct answer for conversation, greetings and honest “no results” replies.

GET /debug?q=…

The most useful thing on the server. It runs the complete pipeline — classify, fetch, build the cards, compose the spoken line — from typed text, skipping only transcription, and returns exactly the envelope /converse would have returned. No device, no microphone, no network between machines.

# on the server machine
curl "http://localhost:8807/debug?q=weather+in+London"
curl "http://localhost:8807/debug?q=AAPL+stock"
curl "http://localhost:8807/debug?q=who+won+the+Yankees+game+last+night"

It also takes units, lat, lon and location. Always try this before blaming the device. If /debug gives the right answer, everything except the microphone and the LAN is working, and the fault is in one of two much smaller places.

GET /healthz

{"status":"ok","stt":"Systran/faster-distil-whisper-small.en",
 "llm":"gemma4:e4b","search":"duckduckgo",
 "movies":"needs TMDB_API_KEY","public_base":"http://<server-ip>:8807"}

"stt":"unreachable" means the speech container is not answering — usually still downloading its model on a first run. Check docker compose logs -f mynah-stt.

GET /config and POST /config

Both are refused with 403 unless the caller's address is private, loopback or link-local, because iOS 6 cannot encrypt anything and these carry configuration. GET returns the effective configuration with tmdb_api_key and wolfram_appid redacted to set (…cd5f) or unset, so you can confirm a key was typed correctly without it ever being printed. The overrides_set list tells you which values are coming from a device override rather than from .env.

POST accepts a fixed key list — tmdb_api_key, wolfram_appid, model, ollama_url, searxng_url, public_base, units, default_location, default_city, default_lat, default_lon — and persists them to /data/config/overrides.json inside the container, which is ./config/overrides.json beside the compose file. Precedence is override, then .env, then the built-in default. An empty value clears an override.

Nothing on the device writes to this endpoint

Only four settings and the six card switches affect a request. Server URL and Enabled decide whether the tweak acts at all; Location and Units ride along as form fields on every /converse; the card switches are applied on the device as the reply is unpacked.

The model and the API keys are not among them, and there is no way to set them from the iPad. POST /config works, but nothing on the device ever calls it: the Settings pane makes no network calls, and the routine in the tweak that would have pushed overrides is compiled and never invoked. Earlier builds of the pane had Model, Ollama URL, SearXNG URL, TMDB Key and Wolfram AppID rows; they were removed, both because they cost a LAN round trip on every open and because those settings belong on the server. A device upgraded from one of those builds may still have the values sitting in its plist, doing nothing.

So: the model and the API keys are set on the server, in .env, and nowhere else. That is also the safer arrangement — a key typed on the device would cross the network in plain text, because iOS 6 cannot encrypt anything.

POST /config is still reachable with curl from the LAN, if you want to change something without editing .env and restarting. It is simply not a path the device uses.

GET /models

LAN-only. Returns what Ollama has installed, with the model currently in use first and flagged:

{"models":[{"name":"gemma4:e4b","size":"4.7 GB","current":true},
            {"name":"llama3.2:3b","size":"2.0 GB","current":false}],
 "current":"gemma4:e4b"}

If Ollama cannot be reached the response carries "error": "ollama unreachable" rather than failing, which makes it a quick way to confirm the container can see Ollama at all. The Settings pane used to populate a model picker from this; it no longer does, and this endpoint is now purely for your own use with curl.

The image and link endpoints

Section 05Why every image is plain http

iOS 6 cannot load any https URL at all. Not an image, not a link, not a favicon. It is missing the certificate roots the modern web is signed with, and nothing on the device can supply them.

So the server does the loading. Every poster, team logo, headshot and photograph is fetched by the server, resized to something an A6X decodes quickly, written into its own on-disk cache, and handed to the device as a plain http://<server-ip>:8807/img/<hash>.jpg. The device only ever loads images from your own machine.

Three consequences follow, and between them they explain a good share of everything that goes wrong:

  1. The Server URL must be http://. This is not a preference or a security trade-off you are being offered — the image addresses are built from that same base, so an https:// server address fails for the pictures exactly as it fails for everything else.
  2. A broken image URL is worse than no image. The tweak refuses outright any image URL that is not plain http, logs photo not plain http -> dropped, and omits the field. The reason is specific: on iOS 6's card code both completion paths of a failed image load call setImage: with nil, which wipes the placeholder artwork that had already been drawn. An omitted image keeps the placeholder; a broken one leaves a hole.
  3. The first use of a given image is slower than the rest. MYNAH_STAGE_BUDGET — 3.5 seconds by default — caps how long the server waits for a card's images before sending the card anyway. Anything still downloading finishes in the background and is a cache hit next time.

The same rule is why PUBLIC_BASE should be left blank. The server learns its own address from the Host header on the device's own request, which is by definition an address the device can reach. Hard-coding it can only make that worse, and is worth doing only behind a reverse proxy.

Section 06Reading the logs

On the device

Over USB, from the computer, with libimobiledevice installed. Every line the tweak prints is prefixed [SiriRemastered]:

idevicesyslog | grep SiriRemastered

This needs nothing installed on the device and works whether or not SSH is set up, which makes it the reliable route. Leave it running and then ask Siri something.

A healthy request looks like this — values are illustrative, the sequence is not:

[SiriRemastered] loading (server=http://<server-ip>:8807 enabled=YES cards: answer=1 weather=1 sports=1 stocks=1 movies=1 restaurants=1)
[SiriRemastered] v2 hooks installed
[SiriRemastered] AudioQueue tap: rate=16000 ch=1 fmt=0x6c70636d
[SiriRemastered] record START (ok=1) minted refId=1D4F…
[SiriRemastered] record STOP (reason=1): 51200 bytes ch=1 rate=16000 (~1.6s) -> POST flux
[SiriRemastered] flux reply: transcript="what's the weather" speak="It's 14 and cloudy." cards=1
[SiriRemastered] delivered reply for refId=1D4F… (1 card(s))

The diagnosis is in which line you do not see:

What is missing, or what it saysWhat that means
No loading line at all The library is not being injected. Substrate missing or broken, the filter plist absent, or the dylib not on disk. Check that both files exist under /Library/MobileSubstrate/DynamicLibraries/.
loading … server=<unset> No Server URL in Settings. The tweak is deliberately inert until one is set, whatever the Enabled switch says.
loading … enabled=NO Enabled is off, or the URL is blank. Every hook is calling straight through to Apple's original.
No AudioQueue tap line assistantd never opened an input queue, so Siri never got as far as listening. The fault is upstream of the tweak entirely.
record START and no record STOP Still recording. Endpointing has not fired — usually it is waiting for you to stop talking.
record stop but no audio captured The tap saw no buffers between start and stop: an empty recording, or audio that came through a path the hook did not see.
-> POST flux and then nothing The request left the device and no reply came back inside 45 seconds. Wrong address, wrong network, server down, or a server still thinking.
flux error: … The reason is on the line: connection refused, timed out, HTTP 500. This is the network or the server answering, not a device fault.
flux reply … cards=0 The server chose not to draw a card. Nothing is wrong on the device; ask the same thing of /debug to see why.
cards=2 then delivered reply … (0 card(s)) The device discarded them: that card type's switch is off in Settings, or a MISSING class line just above says the class does not exist on this firmware.
no live session; cannot deliver The answer arrived after the Siri interface had been dismissed. Ask again and wait for it.

On the server

docker compose logs -f mynah-server           # follow live, Ctrl-C to stop
docker compose logs --tail 200 mynah-server   # the last 200 lines
docker compose logs -f mynah-stt              # the speech container
docker compose ps                             # running? or restarting in a loop?

Lines from the service are prefixed [mynah], and two of them carry most of the diagnostic weight:

[mynah] transcript: "what's the weather in london"
[mynah] intent: weather plan: {…}

The first is what it heard, the second is what it decided that meant. Between them they separate mishearing from misunderstanding, which are different problems with different fixes. Everything else in the log is a named failure of one data source — espn failed:, tmdb failed:, overpass failed:, wolfram failed:, ollama tags unreachable:, stage failed: — and reads plainly.

A container that docker compose ps reports as restarting is crashing and coming back; the error sits just above each restart in the log.

The order to work in

This sequence localises almost any fault in four commands, and it matters that it is in this order — each step rules out everything before it:

  1. curl "http://localhost:8807/debug?q=…" on the server machine. If this is wrong, stop: the device is irrelevant and the problem is server-side.
  2. curl http://<server-ip>:8807/healthz from a different computer on the same Wi-Fi. If step 1 worked and this does not, it is the network or the firewall — the same trip the device makes.
  3. curl http://<server-ip>:8807/config — confirm the server is using the model, keys and location you believe it is.
  4. Only now involve the iPad, with idevicesyslog | grep SiriRemastered already running.

Section 07Failure modes and their causes

“Sorry, I couldn’t reach the server.”

That exact sentence is written on the device, not by the server, so hearing it proves the tweak is loaded, heard you, tried, and the round trip failed. The flux error: line immediately before it names the reason. In order of likelihood:

  1. The Server URL is wrong — https:// instead of http://, a stale IP address, a missing :8807, or a trailing slash.
  2. The two machines are not on the same network. Guest Wi-Fi and separate VLANs are built to block precisely this.
  3. The server is not running, or the machine is asleep.
  4. A firewall is closed on 8807.
  5. The server took longer than the tweak's 45-second timeout — possible on a very slow machine with a large model on a cold start.

The other stock sentences tell you which half spoke, which is worth knowing:

SentenceSpoken byMeaning
“Sorry, I couldn’t reach the server.”device The POST failed outright.
“Sorry, I didn’t catch that.”either The device says it when the reply carried no spoken line; the server says it when the transcript came back empty. The logs tell you which.
“Sorry, I didn’t receive any audio.”server The request arrived with no audio part.
“Sorry, I ran into a problem handling that.”server The server threw an exception. [mynah] ERROR: in its log has the detail.

Siri answers out loud, but no card is drawn

Three causes, in the order worth checking:

  1. That card's switch is off. Settings → iOS 6 Siri Remastered → Cards. The device log gives it away: a flux reply line saying cards=1 followed by delivered reply … (0 card(s)) is exactly this. Remember the athlete card is gated by the Sports switch.
  2. The data source needs a key it does not have. Movies is the only card in this position. curl http://<server-ip>:8807/config reports "tmdb_api_key": "unset" if that is the answer.
  3. The server correctly returned no card. Conversation, greetings, an honest “no results”, a cuisine with nothing nearby, a sport that is not covered — all of these have nothing to draw. curl "http://localhost:8807/debug?q=…" settles it: an empty cards array means the server made that choice and the device is behaving correctly.

Posters, logos and headshots come through blank

Work through it in this order:

  1. Paste one of the image addresses into a browser on another computer — they look like http://<server-ip>:8807/img/3f2a….jpg, forty hex characters. If it does not load there either, this is the reachability problem above, not an image problem.
  2. Look at the host inside that address. If it is an old IP, a Docker-internal name or localhost, the automatic detection has been overridden — set PUBLIC_BASE=http://<server-ip>:8807 in .env and docker compose up -d.
  3. Check the server log. img host refused: means the upstream host is not on the allowlist; img proxy failed: or stage failed: means the download itself failed.
  4. Check the device log. photo not plain http -> dropped means the server handed over an https address, which the tweak refuses on purpose — see section 05.
  5. Give a brand-new image one repeat. The first fetch is a download and a resize; every one after it is a cache hit.

The first question takes forever, then they are all fine

Two models load lazily. The language model is read into memory by Ollama on first use, and the speech model unloads itself after WHISPER_TTL seconds of quiet — 300 by default — and reloads on the next question. The first request after a start, or after a lull, pays for both. Ten to sixty seconds is normal and is not a fault.

If it never gets faster, the model does not fit in memory and the machine is swapping, which turns seconds into minutes. On Linux, watch free -h while a question is being answered: if swap is climbing, move down a model size, set MYNAH_MODEL, and docker compose up -d.

The Settings pane is blank, missing, or will not open

Settings changes seem to have no effect

assistantd is still running with the values it read when it started. killall assistantd over SSH, or wait for it to be restarted on demand. Do not respring — there is nothing of this tweak in SpringBoard. See section 02.

If the change was to Model or an API key on the device, it will not take effect at any point: those are never transmitted. Set them in the server's .env and docker compose up -d. See section 04.

Section 08When a card takes SpringBoard down

This is the worst thing that can happen, and it is entirely survivable. Nothing is bricked, nothing is lost, and no data is at risk.

The cards are drawn by Apple's card code, which lives in SpringBoard. The tweak does not run there — but the objects it builds are handed across, and a malformed one can crash the process that draws it. When SpringBoard crashes repeatedly, Substrate steps in and boots the device into safe mode: SpringBoard comes up with no tweaks loaded at all, a banner says so, and the device is otherwise completely usable.

Why the switches are per-card

Each of the six card types has its own switch in Settings, and that is the reason they are six switches rather than one toggle. If a card misbehaves on your firmware, or with one particular question, you turn that one off and everything else carries on working. It is meant to be the fix, not a preference — one bad card must never mean an unusable device.

What to do

  1. Get out of safe mode first. Tweaks are disabled in safe mode, and PreferenceLoader is a tweak — so the tweak's row will not be in Settings while you are still in it. Respring out: tap the safe-mode banner, or from a computer, ssh root@<device-ip> then killall SpringBoard.
  2. Turn that card off immediately, before asking anything of the same kind again: Settings → iOS 6 Siri Remastered → Cards. Then killall assistantd so the change is picked up for certain.
  3. If you cannot get to Settings, or it crashes again before you can, disable the whole tweak from a computer:
    # on the device, over SSH
    mv /Library/MobileSubstrate/DynamicLibraries/SiriRemastered.dylib /var/root/
    killall assistantd
    Siri reverts to stock — which is to say silent — iOS 6 Siri, the device is entirely normal, and putting the file back is one mv whenever you want it again. The .plist beside it can stay: with no library to point at, Substrate loads nothing.
  4. If you have no computer at all, use iFile on the device to move that same file aside, or simply uninstall the package in Cydia.

The mildest version of all of this, and the right first move if the device is usable: Settings → iOS 6 Siri Remastered → Enabled, off. Every hook then calls straight through to Apple's original and the tweak is transparent, without anything being removed.

If you do hit this, it is worth reporting. The server's [mynah] log records the intent and the card it built, and the device's [SiriRemastered] log records what was delivered immediately before the crash — between them they identify exactly which card and which question did it.

Section 09Removing it cleanly

In Cydia: Installed → iOS 6 Siri Remastered → Modify → Remove, then respring when it offers. That takes away all eight installed files — the library and its filter, the preference bundle, and the PreferenceLoader entry.

One thing is left behind, deliberately:

/var/mobile/Library/Preferences/com.aditya.ios6siriremastered.plist

That is your server address, location, units and card switches, kept so that reinstalling picks up exactly where you left off. Delete it by hand if you want a genuinely clean slate:

rm /var/mobile/Library/Preferences/com.aditya.ios6siriremastered.plist

MobileSubstrate and PreferenceLoader stay, because other tweaks on the device use them. Removing MobileSubstrate is not something to do casually on a jailbroken device.

Nothing on the server is touched by uninstalling on the device. To take that down too, in the server folder on the server machine:

docker compose down          # stop the containers
docker compose down -v       # and throw away the speech model and image cache

Then delete the folder. Ollama and its models are separate again, and ollama rm <model> reclaims that disk space.

← Back to the setup guide What iOS 6 Siri Remastered does
Adi's Repohttp://repo.theadipost.com/
Everything on this page is documented from the source it describes: the tweak, the preference bundle and the server that ships in ios6-siri-server.tar.gz. The server bundle also carries docs/SERVER-SETUP.md, docs/API-KEYS.md and docs/TROUBLESHOOTING.md.
Free, with no ads and nothing phoning home. If it earned a coffee: venmo.com/u/Aditya-Sreedhar