hisohiso

protocol

The server moves your words.
It never reads them.

Encryption happens in your browser, before a single byte leaves. The key never reaches our server. The history never touches our database. Lose your link, and there is nothing for us to recover.

We gave up the conveniences. We meant to.

Mainstream chat apps ship accounts, contact discovery, group invites, forwarding, and cross-device history. Each of those is a surface that lets you be found, followed, and correlated. We do not ship them. What you trade for the rough edges is a chat you actually own.

Have it. Know it. Prove it.

A channel can ask for three things to let someone in: the link you have, the password you know, and the knock that says who you are. For two friends, only the link is required. For an agent pairing, all three are.

have it

The link is the first key.

The room secret lives after the # in the URL. Browsers keep that part of the URL local. Our server sees a hash of the room. It never sees the key.

know it

A password locks the room twice.

Add a password and the message keys are derived from the link and the password. Someone with just the link cannot read or speak.

prove it

A knock says who's at the door.

Knocking sends a short introduction. A person sees it and lets you in. For an agent, the knock is a hidden session secret — the phone has to type it correctly before the agent auto-approves.

Human rooms can skip the password and the knock. Agent pairing uses both: the CLI prints a fresh code and asks for a hidden knock, then only approves a phone that holds all three.

When you create a channel, your browser generates a secret and writes it into the part of the URL after the #. Browsers do not send that part to a server. Our server gets a hash of the room. It never gets the key.

Every message is locked before it leaves you.

When you tap send, your browser encrypts the message with a key derived from the channel secret and, if you set one, the password. The server receives an opaque blob and forwards it. The other browser — or the bridge on your own machine — uses the same inputs to open it.

Messages use AES-256-GCM. Keys are derived from the channel secret and the optional password with HKDF-SHA256.

Joining is a knock, not an account.

A new person opens the link and knocks. Someone already inside sees the knock and approves. For an agent, the local bridge joins from your machine, decrypts the knock with the pairing code, and matches the body against a hidden session message before it lets the phone in. There is no global identity to search, follow, invite, or leak.

We keep the routing. You keep the words.

Our database holds a hash of each channel, a hash of each participant token, and timestamps. Enough to deliver an encrypted event to the right place. Not enough to read it. Your readable message history lives in IndexedDB on your own device.

on our server

Routing data.

Just enough to know which encrypted event belongs where. Not the text of the message.

on your device

Local history.

Every message you received. Clear your browser storage and that local copy is gone.

A channel can opt into encrypted offline catch-up. The server stores ciphertext only, capped by retention rules — newest messages first, old ciphertext expires instead of becoming permanent cloud history.

What we won't pretend to fix.

We protect the contents of your messages from our server. We don't fix bad link-sharing habits. We don't hide your network metadata from your ISP. And we don't decide whether an agent command is safe to run. Those choices stay with you.

If a link gets shared too widely, close the room and create a new one. That is the clean escape hatch.

Small enough to read in an afternoon.

The whole repository is intentionally small. Read the server, the client crypto, and the deployment files without signing an NDA.