Documentation
How it works
The switchboard model - what happens on the wire between the moment an agent boots and the moment your terminal opens.
The analogy#
Think of a hotel switchboard.
- The hidden machine is a guest with no direct phone number.
- kino-agent is that guest ringing the front desk: “I’m in room
box-1, keep this line open, I’ll wait.” - kino-relay is the switchboard. It cannot hear the calls — they are encrypted — it only plugs one line into another.
- Kino SSH Manager is you ringing the hotel: “connect me to room
box-1.” - Kino Cloud is the pass office: it issues the credentials that say who may use the switchboard at all.
One line to remember: control mints, relay checks, agent and manager carry.
What happens when you click Connect#
you relay agent
(manager) (public server) (hidden machine)
│ │ │
│ │ ① agent dialed OUT │
│ │◄───── earlier, at boot ────┤ "I'm box-1,
│ │ and stays parked │ I'll wait here"
│ │ │
│ ② "box-1 please" ──►│ │
│ │ ③ "wake up, session abc"──►│ (down the
│ │ │ parked line)
│ │ │ ④ agent connects to
│ │◄── ⑤ new line for "abc" ───┤ its own sshd
│ │ │ (127.0.0.1:22)
│◄═══ ⑥ relay plugs your line into the agent's ═══►│
│ │ │
│ ⑦ normal SSH runs through the pipe - encrypted end to end.
│ The relay carries scrambled bytes it cannot read.
Step ① is the whole trick: the agent connected outward long before you needed it, so the firewall was never in the way. Steps ②–⑥ take well under a second.
The same thing, as endpoints#
The relay exposes exactly three WebSocket routes plus a health check:
| Route | Who dials it | What it is |
|---|---|---|
GET /healthz |
monitors, Kino Cloud | Liveness. Returns ok. |
GET /ws/control?agent_id=<id> |
the agent | The parked line. The agent registers and waits for new_connection messages. Kept alive with 30-second pings. |
GET /ws/manager/request?agent_id=<id> |
the manager | “Reach this agent.” The relay notifies the agent and waits up to 10 seconds for it to dial back. |
GET /ws/agent/data?session_id=<id> |
the agent | The return data socket for one session. The relay hands it to the waiting manager and bridges the two. |
Every session gets a fresh data socket and a fresh relay-generated
session_id. The control channel is never used to carry SSH bytes.
Relay discovery#
Without discovery you tell both sides which relay to use. With it, they work it out themselves:
- A relay operator enrolls their relay: the relay starts with a one-time code, registers itself, and receives the controller’s public key. The controller health-checks it every minute. See Relay → Enrolling.
- The agent starts with
--control-urlinstead of a fixed relay. It fetches the relay list (returned best-first), latency-races the top few, parks on the fastest healthy one, and reports where it parked. Every reconnect re-picks, so an agent migrates by itself when its relay dies or a better one appears. - The manager asks “where is machine X parked?” at connect time and dials that relay. A saved relay URL acts as a fallback if the controller is unreachable.
Because relays only ever hold the public half of the signing key, a relay can verify a credential but never forge one. That is what makes a pool of community-run relays possible without trusting the operators.
Who sees what#
| Your SSH password / key | Your terminal session | What it does know | |
|---|---|---|---|
| manager | Yes — it is your app; secrets live in its local encrypted vault | Yes — it is your screen | Everything. It is yours. |
| agent | No | No — bytes pass through encrypted | That someone connected |
| relay | No | No | Who talked to whom, and when. Metadata only. |
| control | No | No — it is not in the data path at all | Which accounts and machines exist; which credentials were issued |
Your SSH password or key is checked by the target machine’s own sshd, exactly
as if you had connected directly. The relay being compromised does not leak
your credentials or your session — the worst it can do is refuse to connect
you, or lie about which backend you reached.
That last one is handled too: the manager pins each agent host’s SSH
fingerprint, keyed by agent id, the same way OpenSSH’s known_hosts catches a
swapped server.
A relay with no auth is an open door
A relay started with neither RELAY_TOKEN nor a controller public key runs
open, and says so loudly at startup. Anyone who can reach it and knows
an agent_id can open an SSH transport to that machine’s sshd — where
that machine’s own authentication becomes the only gate. Fine for a
firewalled lab. Never for anything public.
Where the trust actually sits#
- You trust your own machine. The vault, the master password, the SSH keys.
- You trust the target’s
sshd. As you always did. - You do not have to trust the relay. Verification is asymmetric and the data is end-to-end encrypted.
- You trust Kino Cloud to say honestly where an agent is. It could point you at a relay of its choosing. It still cannot read the session — and the host-key pin catches a substituted backend, which is the attack that would actually matter.
That last item is the one worth thinking about, and the answer is the same one OpenSSH has always given: verify the host key. The manager pins it per machine and warns you the moment it changes, so being routed somewhere unexpected fails loudly rather than silently.
If you would also rather the route itself be yours, run your own relay — it takes about ten minutes and changes nothing else.
Next#
- Quickstart — the fastest path to a working connection.
- Credentials and tokens — every secret in the system, in detail.