Skip to content

heycupola/wrapper

Repository files navigation

Wrapper

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.

How it works in one minute

  1. 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 to 127.0.0.1. Nothing is exposed yet.
  2. From the same machine, wrapper attach connects to that local server and mirrors the session. This path needs no account and no network.
  3. 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 with wrapper attach --relay --id <id>; anyone else must pass the code with --code <code>, so knowing the session id alone is not enough.
  4. 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.

Repository layout

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.

Where to read next

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)

Status

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)

Local development

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.example
  • apps/relay/.env.example
  • packages/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-host

NODE_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.

Tooling

  • 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, and typescript use a single pinned version across the workspace.

License

TBD.

About

A terminal layer that connects and orchestrates AI tools across your devices.

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages