Team-only, self-healing SSH tunnels over Cloudflare. The package is public but
carries zero secrets and does nothing without a currently-valid, server-issued
key. Boxes need no gh/npm login: the tool is npx-run and SSH keys are pulled
from https://github.com/<user>.keys.
Linux targets. Every command runs silently and fully detached as a background daemon, self-heals through tunnel death and reboots, and keeps no local logs — crashes, errors, and status are forwarded to the registry, never written to the box.
No install needed on a box:
npx burrowed <command> ...As a dependency for the SDK:
npm i burrowedTwo credentials, split by entropy:
- Join key — what you type: three words plus two digits (
swift-tiger-comet-42). Server-minted, short TTL, single-use by default, rate-limited. Carries a role:node(expose + snapshot),reader(list/view/pull), oradmin. - Session token — 256-bit, returned by enroll, held only in daemon memory and slide-refreshed. Never on a command line or disk.
--root <ROOT_KEY> is the admin override. Root enrolls as an admin session and can
do anything — list, ssh, kill, and snapshot any box. Admins hold it; it is never
required on a box. Admin commands also read BURROW_ROOT_KEY from the environment.
burrowed on (<key> | --root <K>) [--github <user>]... [--pubkey <line>]... [--restart]
burrowed getboximage (<key> | --root <K>) [--manifest | --content] [--path <dir>]...
burrowed ssh <id|name|latest> (<key> | --root <K>) [--githubsshkey <file>] [--user <u>]
burrowed list (<key> | --root <K> | --token <T>)
burrowed kill <id|all> (<key> | --root <K> | --token <T>)
Fire-and-forget. Backgrounds a daemon that opens a Cloudflare tunnel to the box's
SSH and registers it. The tunnel URL is never printed or persisted on the box —
discover boxes centrally with list.
npx burrowed on swift-tiger-comet-42 --github alice --github bobDefault --manifest: a file tree plus small text snippets, with secrets
(.ssh/.env/keys/cloud creds) and heavy dirs excluded, reading only what the
running user can already access. --content (alias --full) also streams full file
bytes to R2. Browse with images/image, restore with pull.
npx burrowed getboximage swift-tiger-comet-42 # manifest (default)
npx burrowed getboximage swift-tiger-comet-42 --content # full bytes to R2Resolve a box by instance id, machine name, an unambiguous id prefix, or latest,
then open a shell over the tunnel. CLI-only by design; this is not in the SDK.
npx burrowed ssh latest --root <ROOT_KEY> --githubsshkey ~/.ssh/id_ed25519
npx burrowed ssh my-box-a1b2 swift-tiger-comet-42npx burrowed list swift-tiger-comet-42Marks a box (by id) or every box in scope (all) for self-destruct. The registry
drops the listing immediately; the box obliterates itself — daemon, service, tunnel,
and local state — on its next heartbeat. A bound key kills only what it owns; root
or an admin token kills anything.
npx burrowed kill my-box-a1b2 --root <ROOT_KEY>
npx burrowed kill all swift-tiger-comet-42on self-heals the tunnel (edge death, 530 zombies, link loss) and survives the
shell that launched it, but the daemon it spawns has no supervisor — a host reboot
or a hard process kill ends it. For a box that must come back on its own, install a
supervisor:
npx burrowed install-service swift-tiger-comet-42 --github alice
npx burrowed uninstall-serviceOn Linux this writes a systemd --user unit (Restart=always, started on boot via
linger) that runs the same worker; on macOS, a launchd agent. It restarts on crash
and starts at boot. Trade-off: unlike on, this writes the key into a 0600 unit
file on the box, so prefer a longer-lived, multi-use key for it. kill and remote
self-destruct remove the unit as part of teardown.
A key-bound client for apps running on a box. Set the key once; every call is gated
by it. ssh is intentionally absent — it is CLI-only. Each command is four lines or
fewer:
import { burrow } from "burrowed";
const b = burrow({ key: process.env.BURROW_KEY });
const handle = await b.on({ github: ["alice"] }); // 1. expose over SSHconst snap = await b.snapshot(); // 2. getboximage (manifest)
const full = await b.snapshot({ mode: "full" }); // or full bytes to R2const { tunnels } = await b.list(); // 4. active team tunnelsawait b.kill("all"); // 5. self-destruct owned boxes
await b.kill(handle.id); // or one box by idThe key is the only secret; nothing here works without a live one.
Env: BURROW_KEY, BURROW_ROOT_KEY, BURROW_REGISTRY, BURROW_SSH_GITHUB (csv),
BURROW_SSH_PUBKEY (csv).