> ## Documentation Index
> Fetch the complete documentation index at: https://docs.phoneuse.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Installation

> Install the CLI from npm, or run it from a checkout.

The CLI is published to npm as `phonebase`. Install it globally, then log in:

```bash theme={null}
npm install -g phonebase
phonebase login
```

`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.

<Note>
  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](/changelog).
</Note>

<Note>
  Installing the CLI gives you the client, not access. `phonebase login` needs
  a console account in an organization: request access through
  [phonebase.co](https://phonebase.co). Nothing on this surface requires the
  CLI, so if you are integrating rather than operating, start at
  [Quickstart](/quickstart) and treat this page as optional.
</Note>

## Logging in

What `phonebase 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.

```bash theme={null}
phonebase whoami    # organization, key id, scopes, expiry, and where the key came from
phonebase logout    # revoke the key on the server and forget it here
```

Need a new key, say after it expired or on a new machine? Run
`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 an `npm install -g` on Node 20 or 21 is refused outright under
  `engine-strict`. The CLI refuses to pretend an older runtime is fine either:
  `doctor` reports it as a failure with the fix.

That is the whole list for an npm install. The two sections below are for
people working in the repository, which is private: they apply to you only if
you already have a checkout.

```bash theme={null}
corepack enable
corepack pnpm install --frozen-lockfile
```

## 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.

```bash theme={null}
corepack pnpm cli --help
phonebase doctor
```

Everything after `cli` is passed through, so flags work as documented:

```bash theme={null}
corepack pnpm cli devices --json
corepack pnpm cli devices --server https://<your-control-plane>
```

## Running the built entry point

Building compiles the repository into `dist`.

```bash theme={null}
corepack pnpm build
node dist/cli/main.js doctor
```

`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:

```bash theme={null}
export PHONEBASE_API_KEY="pbk_..."
phonebase devices
```

`phonebase whoami` names which of the three it is using.

<Note>
  From a checkout, `corepack pnpm cli` substitutes for `phonebase` in every
  command below. It is the same program either way.
</Note>

Sending either credential in the clear to a non loopback server is refused. Use
`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.

```bash theme={null}
phonebase doctor
```

It reports on your Node version, whether your device rows parse and where they
were read from, whether the control plane answers on `/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:

```bash theme={null}
phonebase rows list
phonebase rows add '{"deviceId":"black-arm-01","backendKind":"robot_hand","metadata":{"baseUrl":"http://127.0.0.1:8790/visualremote/v1"}}'
phonebase rows remove black-arm-01
```

`backendKind` must be one of the kinds in
[Capabilities](/devices/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.

<Note>
  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.
</Note>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.