The tunnel modality is driven by the clutchcall CLI and its QUIC data-plane engine. There is no typed Tunnel SDK class today.
A programmatic client (embed a tunnel in your own process) is Preview — see Programmatic API (Preview) at the bottom. For shipping work, use the CLI documented here.

Install

curl -fsSL https://clutchcall.dev/clutchcall/install.sh | sh
The CLI is a pure-static binary for Windows, macOS, and Linux (amd64 / arm64). It launches a separate QUIC engine for the data path; the engine ships next to the CLI or is pointed at with an env var (see Config).

Sign in

clutchcall login      # provider device flow — the provider hosts the UI
No credentials are stored. The CLI persists only a short-lived session JWT and a device id under your user config dir (0600). Sign out with clutchcall logout.

Command surface

CommandWhat it does
clutchcall loginSign in via device flow → session token
clutchcall logoutForget the saved session
clutchcall statusPlan, devices (n/5), wallet balance, this-month egress
clutchcall devicesList your devices
clutchcall devices rm <id>Remove a device, freeing a slot on the free plan
clutchcall claim <name>Reserve a subdomain → https://<name>.clutchcall.dev
clutchcall http <port> [--name n]Expose localhost:<port> at a public HTTPS URL
clutchcall p2p share <pair-id> --port <p>Share a local service direct to a peer (no relay)
clutchcall p2p connect <pair-id> --listen <p>Reach a peer’s shared service directly
clutchcall topup <amount>Add wallet balance
clutchcall versionPrint version

http — expose a local service

clutchcall http <local-port> [--name <sub>] [--slug <slug>]
Dials the nearest edge PoP over QUIC and forwards inbound public traffic to localhost:<local-port>. Prints the public URL and runs until interrupted.
<local-port>
int
required
The local TCP port to expose (e.g. 3000).
--name
string
A label appended to your reserved subdomain: with handle alice, --name apihttps://alice-api.clutchcall.dev. Requires a claimed handle.
--slug
string
Override the slug explicitly (power users). The edge still enforces your namespace from the session token, so a stale slug can’t escape it.
clutchcall claim alice          # reserve https://alice.clutchcall.dev
clutchcall http 3000            # → https://alice.clutchcall.dev
clutchcall http 8080 --name api # → https://alice-api.clutchcall.dev
WebSocket upgrades, server-sent events, and chunked/streaming responses pass through unchanged — each public connection is its own QUIC stream.

p2p — direct peer-to-peer

Two peers run with the same pair-id; they auto-discover via the control-plane rendezvous and connect directly, with the edge brokering candidates but never carrying bytes. Across NATs, set the <P>_STUN env var (where <P> is your CLI’s uppercased brand prefix) to a reflector so each side can gather its public candidate.
clutchcall p2p share <pair-id> --port <local-port> [--proto tcp|udp|http]
<pair-id>
string
required
A shared secret both peers know; gates the direct tunnel and keys the rendezvous.
--port
int
(share) The local service port to expose to the peer.
--listen
int
(connect) A local port to listen on; connections to it are piped to the peer’s shared service.
--proto
string
default:"tcp"
(share) tcp, udp, or http.
--stun
string
STUN reflector host:port for reflexive candidate gathering (or set <P>_STUN).
# Box A shares its SSH; Box B reaches it on its own port 8022
A$ clutchcall p2p share mylink --port 22
B$ clutchcall p2p connect mylink --listen 8022
B$ ssh -p 8022 localhost       # rides the direct QUIC link
Endpoint-independent (cone) NATs punch through directly. Symmetric NATs fall back to the relayed path.

status & devices

clutchcall status     # plan, devices (n/5), wallet balance, egress this month
clutchcall devices    # list devices; current device is marked
clutchcall devices rm dev-1a2b…   # free a slot
The free plan caps you at 5 devices. Each install gets a stable device id, shown in devices and enforced by the session token’s device claim.

Config

CLI state lives at your user config dir, e.g. ~/.config/clutchcall/config.json (mode 0600). It stores only non-secret session state:
{
  "api_base":    "https://api.clutchcall.dev",
  "device_id":   "dev-…",
  "device_name": "my-laptop",
  "token":       "<short-lived session JWT>",
  "expires_at":  "…",
  "handle":      "alice"
}

Environment variables

Env vars use your CLI’s brand prefix — shown below as <P> (the uppercased binary name, e.g. clutchcall → its uppercase form).
VarPurposeDefault
<P>_APIControl-plane base URLhttps://api.clutchcall.dev
<P>_POPQUIC edge host:port (data plane)<base>:4443
<P>_STUNSTUN reflector host:port for P2P
<P>_TUNNEL_BINPath to the QUIC data-plane enginenext-to-binary / $PATH
<P>_BASE_DOMAINPublic base domain for printed URLsclutchcall.dev

Data-plane engine flags

clutchcall http execs the QUIC engine (clutchcall-engine) with the resolved arguments. You rarely call it directly, but the surface is:
clutchcall-engine http <port> --server <pop> --token <jwt> [--slug <slug>]
clutchcall-engine p2p share <proto> <port> --quic-port <p> --peer <ip:port> --token <pair-id> [--stun <addr>]
clutchcall-engine p2p connect --quic-port <p> --peer <ip:port> --listen <port> --token <pair-id> [--stun <addr>]

Remote desktop on the same transport

A remote-desktop client (a fork of an open-source remote-desktop project) runs its network transport over this same raw-QUIC relay instead of its own rendezvous/relay. Enable it by pointing the client’s quic-relay-server option at a host:port running the tunnel module:
  • The controlled box registers its device id as a slug (proto":"quick") and parks bidi work streams.
  • The controller dials the box by slug; the edge splices the two QUIC streams.
  • The remote-desktop client’s own message framing and end-to-end encryption ride unchanged on top — the edge only secures the QUIC hop to the PoP and never sees cleartext.
This is the remote-desktop tunnel type in the details page; no extra CLI is needed beyond the relay endpoint.

Programmatic API (Preview)

Preview / forward-looking. A typed Tunnel client to embed a tunnel inside your own process is not in the shipping SDK. Ship with the CLI today. The shape below is illustrative and may change.
// Preview — not yet shipped
import { Tunnel } from "@clutchcall/sdk/tunnel";

const tunnel = new Tunnel({
  pop:   "edge.clutchcall.dev:4443",
  token: process.env.CLUTCHCALL_CREDENTIALS!,
});

const { url } = await tunnel.http({ port: 3000, slug: "alice" });
console.log("public URL:", url);   // https://alice.clutchcall.dev
await tunnel.close();