Peace
An expense tracker that keeps its mouth shut. Every record lives in one SQLite file on your phone — no account, no server, no sync, and nothing on the network unless you ask for it.
Peace is built around the month, and around the thing you do fifty times a month: type an amount.
The pickers sit at the top of the record screen and a calculator keypad at the
bottom, so the bottom-right key walks the whole record — account, category,
save — and a coffee takes four taps with one thumb. = finishes a sum first if
you were still adding things up, and the key’s label always says which of the
three it is about to do. It works in split-screen, with a bank notification open
beside it, because that is where records actually get logged.
Everything else exists to make the ledger tell the truth afterwards. Transfers appear once instead of twice. A refund nets against the thing it reversed rather than inflating both sides of the month. A credit card reads as money owed rather than an emptied wallet. The percentages on the analysis ring add up to exactly 100. Search shows the total of every match, not of the rows that fit on screen.
What it refuses to do
What an app declines is as much a description of it as what it ships.
- No sync. Sync means a server, an account, and a copy of your spending somewhere you do not control.
- No budget carry-over. An unspent limit rolling forward is a limit that gets easier every time you fail to use it. What carries between months is money, and the header does that instead.
- No single cross-currency total. Valuing a whole balance needs today’s rate, and the only honest rates here belong to past records — each one stored against the record that used it, so a purchase made when the dollar was fifty pounds stays at fifty forever.
- No settings that do nothing. A control for a preference nothing reads is a switch that silently lies, so each row ships in the same change as the code that honours it.
The whole app makes four outbound calls and there are no others: an exchange rate when you tap for one, a receipt or bank message sent to Gemini if you have supplied your own key, Drive if you have connected it, and a once-a-day check for a newer build. Two of the four are off until you switch them on.
It is an APK you sideload rather than a store listing, and that is the price of reading bank alerts without asking Google’s permission to keep the feature.
Releases
What’s new
- A long note now scrolls wherever you drag it, including in the space around the photos, tags and buttons at its foot.
Changes
- fix(record): a drag anywhere in a long note scrolls it (1.37.3)
What’s new
- A long note now scrolls inside the notes box, so the account and category stay where they are while you type.
- Transfers show their note in the list, next to the accounts the money moved between.
Changes
- fix(record): a long note scrolls under its bar; transfers show their note (1.37.2)
What’s new
- Peace no longer slows to a crawl when it opens on a day a backup is due. Backups are now made in the background, so the app stays quick while one runs.
Changes
- fix(backup): pack and seal natively so a due backup cannot stall the app (1.37.1)
What’s new
- You can now share a receipt photo. Tap it to open it full screen, then tap Share at the bottom to send it to any app, like WhatsApp or email.
Changes
- docs(whats-new): Share is at the bottom now
- test(e2e): scroll to Backup & export before tapping it
- feat(receipts): Close and Share at the viewer’s foot, in theme colours
- feat(receipts): share a photo from the full-screen viewer (1.37.0)
Changes
- docs(store): voice shot while it reads; Budgets back in place of Accounts
- docs(store): fresh screenshots with voice and Penny, widgets with the mic
- feat(store): voice and Penny in the listing; the mic hint is just “Say it your way.” (1.36.1)
What’s new
- You can now speak a record instead of typing it — in Arabic, English or both. Tap the mic on a new record, use the new Speak shortcut or widget button, or tap the mic in Penny to ask her a question out loud.
- Voice uses your Gemini key. Peace asks for the microphone the first time you tap it, listens only while the mic is open, and never keeps the recording.
Changes
- chore(voice): allow the microphone, and declare audio in Data safety
- fix(voice): silence is never sent, and a model that heard nothing says so
- fix(voice): a permission check no longer cancels the mic it opens
- feat(voice): speak a record, or a question to Penny (1.36.0)
What’s new
- Peace now opens in your theme: light for Paper and Mist, dark for Ledger and Graphite, instead of always dark. On Android 12 and later, a new theme shows from the next time you open the app.
- The Analysis chart is bigger. Tap or hold any part of it to see which category it is and its share of the month.
Changes
- feat(theme): the splash opens in the chosen theme (1.35.0)
- docs: refresh the screenshots for the new Analysis screen
What’s new
- The Analysis chart is bigger. Tap or hold any part of it to see which category it is and its share of the month.
Changes
- feat(analysis): a bigger ring you can touch (1.34.0)
What’s new
- Analysis now breaks each category down by its sub-categories, in the list and as an outer ring on the chart. Every category gets its own row too, instead of the smaller ones being folded into “Other”.
Changes
- feat(analysis): break each category down by its sub-categories (1.33.0)
What’s new
- Fixed a rare freeze when Peace opened while a Google Drive backup was due. If Peace ever stops responding again, About now lists when and what it was busy with, so you can share it with us.
Changes
- fix(backup): stop the Drive catch-up freezing the app at launch (1.32.1)
What’s new
- The keypad’s next key now shows where it goes: the account, then the category, then a check to save.
- After an update, Peace now shows what changed — like this. Find it again any time in About.
Changes
- feat(record): the next key shows what it opens — account, category, save (1.32.0)
- site: bank messages get their own feature, from a real frame of the promo clip
- ci(play): also release each upload to internal testing at once
What’s new
- After an update, Peace now shows what changed — like this. Find it again any time in About.
Changes
- feat: What’s new after an update, from one release-notes file (1.31.0)
Changes
- fix(setup): Continue on the AI step when a key is already saved (1.30.1)
Changes
- feat(setup): choose a theme during onboarding, by looking (1.30.0)
Changes
- feat: read PDFs and text files into a record, like receipt photos (1.29.0)
- docs(store): widgets on a home screen — store screenshot 3 and a site section, from real captures
Changes
- fix: centre the app in a 640dp column on tablets and unfolded foldables (1.28.1)
- docs: listing and site name widgets, shortcuts, the in-app camera, import, lock and themes; Arabic and Peace Cloud deferred
Changes
- feat(widgets): Balance is 4×1 by default; taller, its accounts fill the space
- feat(widgets): Budget and Balance as separate widgets; Balance lists accounts when stretched
- feat: home-screen widgets — This month and Quick add (1.28.0)
- fix(budgets): a set-aside limit leaves the spent total too
- docs(screenshots): retake Penny’s three in Ledger’s red; fix the script’s two stale waits
Changes
- feat(shortcuts): Penny takes Income’s launcher slot (1.27.0)
Changes
- ci(play): upload the bundle to a testing track as a draft, keyless via WIF
- build: R8 shrinking and obfuscation in release builds (1.26.1)
Changes
- feat(record): the notes field becomes the camera; one press attaches (1.26.0)
Changes
- docs: shortcuts and accessibility in AGENTS.md and the release plan
- feat(a11y): spoken keypad, one-sentence chart rows, named swatches, large-text density
- feat: launcher shortcuts for Expense, Income and Receipt (1.25.0)
- docs(release-plan): the OAuth consent screen is in production
- docs(release-plan): Play App Signing, Drive for play, Data safety and the internal track done
- docs(screenshots): retake with Ledger’s red (1.24.0)
Changes
- feat(penny): Your rules, appended to her system prompt (1.24.0)
- fix(setup): the accounts step shows and sets today’s balance, not the opening one
- fix(setup): fade the step emblem in instead of springing it
- fix(theme): Ledger’s expense back to the salmon red
- docs(store): the filled-in Data safety form, importable into Play Console
Changes
- fix(site): generate the theme table before typechecking
- feat(themes): a grid of live previews, and a themes section on the website
- fix(restore): name the backup file in the confirmation, not its document id
- feat(themes): Ledger, Graphite, Paper and Mist, or match the phone (1.23.0)
- chore(site): drop a generated file committed by mistake
- feat(site): /delete/ — the page Play’s Data safety form links to
Changes
- feat(import): bring records in from a CSV in Peace’s own format
Changes
- feat(lock): app lock, with the phone’s own fingerprint or PIN
- feat(site): the sitemap finds its own pages, with dates
- feat(site): /move/ walks the GitHub version over to Play
Changes
- fix(settings): the index calls it Money & months, like its page
- docs(agents): components read the period label through usePeriodLabel
- fix(periods): labels follow the start day under the React Compiler
- feat(periods): months that start on payday, and a first day of the week
Changes
- feat(settings): “Your rules” is always open, and saves as you type
- fix: setup’s bank step notices access granted; Penny leaves the side menu
- fix(settings): one line above Receipts’ rules, Bank follows the disclosure back, Settings near About
- fix(ai): no key means every AI switch is off and muted
- feat(settings): a dropdown for the model, and Receipts and Bank switches like Penny’s
- feat(settings): AI on the Settings page with a master switch; Recording joins keypad and default account
- feat(settings): AI is one hub — the key, then receipts, bank messages and Penny
- feat(settings): an index of sections, each a page that says what it is for
Changes
- feat: empty states that teach, and About links to the site and the source
- feat(site): /store/ is a page of the listing’s graphics, not a 404
Changes
- feat(store): Penny’s screenshots in dollars too
- feat(store): the Play listing, neutral screenshots, and both put to work
Changes
- style(setup): restore the house formatting the key-check commit overwrote
- fix(setup): check a Gemini key before saving it, and show errors on the field
- feat(setup): onboarding — welcome, seven skippable steps, and the bank disclosure
- docs: update effective date and support email in privacy policy
- ci(play): the shared build makes a signed AAB for flavor play, on a manual workflow
Changes
- docs(permissions): point at the policy’s home in site/content
- fix(android): request 9 permissions instead of 33, and fail the build on an unapproved one
- chore(seed): Telephone becomes Phone; the prompts and defaults are reviewed for regional assumptions
- feat(site): social and meta tags, generated social cards, and the taglines
- feat(site): peace.merope.dev — a static Next.js site on GitHub Pages
- docs(site): privacy policy and Data safety answers for peace.merope.dev
- docs(release-plan): tick off what 1.15–1.16 shipped, and pin the disclosure to before the first upload
- test(e2e): the reminders flow scrolls to each row instead of assuming it is on screen
Changes
- fix(penny): a key saved in Settings reaches Penny’s card at once
Changes
- fix(ui): sheets and snackbars clear the three-button navigation bar
- ci(e2e): run Maestro from one script line, or the workflow never reaches a flow
- test(e2e): one record lifecycle flow instead of three that each logged it first
- test: share DB fixtures, drop tests that only re-proved another, and stop sleeping
Changes
- feat(build): oss and play flavors, and the app moves to dev.merope.peace
Changes
- chore(copy): examples and hints that do not assume one country’s banks
Changes
- feat(keypad): choose 1-2-3 or 7-8-9 on top, and which side the operators go
- docs: Play Store release plan
Changes
- feat(assistant): replies render as one native text view, so a selection spans the whole reply
- fix(assistant): a horizontal rule is a paragraph break, and italics around a figure lose their asterisks
- refactor(assistant): one general query instead of a special tool, and no Copy button
- feat(assistant): fewer steps, no step limit, and replies you can copy
Changes
- feat(assistant): Penny can refund a purchase and reverse a transfer
Changes
- docs: a row of Penny in the README, and npm run shots:penny to regenerate it
- feat(assistant): Penny’s coin is the cursor, and the label says what is happening now
- test(assistant): live flows return to Penny before attaching, and back out of the folder picker
- docs: Penny in the features, and in the list of everything that talks to Google
- feat(assistant): the assistant is called Penny
- feat(assistant): attach receipts and invoices, save reports, richer reports, retries
- feat(assistant): replies stream in, the dots say what is happening, and a real new-chat icon
- chore: npm run demo:ledger — a year of invented data, restorable as a backup
- fix(assistant): an expired card does not leave the composer asking for an answer
- fix(assistant): what the device runs showed, and E2E flows with and without a key
- test(assistant): a live suite against the real Gemini API, skipped without a key
- feat(assistant): the chat screen, its charts, cards and settings
- feat(assistant): the engine — tools over the ledger, cited figures, approval-gated writes
A reminder names your verb, not the model’s.
Changes
- fix: name the person’s verb, not the model’s
Ask what the day cost, and hear what is still waiting.
Changes
- feat: ask what the day cost, and say what is still waiting
An error says what to do about it rather than what cannot happen.
Changes
- fix: say what to do, not what cannot happen
One long press, one archive, one way to delete — and a search that keeps your place when a deletion moves you.
Changes
- feat: hold a row in search, say why a delete sent you there, and ask about updates
- test: there is no form to cancel any more
- test: anchor the category scrolls instead of guessing the offset
- fix: say it where the tap was, and lift the FAB clear of it
- feat: one long press, one archive, one way to delete
Archiving is finished: categories go away and return, an archived account keeps its money, and what is put away can be deleted once nothing points at it.
Changes
- chore: 1.9.0 — the rest of the Archived section
- test: reach a tab from Settings, and a button from its card
- ci: run the flows on a runner when there is no emulator to hand
- test: check every flow’s testIDs without a device
- feat: delete what has been put away, once nothing points at it
- fix: an archived account still holds its money
- feat: put categories away, and bring any of the three back
An archived account can come back.
Changes
- feat: bring an archived account back
A backup from any schema this app has ever had restores cleanly.
Changes
- test: restore a backup from every schema this app has had
- fix: an old backup is not a stranger
The Now card explains itself and splits by time as well as by account, and a loan stops being filed as a card.
Added
- Now explains itself. The header’s running position reconciles exactly with the Accounts total, and the card now shows the working rather than asking you to trust the number.
- The breakdown splits by time as well as by account.
Fixed
- A loan is not a credit card. It was being drawn as one, with a credit limit it does not have.
Tags — the axis categories cannot be. Many per record, crossing categories, and archivable when the project they name is over.
Added
- Tags. A category answers “what kind of spending was this” and can only answer once. A tag answers “what was this for”, as many times as it needs to, across categories — so “where did the kitchen money go” is still a ring, and the tag can be archived when the kitchen is finished.
Upcoming payments lifted above the ledger, where a thing you have not paid yet belongs.
Changed
- Upcoming occurrences sit above the records list rather than below it. A payment you have not made is a decision waiting, not history.
- Nine screenshots in the README, all generated by a flow that asserts the totals it is about to photograph — so a wrong screen fails the build rather than being quietly captured.
Reverse a transfer, let a refund say what it refunds, and hide every amount behind one tap in the header.
Added
- One tap hides every amount. The eye in the header masks each figure on every screen, for reading your ledger with someone beside you. It persists, so the eye stays in the header as the way back. Shoulder privacy only — it does not touch screenshots or the recents thumbnail.
- Reversing a transfer, and a refund that names the purchase it undid.
Fixed
- Search finds a transfer by where it landed, rather than by a category a transfer cannot have.
- A reading fills the note in; it no longer overwrites what you had typed.
- Pickers open on the current selection instead of at the top.
- The update-balance sheet and the budget editor both sat under the keyboard.
Eight fixes to the reader after a week of real use — a cash withdrawal is a transfer, not an expense — and a relicence to GPL-3.0.
Fixed
- A withdrawal is a transfer. Cash out of a machine has not been spent; it is spent later, one purchase at a time. Filing it as an expense counted it twice and left the cash account permanently empty. Both halves looked individually plausible, which is why it survived a glance.
- Bank messages get a category. The prompt never asked for one, so every bank record arrived uncategorised — which read as the model declining to guess, and was the app never putting the question.
- The currency the message named is the currency entered. The screen took
its currency from the account and nothing else, so a correctly-read
USD 50.00was saved as fifty pounds. Not displayed wrong — saved wrong. - The message survives a failed reading. The app had the bank’s own words, showed them in the grey row, and threw them away at the one moment they became permanent.
Changed
- Relicensed under GPL-3.0, so anything distributed from this comes back rather than disappearing into a closed fork. The name and the icon stay reserved.
Bank notifications read into records for approval, editable prompts, and a Settings screen that holds your rules rather than the app’s wiring.
Added
- Bank alerts captured and offered as records to approve, never written
behind your back. Android hands over the notification your messaging app
already showed — the same text you read off a lock screen. No
READ_SMS, no conversation history, and the sender list starts empty. - The finance half of each prompt is yours to edit, so “the card ending 0042 is Kenana” resolves against your real accounts.
Changed
- Captured messages join the records list instead of living on a page of their own.
- Two permissions the app never used are no longer declared.
Fixed
- A busy model no longer burns the message it failed to read.
- The app says when messages are waiting on a key you have not supplied.
- Bank alerts captured and offered as records to approve, never written
behind your back. Android hands over the notification your messaging app
already showed — the same text you read off a lock screen. No
Daily totals in the records list, and a settings row deleted rather than wired to nothing.
Added
- A total on each day heading, so the month reads as a sequence of days that each net themselves.
Fixed
- The day heading was clipped by the total sitting beside it.
First light. The whole ledger in one version — keypad entry, budgets, analysis, credit cards, refunds, backups, receipts and recurring payments.
The version stayed at 1.0.0 for seventy-five builds while the app was built, so this is less a release than the shape of the thing when it was first worth installing.
Added
- Recording — a calculator keypad, two-tier categories, transfers written as one atomic pair, refunds that net against the purchase they reverse, and multi-currency with the rate stored per record.
- Making sense of it — records grouped by day and netted, a category ring with a ranked breakdown, budgets suggested from what you actually spend, free-text search with a total, and balances derived from the ledger rather than stored.
- Credit cards as money owed rather than an emptied wallet, with per-card fee profiles and balance corrections that move your position without counting as spending.
- Keeping it — a backup that is a plain zip you can open anywhere, an undo for the last restore, optional Drive backup sealed with a passphrase, and a CSV export that carries both legs of a transfer.
- Receipts read by Gemini, with your own key, off until you supply one.
- Recurring payments and portfolio rebalancing, the latter deliberately not wired into the ledger — it never tells you to sell.