One command to make any terminal you open reachable from your phone or another device.
Wrapper transparently wraps every interactive shell session you open (zsh, bash, or fish) so an authenticated device can mirror it on demand. The wrapping itself is invisible: your dotfiles, prompt, plugins, and history all behave exactly as before.
A session never leaves your machine until you decide to share it. Inside
a wrapped shell, Ctrl+\ s opens a relay tunnel and Ctrl+\ u closes it
again. A second device then attaches to that session and sees the live
terminal.
- You open a terminal. Your rc file runs
wrapper shell-host, which spawns your real shell inside a pseudo-terminal (PTY) and starts a tiny local WebSocket server bound to127.0.0.1. Nothing is exposed yet. - From the same machine,
wrapper attachconnects to that local server and mirrors the session. This path needs no account and no network. - When you press
Ctrl+\ s, the CLI asks the Convex backend for a short-lived host ticket, connects to the relay on Fly.io, marks the session shared, and prints a secret share code. You join your own devices withwrapper attach --relay --id <id>; anyone else must pass the code with--code <code>, so knowing the session id alone is not enough. - By default the relay is used only to exchange WebRTC signaling, and the actual
keystrokes and output move over a direct peer-to-peer data channel for lower
latency. The relay stays as the fallback, and you can force it with
WRAPPER_P2P=0.
This is a Bun and Turborepo monorepo.
apps/
cli/ Wrapper CLI: shell wrapping, session registry, local + relay attach, device auth, default-on P2P
relay/ Relay service: authenticated WebSocket routing for shared sessions, deployed on Fly.io
web/ Next.js app on Vercel: landing page, device-login approval, onboarding, Pro upgrade
docs/ Public documentation site (Mintlify)
mobile/ Git submodule pointer to the external mobile app repository (not built here)
packages/
protocol/ Zod wire schema shared by every wrapper component (JSON frames + WebRTC signal)
backend/ Convex backend: Better Auth, session lifecycle, relay tickets, onboarding, billing
terminal/ Bun-native PTY layer using the wrapper-pty-helper binary
logger/ Consola logging plus opt-in PostHog telemetry
typescript-config/ Single-source tsconfig presets
tools/
pty-helper/ C source and Makefile for the wrapper-pty-helper binary shipped with the CLI
The CLI is the heart of the project. See
apps/cli/README.md for how the wrapping flow works
and what every command does. The transport layer (relay WebSocket and the
default direct WebRTC path) is documented in
apps/cli/transport/README.md.
| Topic | Document |
|---|---|
| CLI commands, keystrokes, env vars | apps/cli/README.md |
| Relay + direct P2P transports | apps/cli/transport/README.md |
| Relay service and Fly deploy | apps/relay/README.md |
| Convex backend (auth, sessions, tickets, billing) | packages/backend/README.md |
| Wire protocol | packages/protocol/README.md |
| PTY internals | packages/terminal/README.md |
| Logging and telemetry | packages/logger/README.md |
| Dev and prod environments, deploy automation | ENVIRONMENTS.md |
| The full docs site | apps/docs (run bun run --cwd apps/docs dev) |
The CLI core, the Convex auth and backend, the relay transport, and the web
onboarding flow are implemented in this repository. Sharing attempts a direct
WebRTC P2P data path by default, with the relay kept online for signaling and
automatic fallback (WRAPPER_P2P=0 forces relay-only mode). The terminal title
shows the role, session, and active transport without reserving a screen row.
The next major phase is the mobile app, which lives in the apps/mobile
submodule and is planned in the docs site.
The active focus before mobile work is operational hardening and release channels:
- deploy the relay service (
apps/relay) through the workflow with smoke checks - publish CLI release archives and update the Homebrew tap formula
- keep the critical auth and relay test lanes green in CI
- verify the P2P fast path on real networks (NAT traversal)
Requirements:
- Bun 1.3.5 or newer for runtime, package management, and bundling.
- A POSIX system (macOS or Linux). On Windows, run Wrapper inside WSL.
Environment templates are included:
.env.example(shared)apps/cli/.env.exampleapps/relay/.env.examplepackages/backend/.env.example
bun install # one-time
bun run check-types # typecheck every package
bun run lint # oxlint
bun run format # oxfmt --write
# try the wrapping flow locally
cd apps/cli && NODE_ENV=development bun run index.ts shell-hostNODE_ENV=development moves every on-disk path into a wrapper-dev namespace
under XDG state (or %APPDATA%\wrapper-dev\ on Windows), points the relay and
auth URLs at localhost, mirrors logs to stderr, and writes rc-file patches into
a throwaway directory. A developer running the CLI locally can never corrupt a
real installation's registry, logs, or rc files.
Setting CI to any value disables telemetry and console output. For the full
list of CLI environment variables, see
apps/cli/README.md.
- Bun for runtime, package management, and bundling.
- Turborepo for task orchestration and caching.
- oxlint and oxfmt for linting and formatting (no ESLint, no Prettier).
- Lefthook for git hooks (pre-commit oxfmt and oxlint, pre-push checks).
- Catalog dependencies so shared packages such as
react,next,zod, andtypescriptuse a single pinned version across the workspace.
TBD.