Reins

SECURITY

Reins isn't end-to-end encrypted — because "ends" implies something in between.

Your phone opens an SSH connection straight to your own machine. There's no relay to encrypt against, no account to breach, and no server that has to stay up for your tools to work. That's not a knock on E2E — it's the right answer if you have a relay. It's just a different question. E2E asks "can the server in the middle read this?" Reins asks "why is there a server in the middle?"

Two things cross the boundary, both to your own machine and nothing else: SSH, authenticated by your key against a host key checked at pairing, and the encrypted transport connection it mints for the session. Everything else lives on loopback or a Unix socket only your user can open. The amber arrow is the one capability worth knowing about — turn it off with --allow-chat-send=false.

Where the trust boundaries actually are

Reins adds one process to your machine: reins serve. It runs as you and binds 127.0.0.1:7777 for the local shims. Your phone authenticates over SSH — the sshd you already trust — using a key the host minted for the pairing, or one you imported, held in the phone's keychain. That SSH session mints a short-lived grant, and the phone then holds an encrypted transport connection to the port named in it, so a dropped link resumes instead of reconnecting from scratch.

Inside the tunnel there's a second check: a 48-character random token, generated on first run, stored at ~/.reins/token with mode 0600, compared in constant time, sent in an Authorization header — never a URL. Its job isn't to stop the internet; the tunnel did that. It stops a different process on your own machine, or a phone you didn't pair, from talking to the daemon.

Don't take our word for it

Every claim on this page is checkable in about two minutes.

  1. 01

    See everything the daemon listens on

    lsof -nP -iTCP -sTCP:LISTEN | grep reins

    Two lines: 127.0.0.1:7777 for the local shims, and the transport port your paired phone dials. Anything beyond those two means you passed --listen — or we broke a promise and want to know.

  2. 02

    See every connection it makes, at any moment

    lsof -nP -i | grep reins

    Inbound from your phone — the SSH session and the transport connection. Nothing outbound. Ever.

  3. 03

    Look for a phone-home in the binary itself

    strings $(which reins) | grep -Eo 'https?://[a-zA-Z0-9./-]+' | sort -u

    Three results, all Go runtime error URLs (go.dev/…). There is no API endpoint in this binary because there is no API.

  4. 04

    Watch the wire while you use it

    sudo tcpdump -i any -n 'not port 22 and not host 127.0.0.1'

    Drive the app for a few minutes. Two flows reach your phone and nothing else: SSH on port 22 for the handshake, and the daemon's transport port carrying the encrypted session. Exclude that port too and everything else is silence.

5. Check what you downloaded. Every release publishes SHA-256 sums. Compare the binary you installed against the checksums file on the release before you run it — shasum -a 256 on macOS, sha256sum on Linux. The source is not published yet, so the four checks above are what you can verify today, and they cover what the daemon listens on and every connection it makes.

What Reins can see

The daemon tails Claude Code's transcript files so your phone can show the conversation: your prompts, the agent's replies, the commands it wants to run, your working-directory paths — sent to your phone and nowhere else. Other agents have no transcript to tail: Codex, OpenCode and a plain shell are read from their pane, so Reins sees exactly what is on that screen and nothing more. Nothing is sent to us. There is no "us" in the data path: no relay, no analytics, no crash reporting, no telemetry.

Voice input goes to your phone's dictation service.

Tap the mic and Apple or Google transcribes your audio before the text reaches your machine. Type instead if that's not acceptable — everything else is identical.

If you reach your machine over Tailscale or a VPN, that's in your path.

Reins adds no third party. Your network layer might have one. We'd rather say so than let "no middleman" quietly mean "except the one we told you to install."

Reins cannot lock you out of your own machine

When Claude Code asks to run a command, it calls reins hook pre-tool-use. That process either produces a decision your phone made, or it produces nothing at all — and when it produces nothing, Claude Code falls through to the permission prompt it would have shown you anyway.

What happens when part of Reins is unavailable
SituationWhat happens
Daemon isn't runningShim exits immediately. Normal prompt.
Daemon running, no phone connectedExits immediately — doesn't burn the 60s waiting for a phone that isn't there.
Phone connected, you're asleep or in a tunnelWaits up to 60s, then exits. Normal prompt.
Phone taps approve after the shim gave upIgnored. A late tap is never a live approval.
Daemon crashes mid-decisionSocket read fails, shim exits. Normal prompt.
Our infrastructure goes downThere isn't any.

The cost is honest and worth stating: an unanswered approval is not a denial. If you want a command blocked, deny it. Walking away is the same as not having Reins installed.