How it is built, and what leaves your phone.
The promise this app makes is small and specific: your goals, the situations you describe, every practice and every debrief stay on your device, and the only thing that ever goes out is the AI call you set up yourself. Here is the shape that makes that true, and where to check it.
The edge of the phone
Everything the app holds, and whether it crosses the edge of the phone.
Stays on the phone
- Your goals Rows in a database file in the app’s private storage. Delete the app and they are gone with it.
- The situations you describe Where it happens and who is usually there, in your words, stored as you wrote them. Nothing about a real person is uploaded or looked up anywhere — the app never asks who a real person is, so there is nothing to look up.
- Your real conversations The debrief you write after the real thing is never sent anywhere and never scored.
- Your voice Speech is turned into text on the phone itself, by a model that runs on its processor. The audio is never written to storage.
- Your scorecards Six rows and two notes per practice, kept locally so the next practice knows which row to make room for.
- Your provider key Encrypted on the device, readable only by the app, never returned by the app’s own interface — the settings screen shows a masked fingerprint, not the key.
Leaves, once, when you practise
- One practice turn The text of the practice and the prompt around it go to the provider you chose, with your key, at the moment you speak. That is the whole of the outbound traffic.
There is no server of ours in this picture, because there is not one. The engine binds to your device’s own loopback address, and a request to any host but your provider’s fails before it is even looked up.
One process, one device
The app is a Rust engine and a web screen in a single process on your phone. The screen talks to the engine over your device’s own loopback address — the same one that never leaves the handset — and the engine holds everything: the programme, the database, the encrypted key, the speech.
That is an unusual shape for a phone app, and it is the whole reason there is nothing to breach. There is no account, no user record, and no authentication path anywhere in the engine, because there is nothing to identify you with. Nobody can reset anything for you. Your data does not follow you to a new phone unless you export it and carry it there yourself.
The one way out is a list, not a promise
The engine holds an allowlist of hosts it may reach, and it is built from the provider you actually configured — not from every provider the app knows about. An install set up for one company cannot open a connection to the other, and a request to anything else fails before the address is even resolved.
The tests assert the refusals as well as the permissions: the other supported provider, this website, and a set of well-known analytics hosts are all checked and all denied. That file and those tests are in the public source; they are the claim.
- Allowed
- The API of the one AI provider whose key you pasted.
- Denied
- Everything else, including us. There is no analytics SDK, no crash reporter and no metrics client — not switched off, absent.
- Checked by
- A build that greps the dependency locks for known analytics and crash-reporting packages and fails if one appears.
Your key, your bill, no middleman
You bring a key from your own AI provider and pay that provider directly at their rates. The app adds nothing on top, takes no cut, and never sees your card. Setting up finishes without a key; it is asked for once, in place, the first time the app actually needs the model, and it tells you what a practice costs at those rates before you spend anything. A running local tally keeps the number from ever being a surprise.
The key is encrypted on the device with a key file only the app can read. No part of the app’s own interface will hand it back — the settings screen shows a masked fingerprint so you can tell which key is loaded without revealing it. Remove it and the file goes with it.
Asking someone to paste a key into an app is asking for trust. Open source is how that is repaid: you can read the exact call, the exact prompt and the exact host, or ask someone who reads code to do it for you.
Speech happens on the phone
Your microphone is on during a practice and at no other time. It is never on during the real conversation, and it never records anybody else.
What you say is turned into text by a speech model running on the phone’s own processor — the multilingual base model, downloaded once inside the app. Your audio is not uploaded for transcription, and it is not written to storage: it exists in memory for as long as it takes to turn it into words, and then it does not exist.
The rules are code, not instructions to a model
The parts that have to be true are not asked of the AI. They are ordinary program logic with ordinary tests, in a layer that has no network access at all.
A practice, however well it goes, never moves a goal — that is a rule in the programme code with a test on it, not a line in a prompt hoping the model behaves. The same layer holds the six skills and their citations, the questionnaires and their sources, and the list of places to get help with the date each entry was last checked.
- Grounding
- What the person in a practice is told about your situation must be in your own words: a verifier checks every claim against what you wrote and flags anything it cannot find. The person themselves is made up on purpose, and new each time.
- Crisis words
- Detected on the device, before anything is sent anywhere. A test asserts that when it fires, no call to the provider is made at all.
- The programme
- Goals, real conversations and when the programme is met are engine state with route tests. It ends when your goals are met, and then it suggests you delete it.
The model is a stand-in, not the product
A language model is very good at one job here: answering in character as someone who could be in the room you described, so you can practise on something that talks back. It is trusted with that and nothing else. It does not hold your progress, decide what counts, or remember you between practices, because it is not where any of that lives.
Every prompt the app sends is a file in the repository, and each one has a golden test — change the wording and the test shows you exactly what changed. The stand-in answers in character and never coaches, grades, remembers other practices or chats outside a practice. That is enforced, not requested.
Bringing your own key is how it works today. A model small enough to run on the phone with no key at all is the direction we want to go, and the layer that talks to providers is a single crate precisely so that swap is a swap.
Built for the phone you already have
The reference device is a mid-range Android phone from a few years ago, not this year’s flagship. Android 8 and newer; the iPhone version runs on the same code.
Accessibility is a gate on every change, not a follow-up: contrast, target sizes, dynamic type, both themes, reduced motion and a screen-reader path all ship together, and a change that breaks one does not merge. Every state is designed — empty, loading, error, degraded, no key, first run — because a shy person meeting an error screen at 11pm deserves a sentence that makes sense.
When something does fail, it degrades honestly: the app says what happened in one plain sentence and keeps working. A dead key stops the practice, never the real conversation.
Two languages, all the way through
English and German are both first class — the interface, the lessons, the questionnaires, the crisis words and the help-line entries, not a translated shell over English content. Every string is keyed, and a check refuses a build where the two sets disagree.
Each conversation has its own language, so you can rehearse a German conversation while reading English screens.
What each piece is, and why it is that one
No part of this is exotic. It was chosen so the interesting properties — one process, one host, no server — are cheap to keep true.
- Rust engine
- The programme, the database, the key store, the speech. Compiled into the app on the phone; also runs as a plain binary on a desktop, same code, same routes.
- SQLite
- One database file in the app’s private storage. Your export is a copy of your own words; deleting the app deletes the lot.
- React and TypeScript
- The screens, served to the WebView from loopback. The types the screen uses are generated from the engine’s own types, so the two cannot drift.
- Tauri
- The shell that makes it an app in the store: the WebView, the microphone permission, and the engine started in-process beside it.
- Speech in
- A whisper model on the phone’s processor. Microphone capture at 16 kHz in the browser layer, straight into the engine.
- The AI call
- One crate is the only thing in the codebase that knows a provider exists. Everything else, including the no-key path, goes through the same call sites.
- No key at all
- A built-in stand-in provider answers from templates with no network, so the app is honest and usable while you decide whether to paste a key.
Do not take our word for it
The source is public under the Mozilla Public License 2.0. Clone it, read it, build it yourself, or point it at a network monitor and watch what it does and does not do.
git clone https://github.com/defoAI/getspeaking - PRIVACY.md
- Each claim on this page, mapped to the file and the test that enforces it.
- ARCHITECTURE.md
- The shape above, in the detail a contributor needs.
- allowlist.rs
- The one egress, and the tests that assert what is refused.
- prompts.rs
- Every word the app sends to a model, with its golden test.
- skills.rs
- The six skills in both languages, each carrying its sources.
Bug reports and questions belong in the public tracker on the repository, where the answer is public too.
Read the code, or just practise the conversation.
Free, no account, and nothing above changes whichever you do.