Think ngrok, but for keystrokes

Let your colleague
type into your terminal.

You're screensharing. They need to run a command. Stop dictating characters. Give them a session code and let them type directly.

Install keytun Join from browser See how it works
Terminal — host
$
keytun v0.1.0
Session: keen-fox-42
Waiting for client...
✓ Client connected
$
Terminal — helper
$
Connected to keen-fox-42
You are now typing into the remote terminal.
Press Esc twice to disconnect.

The problem with screensharing

🗣

Dictating commands

"Capital D, dash, dash, no-cache, space, dot, no the other dot..."

🔄

Swapping screen control

Request control, wait for approval, fumble with resolution differences, give it back.

🛠

Full pair-programming tools

VS Code Live Share, tmate, tmux — all overkill for "let me just type this one command."

keytun

Share a code. They type. You see it live on your screenshare. Done.

How it works

Host

Developer screensharing.
Runs keytun host

WebSocket
Relay

Stateless broker.
Bridges connections.

WebSocket
Client

Helper colleague.
Runs keytun join <code>

1

Host starts a session

Run keytun host. A PTY spawns your shell. You get a session code like keen-fox-42.

2

Share the link over your call

You get a direct join link like keytun.com/s/keen-fox-42. Drop it in chat — your colleague opens it in their browser. No install needed.

3

Helper joins and types

They can join from the browser or via CLI. Raw key bytes flow through the relay to the host's PTY. Arrow keys, tab completion, Ctrl+C — everything works.

4

Host sees it live

Both local and remote input appear in the same terminal. Your screenshare shows everything in real time.

Two ways to inject keystrokes

Choose the mode that fits your workflow.

🖥

Terminal mode

Spawns a full PTY session with your shell. Your colleague types directly into a real terminal — arrow keys, tab completion, Ctrl sequences all work.

Terminal
$ keytun host
  • Run commands together
  • Debug a shell session
  • Pair on infrastructure
🎯

System mode

Injects keystrokes at the OS level into any application. Target a specific window by name — your colleague types into your IDE, editor, or any focused app.

Terminal
$ keytun host --mode system
$ keytun host --mode system --target "VS Code"
  • Type into an IDE over screenshare
  • Fill forms in any GUI app
  • Target a specific window by name
macOS only

Built for developers

Single binary

Go binary. No runtime, no dependencies. Download and run.

🔑

Readable session codes

Wordlist-based codes like keen-fox-42. Easy to say over a call.

🔒

End-to-end encrypted

X25519 key exchange + AES-256-GCM. The relay is a dumb pipe — it never sees your keystrokes or output.

☁️

Self-hostable relay

Stateless WebSocket broker. Deploy on Fly.io, Railway, or any container host.

🌐

Browser client

Your colleague doesn't need to install anything. Share a link and they join straight from the browser.

🪶

Lightweight

No database, no auth tokens, no persistence. Sessions live in memory.

Get started

Shell

Terminal
$ curl -fsSL keytun.com/install.sh | sh

Homebrew

Terminal
$ brew install --cask gboston/tap/keytun

Usage

Host (developer)
Terminal
$ keytun host
Client (helper)
Terminal
$ keytun join keen-fox-42

Connects to relay.keytun.com by default — all traffic is end-to-end encrypted. The relay only sees ciphertext.

Roadmap

What's coming next.

🔐

Password-protected sessions

Host sets a password when starting a session. Clients must enter it before keystrokes flow.

👁

Read-only mode

Join as a viewer — see the terminal output without being able to type. Great for demos and teaching.

🐧

Linux system mode

OS-level keystroke injection on Linux via xdotool/ydotool, matching the existing macOS system mode.

🔔

Connection notifications

Audible and visual notifications when a client joins or leaves your session.

📡

Latency indicator

Round-trip time in the client status bar so you know whether lag is keytun or your connection.

Connection approval

Host approves each client before keystrokes start flowing. Full control over who gets access.