split-free.openapps.xyz

Source

This app’s code and revision history are public. Download a copy or explore the files below.

Public
The app’s code and revision history are public.
Owned app · rev 9ed962174401
Run it yourself
Take the whole tree and run it on your own machine. The download needs no account. Cloning needs a sign-in.
Download .zip
bounded clone 20ace674a35b849ffda63b30
A copy you download is not bounded. The guarantees this app runs under - declared egress, proven invariants, writes that fail closed - live in the runtime serving this page, not in the files. What you get is auditable source you can read and run, with no runtime guarantees attached.
← All files
AGENTS.md
# Split

Split is a free expense splitter for groups, and a free alternative to Splitwise. It is an OpenApp in the OpenApps free apps store (https://free-apps.openapps.xyz/), owned by the OpenApps team.

## What it promises

- Free, with no limit on groups or expenses, no ads and no paid tier. Never add a cap, an upsell or tracking.
- No sign-up. Every visitor is a guest account created in the browser.
- Anyone with a group's link can see and change the group. The random group id is the link's secret.
- AI assistants can do everything a person can through the public API (`functions/api.ts`), documented in `public/llms.txt` and `public/openapi.json`. Keep both true whenever the API changes, and keep `public/index.md` in step with the landing page.

## How it is built

- `index.html` is the static landing page that search engines and AI crawlers read. Keep its copy, FAQ and JSON-LD in sync with what the app does.
- `src/` is the React app. `/` mounts the start column (the groups this browser opened, then the create form) into the landing; `/g/<groupId>` hides the landing and shows the group. `?add=1&title=&amount=` and `?settle=1` on a group link open a filled-in sheet, for links assistants send.
- `src/lib/mine.ts` is what a browser remembers in localStorage: the groups it opened (`split:groups`) and which person it is in each (`split:me:<groupId>`). `split:new:<groupId>` marks a group this browser just created, for the "send the link" notice. The guest session is the client library's own.
- The shared look is `public/kit.css` (dialogs, menus, skeletons, empty and error states, the phone action bar). Use its pieces before adding styles to `src/styles.css`.
- `functions/lib/split.ts` holds the money math for both the app and the API. Amounts are integers in the currency's minor unit, splits always add up exactly, and balances always sum to zero.
- `functions/lib/config.ts` holds the app id and the site URL used in links.
- `policy.json` holds the data rules. Reads need a join record (`groups/<id>/joins/<userId>`), and creating that record needs only the group id. That is what makes the link the permission without letting anyone list groups.

## Working on it

`npm install && npm run build` typechecks and builds `dist/`. Ship changes through previews and releases as your runtime instructions describe; the app is an OpenApp, so nobody deploys it directly.

Check a change by creating a group, adding expenses with each split mode, recording a payment, deleting and undoing, and calling the API with curl. Check phones at 390px wide: the action bar, sheets and the "Which one are you?" step.

## Voice

Plain words, short sentences, no jargon, no em dashes. Say what happens, not how clever it is.

Change history

Publish quality pass from owner chat
9ed9621744 · 5 hours ago
Bind agent address in policy constants
7effc1cbbd · 5 hours ago
Quality pass: cleaner group page, phone polish, fuller API, sourced comparison
5345219781 · 5 hours ago
Bounded source sync
277fb9ad96 · 1 day ago
Bounded source sync
e944552325 · 1 day ago