Wordship
You choose my word.
I’ll choose yours.
A friend sends you a challenge. You think of a word that might stump them. A few guesses later, there’s something new to compare, laugh about and try again.
I’m building Wordship for those small moments of playing together, with daily puzzles for the time in between.
Play in your browser. Start as a guest; create an account later and your games stay yours.
01 / Deduce
Every guess gives you
something to go on.
Find a five-letter word in six guesses. Each guess tells you which letters fit, which need moving, and which you can leave behind.
Play the shared daily word, keep playing fresh words, or choose words for a friend while they choose yours. You can also challenge each other to the same random word.
- Right place
- Somewhere else
- Not in the word
A friendly rivalry, at your pace.
Share an invite link, or say a five-character room code aloud, for one head-to-head game, even without an account. Signed-in friends can also find each other with friend codes and play challenges across one, three or five rounds. Choose Performance to compare results after every round is played, or Race: when one person finishes, the other gets thirty seconds.
02 / Salvo
First find the word.
Then work it out.
Play a daily board or start a fresh solo hunt. With a friend, you each hide five five-letter words on a ten-by-ten grid and take turns hunting for them. Hits tell you which word you’ve touched, but keep its letters secret.
Find every cell of one word and a timed Deduce challenge opens. Your friend watches you try to solve it. A solution sinks the ship; a missed word still scores the letters you found before the hunt resumes.
01 Find its five cells.
02 Figure out the word.
Six guesses. Three minutes.Your friend watches the attempt.
Behind the play
The same game
on both screens.
A shared puzzle depends on small promises: whose turn it is, what each person can know, and where the game stands when they come back.
The shared result
The server validates guesses and decides when a round ends. Both players’ screens use that saved result, including when their final guesses arrive together.
Protecting unsolved answers
A player can read the progress they need without receiving their unsolved answer. Access to a game and its live updates is limited to its participants.
When the connection fails
If a guess is accepted but the next read fails, the submitted letters stay on the board and further input pauses. Refresh brings back the saved game, so a momentary connection problem does not make a player guess whether their move counted.
Starting as a guest
You can begin without a signup form. Wordship gives the guest a durable player identity and saves their moves. An account with no existing Wordship history can later claim that same player instead of starting over.
Engineering
Game state and access
Two friends on two phones each see a board, but there is one game. It lives in Postgres, and rules in the database decide what each player may write and read. The page sends requests to the app’s server, which works out who is asking. Functions inside the database then check that this player may make the move, take a lock, apply it and return the result.
- Authority
SECURITY DEFINER PL/pgSQL · search_path pinned · client writes revoked · FOR UPDATE; room writes: match, then round · one STABLE snapshot · answers null until complete
A move is a call to a function that runs inside Postgres with its own rights, so a modified page cannot write a game row, a placement or a guess.
How it works
The definer functions that make game moves pin their search path. A move locks its game row before it changes anything, and a room write locks the match before its round, always in that order. When two players move at the same moment, one waits for the other, and the fixed order keeps them from deadlocking. One STABLE function builds the whole authorized game view from a single snapshot. Both players’ answers stay null until the game is complete, so the secret word stays on the server until then.
- Access
row-level security · anon and authenticated revoked · explicit JSON projection · missing and forbidden look alike
Row-level security and restricted writes separate application tables from server-owned records, with the database checking who may read or change game state.
How it works
Tables only the server should touch, such as guest sessions, receipts, budgets and account links, also revoke every privilege from the anonymous and signed-in roles. The read functions return only an explicit JSON projection of the data. A missing game and a game the caller is not in get the same answer, so game ids cannot be probed for existence.
- Live updates
Realtime Broadcast, private channels · RLS on realtime.messages · topic parsed per subscription · send only on own typing channel · RESTRICTIVE beside permissive · guests reconcile over HTTP
The database authorizes each subscription, where policies on realtime.messages parse the topic name and admit only that game’s participants.
How it works
Live updates travel on private Broadcast channels. A client may send only on its own typing channel, and an opponent’s draft becomes visible only once the reader has finished their own solve. Wordship’s permissive policies are paired with restrictive ones, so a broader policy on the same table cannot widen access to a Wordship topic. Guests are not on Broadcast. Their page reconciles over HTTP while it is visible.
- Retries
expected slot number · unique (game, guesser, guess_number) · 64-hex operation key · advisory locks: key, then player · OPERATION_KEY_CONFLICT · replayed: true
If the reply is lost and the client sends the same word for the same slot again, the function returns the row it already committed, without a second write, feedback calculation or broadcast.
How it works
A guess names the slot it expects to fill and is written under the game’s row lock and a unique index on game, guesser and guess number. Only the same word replays, and a different word for a filled slot is refused. Creating a room takes a client-made 64-hex operation key under two advisory locks, one for the key and one for the player, and records a receipt. If the same player retries, they get the same room back, marked as replayed. The same key from a different player is refused with a conflict, so it cannot fetch someone else’s room. Practice guesses, friend-room secrets, Salvo shots and challenge guesses use the same expected-slot pattern.
- Identity
256-bit token, SHA-256 digest stored · HttpOnly, SameSite=Lax, Secure · 365-day expiry, revocable · account to player link table · one atomic claim · erasure core + tombstone
The server mints a 256-bit token and keeps it in a host-only HttpOnly cookie that page scripts cannot read, and Postgres stores only its SHA-256 digest.
How it works
A friend can play from a link without signing up. The server mints a 256-bit token and keeps it in a host-only HttpOnly cookie that page scripts cannot read. Postgres stores only its SHA-256 digest, so the database holds no usable credential. The session expires after 365 days and can be revoked. A player’s lasting identity is a profile kept separate from any sign-in account and joined to it through a private one-to-one link table. Naming a guest and attaching an account is therefore one atomic claim, and it rewrites no game row. Deleting a guest or an account runs the same erasure core. It removes the profile, notifications and every game the player took part in, both seats’ turns included. Opponents’ profiles stay intact. Erasure also writes a digest-only tombstone so a late request cannot recreate an erased guest, and a daily job erases expired guests in bounded batches.
- Abuse
HMAC-SHA256 of the requester IP · INSERT ... ON CONFLICT budget · fails closed without a client IP · 5 symbols, 32-character alphabet · CHECK on the code format · oracle gate
Anonymous room creates and code joins draw on fixed-window budgets kept in Postgres, so the bound holds across cookie resets and concurrent Worker instances.
How it works
Anonymous room creates and code joins draw on fixed-window budgets kept in Postgres and updated by one atomic upsert, so the bound holds across cookie resets and concurrent Worker instances. The bucket key is an HMAC-SHA256 digest of the requester’s address and the operation. The raw address is never the key. The API refuses the request when no trusted client address is present. A spoken room code is 5 symbols from a 32-character alphabet without I, O, 0 or 1, enforced by a CHECK constraint in the database and the same pattern at the API. Replaying a submitted secret word is permitted only in friend rooms where the players chose the words. On Daily and practice games the same path would be an answer-checking oracle, so it is refused there.
- Delivery
forward-only migrations · pg_get_functiondef assertion · Vitest checks · test, typecheck, lint, then build · artifact secret scan before deploy · Cloudflare Workers via OpenNext
The schema has moved through forward-only migrations, and every web push to main runs the Vitest suite, typecheck and lint before a guarded OpenNext build.
How it works
The schema has moved through forward-only migrations. A migration that reworks identity reads the deployed function body with pg_get_functiondef and asserts that each expected fragment appears exactly once. It then rewrites the body around an explicit player and raises if any auth.uid() dependency remains, so drift in production aborts the migration before behaviour can change unnoticed. Every web push to main runs the Vitest suite, typecheck and lint before a guarded OpenNext build. That build refuses a checkout with local env files or server secrets in its environment, scans the compiled Worker for secret names and the client chunks for localhost URLs, and re-runs that scan right before wrangler deploy. Releases are serialized and each is tagged with the commit it came from. The app is served from a Cloudflare Worker on its own domain.
A guess, retried The same player sending the same word for the same slot gets the committed row back
- PageThe guess names the slot it expects to fill.
- PostgresUnder the lock, the game row’s guess count says whether slot 2 is already filled. A unique index on game, guesser and guess number stops a second write to the same slot.
- PostgresThe row is committed, the feedback is calculated and the participants are notified, each exactly once.Committed
- NetworkThe client cannot tell whether the move counted.Reply lost
- PageThe same word, with the same expected slot.
- PostgresThe saved word matches, so the function returns that row without a second write, feedback calculation or broadcast.Replayed
A room, retried The owner gets the same room back; another player with the key gets a conflict
- PageA 64-hex operation key the client makes before its first attempt.
- PostgresTwo transaction-scoped locks, taken in that order, so concurrent attempts with the same key queue behind one another.
- PostgresThe receipt binds key K to this room and this player. The key is globally unique.Committed
- NetworkThe client holds a key and no room.Reply lost
- PageThe same key, from the same player.
- PostgresThe same room comes back, marked as replayed. There is still only one room.Replayed
- PageThe receipt names a different player.
- PostgresRefused. This player cannot use the key to reach the other player’s room or to create a second one.Refused
Limits. This description comes from source inspection; the live database catalog was not queried and the product’s tests were not rerun for this page. The TypeScript game engines and the PL/pgSQL functions implement the same rules in parallel. The unit tests exercise the TypeScript side. Keeping the SQL in step is a manual discipline, and no automated check compares the two. Guests receive no live Broadcast. No latency, scale, concurrency or player number has been measured. A native client shares the server boundary in code, with Android in closed testing rather than a public store release. Erasure deletes the player’s Wordship data. Wordship now has its own sign-in. Deleting an account removes that sign-in as well as its Wordship play; guests can erase their play from the device they used. The source is private and is not linked from this page.
Changelog
What shipped, newest first.
12 releases since 27 Apr 2026, the latest on 26 Sep 2026. From Wordship’s changelog.
Wordship has its own home, and deleting your account deletes your sign-in.
- Improved Wordship now runs on its own servers. Your games, record and friends came along; sign in once more on each device.
- Improved Deleting your account removes your sign-in too, in the app or on the web, even if you never saved a game.
Deletion says exactly what it removes.
- Improved The deletion page separates your Wordship play from the sign-in shared with other Mainthread apps, and says which one each action removes.
- New If you created a sign-in here, you can request its removal as well, even if you never saved a game.
Steadier turns, and your data in your hands.
- Improved The Deduce board no longer jumps after you press Enter, and your letters stay put until their colors turn.
- Improved A finished solo game has one row of navigation, with Next word just below Share.
- New Delete your Wordship play from your profile, or from the deletion page on the web.
- New Guests can delete their play too, from the device they played on.
- New A privacy page explains what Wordship keeps and why.
Deduce plays like the word game you know, and keeps your record.
- New Press Play Deduce for a fresh word, then Next word when you finish. An unfinished word waits for you.
- New Results show your record across Daily and fresh words: games played, win rate, best and average guesses, and how many guesses each win took. Your profile shows the same record.
- New Guests can look back at their earlier Daily boards.
- Improved The board is larger on phones, with a filled keyboard like the one you know. Tiles flip one after another, and the keyboard colors after the last one.
- Improved Share is one button. Preview & options holds the preview and the choice of text or image.
- Improved Answers come from familiar words, skip words you have already seen in Deduce, and leave out a few offensive ones.
- Improved Screen readers announce each guess's clues once the tiles settle.
- Fixed How to play closes when a round ends, so it no longer covers your result.
Earlier releases (8)
Both games open with their own art, and Salvo is easier to follow on a phone.
- New Deduce and Salvo each open with artwork that shows how every mode plays.
- New Guests can play Deduce and Salvo practice games without an account.
- Improved Practice starts on the first press, and opening a shared replay link no longer starts a game until you press Play.
- Improved Salvo's timed word challenge, its keyboard and the latest clue fit on smaller phones.
- Improved Coming back to a friend Salvo match shows the guesses behind each ship's score.
Daily Salvo and friend matches, open to everyone.
- New Play Daily Salvo, the fleet-hunting word game, without an account.
- New Start or join a Salvo friend match with a short code, as a guest or signed in.
- Improved Home puts Daily Deduce and friend play first. Start makes a room in one tap, and Join opens a code field right there.
- Improved Deduce keeps the board and keyboard in view on smaller phones, with a compact line for your opponent's progress.
- Improved Salvo asks for your word before showing the board, and while you wait you see your own fleet with misses marked.
- Improved The defending friend watches the challenge live: their word, each guess and the countdown. Finished matches offer a new one.
- Fixed A guess sent on a weak connection is checked against the game, never lost or counted twice.
Play first. Sign in later, if you want to.
- New Play Daily Deduce without an account. Your progress stays with this device.
- New Start a Deduce friend room and share a short code. Your friend joins without an account.
- New Keep what you played by saving it to a new account, right from the game you are in.
- New Choose your look: Chart Room, Deep Signal or Lantern, each in light or dark.
- Improved Daily Deduce opens straight onto the board, and a finished match shows the result first, then what to do next.
- Improved After you finish a duel, watch your friend's hunt live.
- Fixed Only the players in a game can see its answers and results.
- Fixed Multi-round matches finish when their last round does, and live updates between friends work again.
A new look: Chart Room, and clearer Salvo hits.
- New Wordship takes on Chart Room, a navigator's chart-paper look, in light and dark.
- Improved A Salvo hit tells you which ship it struck.
Salvo, tuned from the first games between friends.
- New Hits, sinks and a finished fleet each have their own motion, which stays still when your device asks for reduced motion.
- New Share a Salvo result as text or an image, with a link that invites friends to play too.
- Improved Daily and Practice Salvo play the new hunt, then deduce, and a found ship shows its letters on the board.
- Improved Daily puzzles use familiar, well-known words.
- Improved Tapping a match invite joins you to it, and the defender sees their own word while their friend guesses.
- Fixed Ships place with one tap, practice words are always available, and the challenge timer no longer runs out right away.
Salvo rebuilt: hunt the fleet, then deduce each word.
- New Friend matches play Salvo in three phases: hunt ships by coordinate, solve each located ship's word in a timed six-guess challenge, and score by how close you came.
- Improved Every fleet word has five letters, the same as Deduce.
- Improved Phones and desktops each get a layout made for them.
- New Share a finished multi-round Deduce match as text or an image.
- Fixed Watching a friend's Deduce round shows every letter as it is typed.
Streaks, stats and head-to-head records.
- New Daily Deduce tracks your current and longest streak, and your profile shows your full record.
- New See your head-to-head record with any friend.
- New The board-and-word game has its own name and home: Salvo.
- Improved Daily puzzles are published a week ahead, so today's is always ready.
- Fixed Pages no longer scroll sideways on phones.
Wordship opens with Daily Deduce, practice and friend matches.
- New Daily Deduce: one word a day, six guesses, the same word for everyone.
- New Practice with random words as often as you like.
- New Challenge a friend to one, three or five rounds, and watch their board live when you finish first.
- New Share a result with a link that lets a friend play the same word without seeing it.