froglet.
Concepts

Networking

Public HTTPS ports, SSH access via the bastion, and the workspace-private network.

Every sandbox gets a private IP on the workspace network and an sshd the bastion can reach. Outbound is unrestricted; inbound is gated by ports and ssh-access tokens.

Ports

A public HTTPS route from https://<label>--<sandbox-slug>.froglet.sh to an internal port inside the sandbox.

$ froglet ports expose demo --internal 8080 --label web
exposed :8080 → http://web--demo.froglet.sh
FlagEffect
--internalGuest port to forward to. Required.
--labelURL prefix. Reserved labels (api, admin) are rejected.
--publicDefault. No auth on the route.
--privateRequires an access token. Mint with ports share.
--ttlAuto-revoke after N seconds.

One-time share link:

$ pid=$(froglet ports ls demo --json | jq -r '.[0].id')
$ froglet ports share demo "$pid" --ttl 300
token (expires …): eyJhbGciOiJI…

Revoke explicitly with ports revoke <sandbox> <port-full-uuid>.

SSH

The bastion is at ssh.froglet.sh:2222. Auth is a workspace-scoped JWT minted by ssh-access new:

$ froglet ssh-access new demo --name laptop --ttl 4
created access c35d7262-…

    ssh -p 2222 eyJhbGciOiJI…@ssh.froglet.sh

expires 2026-05-17T18:00:00.000Z

Paste the printed ssh -p 2222 … line into your terminal. The JWT is the username; the bastion validates it and proxies to the sandbox's guest sshd.

CommandEffect
ssh-access new <sandbox>Mint a token. --ttl <hours> controls expiry.
ssh-access ls <sandbox>List outstanding tokens.
ssh-access rm <access-uuid>Revoke a token (full UUID required).

PTY

For a browser terminal, mint a 60-second-TTL WebSocket ticket:

$ froglet sb pty-ticket demo
wss://…?ticket=eyJhbGciOiJI…

The dashboard's terminal panel uses this; you can plug the URL into xterm.js or similar.

CLI / SDK

CLI · ports + ssh-access; SDK namespaces ports.*, sshAccess.*, plus the per-sandbox helpers sandboxes.exposePort, sandboxes.createSshAccess, sandboxes.ptyTicket.