phonebase. Install it globally, then log in:
phonebase login prints a link and a short code and opens your browser. Sign
in to the console, check that the page shows the same code, and approve. The
terminal then prints the organization you logged in to, the id of the key it
received and when that key expires. No browser on this machine, or connected
over SSH? Open the link on any other device where you are signed in; the
terminal waits until the code expires, ten minutes after it was printed.
Check
phonebase --version. If it prints 0.1.3 or 0.2.0, upgrade with the
command above. 0.1.3 writes a run’s worker URL, which carries the run token,
to stderr whatever stderr is attached to, including a CI job log. 0.2.0
exits without printing anything. 0.2.1 has neither problem: phonebase run
refuses up front when stderr is not a terminal and would have printed the
URL. One gap remains on 0.2.1: with an API key, phonebase run --watch
without --executor starts a self_hosted run and waits on it until its
deadline, holding the device, because no worker connects. Pass
--executor phonebase. From 0.3.0 --watch refuses
or cancels that run and exits 2. See the changelog.Installing the CLI gives you the client, not access.
phonebase login needs
a console account in an organization: request access through
phonebase.co. Nothing on this surface requires the
CLI, so if you are integrating rather than operating, start at
Quickstart and treat this page as optional.Logging in
Whatphonebase login gives you is an ordinary API key for your
organization, the same kind the console’s /keys screen mints, named after
this computer so you can find it there. It is stored in the system keychain:
the macOS Keychain, or the Secret Service through secret-tool on Linux.
Where neither is available it goes to ~/.config/phonebase/credentials.json,
readable only by you. The CLI never prints it.
phonebase login again. You can also delete any key from the console’s
/keys screen; logout does both halves for the key this machine holds, and
if the server cannot be reached it still forgets the key here and tells you
it is still live, so you can delete it in the console.
Already have a key? phonebase login --with-key < key.txt checks it with the
server and stores it without the browser step.
Prerequisites
- Node 22 or newer. The published package declares
engines: { "node": ">=22" }, so annpm install -gon Node 20 or 21 is refused outright underengine-strict. The CLI refuses to pretend an older runtime is fine either:doctorreports it as a failure with the fix.
Running from source
pnpm cli runs the CLI straight from TypeScript with no build step. This is
the right mode while you are working on the repository, because an edit takes
effect on the next command.
cli is passed through, so flags work as documented:
Running the built entry point
Building compiles the repository intodist.
dist/cli/main.js is the same entry point the published package ships: inside
the package it sits at cli/main.js, which is what the manifest declares as
the phonebase binary. So this is the same program the npm install gives you:
same parser, same client, same control plane.
Configuring it
Two things. Which control plane. Defaults to the hosted one,https://mcp.phonebase.co. A control plane running on your own machine, for
example a robot hand rig, is --server http://127.0.0.1:8788; to make that
the default for a shell, set PHONEBASE_SERVER=http://127.0.0.1:8788. A
--server flag always beats the variable. Each server keeps its own login,
so logging in to a local one does not replace your hosted key.
Which credential. In order: PHONEBASE_API_KEY from the environment, then
the key phonebase login stored for that server, then PHONEBASE_DEV_TOKEN
(a local control plane’s dev token). The dev token is only ever sent to a
loopback server: aimed at any other, the command refuses rather than send it. Use the variable in CI and scripts, where
nobody is there to approve a login:
phonebase whoami names which of the three it is using.
From a checkout,
corepack pnpm cli substitutes for phonebase in every
command below. It is the same program either way.https, or unset both for an unauthenticated call.
Checking the install
doctor runs the checks that catch the setup problems people actually hit, and
exits non zero if any of them fail.
/healthz, whether the
credential in use is accepted and where it came from, and whether the Android
tooling is present. Missing Android tooling is informational
rather than a failure, because the mechanical actuator path does not need it.
Each failing check prints its own fix. Start there before anything else.
Registering a device
The CLI is also how a control plane running on your own machine learns which devices exist. The hosted fleet does not need this. Rows live in a JSON file the CLI manages for you:backendKind must be one of the kinds in
Capabilities, and what belongs in metadata depends
on the kind: a device addressed by configuration needs the address the control
plane should reach it at.
If PHONEBASE_DEVICE_ROWS is set in your environment it takes precedence over
the file, and the CLI warns you that it did, so a forgotten variable does not
silently shadow the rows you just edited.
A control plane started over stdio reads device rows once at startup. If
you add a row while an MCP client has one running, restart the client. The
HTTP control plane rereads rows on every request.