TermBridge logo TermBridge Docs

Architecture

TermBridge has four components. Two you install (the Mac app and the iOS app); the other two are internal. The key idea is that it attaches at the shell layer, not the terminal-emulator layer.

The components

#ComponentTechRole
1Shell hookA guarded block in ~/.zshrcSources the hook, which re-execs each interactive shell through the agent. Heavily guarded against loops and lockout.
2AgentA small background daemon (launchd)Owns the PTYs, holds the live-shell registry, and keeps one outbound connection to the relay.
3RelayCloudflare Worker + Durable ObjectPairs phone ↔ Mac and routes sealed frames. No inbound port on your Mac.
4iOS appUniversal iPhone / iPad appPairing → session list → terminal view.

The shell-layer hook

This is the mechanism that makes “attach to the terminal you’re already in” possible. When you open an interactive shell, the hook re-execs it inside an agent-owned PTY using the classic script(1) pattern. The shell behaves completely normally on your desk, but its input and output are also teed to the agent.

That’s why it works across every terminal app: the hook lives below the emulator, so iTerm2, Terminal.app, VS Code, Zed, Cursor, and tmux all funnel through it the same way. See Supported terminals.

Failing safe

The hook only wraps a shell when every guard passes — it’s interactive, not a -c command invocation, not already wrapped, not disabled, the agent is up, and the wrapper binary exists. If any guard fails, you get a completely normal shell. A missing binary or a dead agent can never lock you out of a terminal — this fail-safe behavior is a core design guarantee.

The agent

The agent runs under launchd and is the heart of the local side. It holds the registry of live shells, owns their PTYs, and maintains a single outbound WebSocket to the relay — so nothing inbound is ever opened on your Mac. Remote clients attach through the agent, which injects their input into the right PTY.

The relay

The relay is a Cloudflare Worker backed by a Durable Object. It pairs a phone and a Mac into a private room and forwards ciphertext only — it never holds a key. It’s also where plan limits are enforced, because it’s the one component that doesn’t run on a device the user controls.

The crypto

Every frame between phone and Mac is sealed with X25519 + AES-256-GCM, with a fresh ephemeral key per connection (forward secrecy) and an HMAC channel binding that defeats a man-in-the-middle relay. Full detail in the Security model.

Data flow

your shell → shell hook → agent (PTY + registry) → outbound WSS
   → relay (routes ciphertext) → iOS app → your phone

Next

See the CLI reference for manual agent control, or Troubleshooting when something’s off.