The hardest thing to explain about splitscreen is also the whole point of it. The people in a room do not need an account anywhere. No Anthropic key, no OpenAI billing page, no card of their own. One person pays and everybody else just asks.
What keeps that from being frightening is the fence. When Marguerite turns cover on for a room she sets a limit per person per day, and a limit for the whole room per day sits behind it. Both are checked before the request is made rather than after the reply arrives, so a room that runs out says so with the budget still intact and nobody is billed for finding out.
The transcript below is that room. Rafi and Dee hold nothing at all, and between them they ask Claude, Gemini and GPT. Watch the strip above the messages: their two daily limits move separately, and the room’s budget for the day moves on every reply. The receipt under each one names Marguerite, because hers is the balance that was charged.
Marguerite owns this room and is on the Squad plan. Rafi and Dee were invited by link and hold no keys and no credits.
A curated transcript, written by us to show what the product does - not a recording of a session, not a live room, and not real people. The prices are the ordinary rates on what each AI can do.
| after | Rafi, today | Dee, today | This room, today |
|---|---|---|---|
| Marguerite opens the room | $0.5000 | $0.5000 | $2.0000 |
| Rafi asks Claude | $0.4909 | $0.5000 | $1.9909 |
| Dee asks Gemini | $0.4909 | $0.4791 | $1.9700 |
| Rafi asks GPT | $0.4758 | $0.4791 | $1.9549 |
Claude - the field app queues writes while it is offline and replays them on reconnect. Two engineers on one job now produce duplicate visit records about once a week. The queue has a client-generated id on every entry. Where would you look first?
A client-generated id only prevents duplicates if the server treats it as the primary key of the write, and the usual failure is that it does not.
Check what the replay endpoint does with the id. If it inserts a new row and stores the client id in a column beside it, then two devices replaying the same visit produce two rows with two different primary keys and one matching client id, which is exactly what you are seeing once a week. The fix is a unique constraint on that column and an upsert rather than an insert.
The second place to look is what the client does after a successful replay. If it clears the queue entry on the response rather than on an acknowledgement it has actually persisted, a reconnect during the response window replays the same entry again. That produces the same symptom from a different cause, and the unique constraint fixes it too.
$0.0091 · covered by Marguerite
Gemini - before we add a unique constraint on 6 million existing rows, go and check what the current advice is for adding one without locking the table on Postgres.
searched the web (1)
postgres add unique constraint without locking create index concurrently
The recommended shape is two statements rather than one.
First CREATE UNIQUE INDEX CONCURRENTLY on the column. That builds the index without taking a lock that blocks writes, at the cost of two passes over the table and a build that can fail part way and leave an invalid index behind, which you then drop and retry.
Then ALTER TABLE ... ADD CONSTRAINT ... UNIQUE USING INDEX, which adopts the index you already built instead of building a second one. That statement does take a brief exclusive lock, but it is a catalogue update rather than a scan, so it is short.
One thing to do before either: find the duplicates you already have. The concurrent build will fail at the end if any exist, after doing all of the work.
$0.0209 · covered by Marguerite
tools: $0.01 · 1 search
GPT - write me the query that finds the existing duplicate visit records, grouped so I can see which jobs they came from.
This gives you one row per duplicated client id, with the job it belongs to and how many copies exist:
select client_entry_id,
min(job_id) as job_id,
count(*) as copies,
min(created_at) as first_seen,
max(created_at) as last_seen
from visit_records
where client_entry_id is not null
group by client_entry_id
having count(*) > 1
order by copies desc, last_seen desc;
Two notes before you run it. min(job_id) assumes the copies share a job; if they do not, that assumption is itself a finding, so run it once with count(distinct job_id) in place of min(job_id) and see whether any row comes back above 1.
And rows where client_entry_id is null are a separate problem. Those came from a client old enough not to have sent one, and no unique constraint will help them.
$0.0151 · covered by Marguerite
I will run the duplicate query on the replica tonight and put the numbers in here tomorrow. Neither of us has an API key and we just used three different models, which I still find slightly odd.
Rafi asked twice and Dee asked once, and each of them drew down their own daily limit. Neither of them can spend the other’s, which is what makes handing out an invite link a reasonable thing to do.
Every covered reply also comes off the room’s budget for the day. That is the number that caps the whole room whatever the individual limits add up to, and the schema will not let a per-person limit be set above it.
Credit leaving Marguerite’s balance is charged at 20% over what the provider charged us, because she is the one paying and she is on Squad. It is the payer’s plan that sets the margin rather than whether the reply was covered, and every other plan pays 30%.
Bring your own keys or use splitscreen credits, set the budget, and invite the people who have neither. The demo room is a longer transcript if you want one first, and pricing is two paths and a subscription.