Skip to content
Work in progresspre-register via email

pbx commands

pbx is one binary for macOS, Windows and Linux. It is built, and not released yet.

pbx [--hub NAME] [--agent INTEGRATION] [--output text|json] [--passphrase-file FILE] <command> [arguments]

--json is the same as --output json. pbx help lists the commands; pbx host lists those that start with host.

CommandWhat it does
pbx loginsign in at the portal in the browser; the token goes to the system’s credential store
pbx logoutforget the portal token
pbx whoamithe account, team and licence this machine is signed in with
pbx licencethe licence as the hub and the portal see it
CommandWhat it does
pbx up NAME [--location nbg1] [--server-type cpx02] [--plan] [--yes] [--abort]create a hub in your Hetzner project, pair this machine as its owner, activate the licence
pbx status [NAME]the hub: its licence, servers, twins, open approvals and releases, the link of every hub on this machine, and the alpha label
pbx open [PATH]the hub’s portal in the browser, through a local proxy while pbx runs
pbx upgrade [NAME] --dist DIR [--plan] [--allow-from ADDR]install another pbx-hub release on the hub’s server; data and pairings are kept
pbx down NAME [--plan] [--confirm NAME] [--keep-image]delete the hub and what pbx up created

Hetzner tokens: --token-file F or --hcloud-context C for production, --twins-token-file F or --twins-hcloud-context C for twins; else HCLOUD_TOKEN, else a prompt.

A machine can be paired with several hubs, with a device of its own for each. A command talks to one of them, chosen in this order: --hub NAME (or pbx status NAME), then PBX_HUB, then the default hub, then the only hub there is. With several hubs and no default, the command asks for --hub.

CommandWhat it does
pbx hub listthe hubs on this machine: endpoint, device, protection level, the default (*), and whether a pbx open holds a link
pbx hub currentthe hub a command talks to now, and why (--hub, PBX_HUB, the default, the only one)
pbx hub use NAMEmake NAME the default hub; --hub and PBX_HUB still win over it

pbx hub list and pbx hub current talk to no hub; they read this machine’s files. The first pairing sets the default when there is none; pbx down of the default hub clears it.

Every command that changes something at a hub prints hub: NAME on stderr first. With --output json there is no such line; the JSON carries a hub field instead. Commands that only read print neither.

CommandWhat it does
pbx pair --listener URL --code CODEpair this machine through the hub’s pairing listener
pbx pair invite --role ROLE [--name NAME]an invite for another device (owner): one string, valid 10 minutes
pbx pair INVITEpair this machine with an invite
pbx devicesthe hub’s devices
pbx devices revoke ID|NAME [--confirm NAME]revoke a device (owner)
CommandWhat it does
pbx --agent INTEGRATION <command>run a command as a coding agent (claude-code, cursor, …), signed with this device’s agent key of that integration
pbx agent register INTEGRATIONregister this device’s agent key of an integration with the hub (a person, once; pbx --agent does it on first use)
pbx agent revoke INTEGRATION [--device ID]revoke a device’s agent key of an integration (this device’s, or any as owner)

In agent mode the hub holds every request to the agent’s ceiling. Above it the command exits 4; what a person must approve exits 5 with the approval’s id. With PBX_AGENT set, pbx open, pbx approve, pairing and pbx agent register|revoke are refused (exit 4); pbx never falls back to the person’s key. Coding agents has the details.

CommandWhat it does
pbx host create NAME [--type cpx22] [--env production|staging] [--location L] [--release V]a production or staging Podman host
pbx host listthe production and staging hosts
pbx host delete NAME [--confirm NAME]delete a host and its server (a device below presence asks for an approval)
pbx open host NAME [--ttl 1h] [--no-browser]a staging host’s page that is not public, in the browser, as pbx open twin
pbx host access NAME [--from ADDR,…] [--ttl 1h]a web access link to a staging host that is not public
pbx host access list NAME [--all]a staging host’s web access grants
pbx host access revoke NAME GRANTrevoke a staging host’s web access grant
pbx host public NAME [on|off] [--confirm NAME]whether a staging host is public (80/443 from anywhere, its own TLS); on needs the name typed
pbx host reseed NAME [--copy-from PRODUCTION] [--confirm NAME]reseed a staging host’s data, or fill it with a copy of production
pbx release listthe releases the hub imported
pbx release promote VERSION --host NAME [--now]move a host to a release
CommandWhat it does
pbx twin create --production HOST --task TASK [--branch B] [--ttl H] [--data seed|copy|empty]a twin of a production or staging host; its data from the seed (default), empty, or a copy of production on purpose
pbx twin list [--all]the twins, with their data and web access
pbx twin show TWINa twin: its state, its data (seed, mask, their logs) and its web access
pbx twin extend TWIN --hours Hextend a twin once
pbx twin reset TWINreturn a twin’s data to its checkpoint
pbx twin reseed TWINrun a twin’s seed again: its volume emptied, the seed of its revision run, a new checkpoint
pbx twin delete TWIN [--confirm TASK]delete a twin and its server
pbx twin evidence TWINwhat the hub knows of a twin, with its digest
pbx twin settings [--type T --location L]the twins’ Hetzner project (owner)
pbx open twin TWIN [--ttl 1h] [--no-browser]a twin’s page in the browser: a grant for this device’s address; without a DNS zone, a local proxy while pbx runs
pbx twin access TWIN [--from ADDR,… | --any] [--ttl 1h]a web access link for named addresses (--any: a presence device, a seed twin, at most 8 hours)
pbx twin access list TWIN [--all]a twin’s web access grants
pbx twin access revoke TWIN GRANTrevoke a twin’s web access grant
CommandWhat it does
pbx env copy PRODUCTIONwhether twins may hold a copy of a production host’s data, masked or not, and who set it
pbx env copy allow PRODUCTION --reason R [--mask required|waived] [--confirm NAME]allow copies of production’s data in twins (owner, presence device; the hub’s warning is shown, the name typed)
pbx env copy forbid PRODUCTION [--confirm NAME]forbid copies again (owner)
pbx dns statusthe twins’ DNS zone, base name, wildcard record and certificate (owner)
pbx dns setup --zone ZONE [--base NAME] [--email E] [--accept-terms] [--caa]name twins <task>.<base> from a zone in Hetzner’s Cloud DNS (owner); the token from --dns-token-file F or --dns-hcloud-context C
pbx dns verifycheck the zone and the wildcard record again (owner)
CommandWhat it does
pbx approvals [--all]what agents and capped devices asked a person to approve
pbx approve ID [--confirm NAME]approve one, signed with this device’s key (presence only)
pbx reject IDreject one
pbx api METHOD PATH [JSON|-]one signed request to the hub’s API
pbx versionthe version

A long-lived pbx (pbx open, pbx open twin, pbx open host) shares its tunnel to the hub with the other pbx runs of the same user, hub and device while it runs, on a socket only that user can open. Each run still speaks TLS to the hub and signs its own requests; only the transport is shared. Without a long-lived pbx, each run opens its own tunnel. pbx status and pbx hub list show the link: open via pbx open (pid …) with the last handshake’s age, or none. Windows shares no link: there, run one long-lived pbx per device.

VariableWhat it does
PBX_HUBthe hub a command talks to, over the default; --hub wins
PBX_AGENTagent mode for every run, as --agent; set it in the agent’s environment
PBX_AGENT_SESSIONthe agent’s session in the audit; default: one per pbx run
PBX_LINK_SHAREoff: neither use nor publish a shared link for this run
PBX_HOMEone directory for all of pbx’s files
PBX_PASSPHRASE_FILE, PBX_PASSPHRASEthe device key file’s passphrase, as --passphrase-file (level passphrase-stored)
PBX_CLEVIS_CONFIG, PBX_CLEVIS_PINthe Tang server (and sss with the TPM) for a key file unlocked by Tang (level tang)
PBX_NO_BROWSERset: print links instead of opening a browser
HCLOUD_TOKEN, HCLOUD_CONFIGthe Hetzner token, or the hcloud CLI’s config for --hcloud-context
PBX_PORTAL, PBX_RELEASESanother portal or release server, for a lab

Without PBX_HOME, the files are in ~/Library/Application Support/pbx on macOS, %LOCALAPPDATA%\pbx on Windows, and the XDG directories on Linux.

CodeMeaning
0ok
1failed
2usage
3the hub answered with a status other than 2xx
4refused by policy: a ceiling, the protection level, or a person’s command run with PBX_AGENT
5waiting for a person’s approval; the approval’s id is printed (with --output json, the approval on stdout)