# The Pilot CLI

Source: https://pilot.braike.com/en/docs/cli

Connect Pilot MCP from the terminal with the pilot command. Sign-in, setup in your assistants, stdio bridge, skills, tool calls and diagnostics.



The Pilot CLI (`@braike/pilot`, command `pilot`) connects Pilot MCP from your terminal, without copying any configuration by hand. It signs you in through your browser, registers the Pilot server in your assistants, bridges clients that only start local programs, installs the skills, and queries Pilot from a script.

## Install [#installer]

You need Node.js 20 or later. Without installing anything, `npx` downloads the CLI and runs it:

```bash title="Terminal"
npx @braike/pilot setup
```

To keep the `pilot` command at hand, install it once and for all:

```bash title="Terminal"
npm install -g @braike/pilot
pilot --version
```

The examples on this page write `pilot`; with `npx`, replace `pilot` with `npx @braike/pilot`.

## In two commands [#demarrage]

```bash title="Terminal"
npx @braike/pilot login
npx @braike/pilot setup
```

`login` opens Pilot's authorization screen in your browser; `setup` finds the assistants installed on your computer and registers Pilot in them. Then restart your assistant and ask it a question.

## Commands [#commandes]

### `pilot login` [#login]

Opens the Pilot sign-in in your browser (OAuth 2.1). You choose the workspace to share and keep the **Read** level, as for an assistant (see [the authorization screen](/en/docs/brancher-son-assistant#autorisation)). The CLI then keeps the token it receives on your computer.

```bash title="Terminal"
pilot login
pilot login --workspace <workspace id>
pilot login --no-browser
```

`--workspace` locks the authorization to one workspace, like a workspace address. `--no-browser` prints the address to open instead of opening the browser, for example on a server.

### `pilot logout` [#logout]

Revokes the CLI's access with Pilot, then deletes the tokens kept on this computer. Without `--workspace`, every sign-in for the address.

```bash title="Terminal"
pilot logout
pilot logout --workspace <workspace id>
```

When Pilot cannot answer (unavailable, network), the sign-in is kept and the command fails, to be run again. `--force` forgets it on this computer anyway.

### `pilot status` [#status]

Tells whether the CLI is signed in, to which address, for which workspace, at which level, until when, and whether it can renew the token by itself. It never shows a token, and returns exit code 1 when no sign-in is usable.

```bash title="Terminal"
pilot status
```

### `pilot setup` [#setup]

Registers the Pilot server in the assistants found on your computer. Without `--client`, the CLI registers it in each of them; `--all` says so explicitly.

```bash title="Terminal"
pilot setup
pilot setup --client cursor
pilot setup --client claude-code --client vscode
pilot setup --client cursor --dry-run
pilot setup --client generic
```

| Option | Effect |
| --- | --- |
| `--client <name>` | Registers Pilot in this assistant only; can be repeated. |
| `--all` | Registers Pilot in every assistant found. |
| `--workspace <id>` | Registers a workspace address, `https://app.pilot.braike.com/mcp/<id>`. |
| `--transport remote` or `stdio` | Remote address, or the local `pilot mcp` bridge for every assistant. |
| `--name <name>` | Names the entry something other than `pilot`, for example one entry per workspace. |
| `--dry-run` | Shows the change without writing anything, and the real file when a link leads to it. |
| `--force` | Writes anyway in the three cases left to you (see below). |

Supported assistants, the name to give `--client`, and what the CLI writes:

| Assistant | `--client` | What the CLI writes |
| --- | --- | --- |
| Claude Desktop | `claude-desktop` | the local bridge, in `claude_desktop_config.json` |
| Claude Code | `claude-code` | `claude mcp add --transport http --scope user` when the `claude` command is installed, otherwise `~/.claude.json` |
| Cursor | `cursor` | `~/.cursor/mcp.json` |
| VS Code | `vscode` | the `mcp.json` file of your user profile |
| VS Code Insiders | `vscode-insiders` | the same, in the `Code - Insiders` folder |
| Windsurf (Devin Desktop) | `windsurf` | `~/.config/devin/mcp_config.json`, and `~/.codeium/windsurf/mcp_config.json` for an install from before the rename |
| Codex and the ChatGPT desktop app | `codex` | `~/.codex/config.toml` |
| Gemini CLI | `gemini` | `~/.gemini/settings.json` |
| Any other MCP client | `generic` | nothing: the CLI prints the configuration to copy |

An assistant that speaks remote MCP gets Pilot's address and signs in by itself on first use, through the same authorization screen: Claude Code with `/mcp` (or `claude mcp login pilot`), Codex with `codex mcp login pilot`, Gemini CLI with `/mcp auth pilot`; Cursor, VS Code and Windsurf open the authorization page on first use. Claude Desktop's configuration only holds local servers: it gets the `pilot mcp` bridge, signed in by `pilot login`. Claude on claude.ai and ChatGPT in the browser connect from their own interface: see [Connect your assistant](/en/docs/brancher-son-assistant).

Before changing a file, the CLI keeps a dated copy of it in `~/.config/pilot/backups/`; run again, it creates no duplicate. Only the Pilot entry changes: a JSON file is written again with its own indentation, and in Codex's TOML only the Pilot table changes. Three cases are left to you, unless `--force`:

- a file whose real path, links followed, leads outside your home folder and the configuration folders (`XDG_CONFIG_HOME`, `APPDATA`, `LOCALAPPDATA`, `CODEX_HOME`, `CLAUDE_CONFIG_DIR`);
- an entry with the same name that is not Pilot's: choose another name with `--name`;
- a JSON file with comments, which `--force` writes again without them.

### `pilot remove` [#remove]

Removes the Pilot entry from the assistants' configuration, leaving the rest untouched. An entry with the same name that is not Pilot's stays, unless `--force`.

```bash title="Terminal"
pilot remove --client cursor
pilot remove --all --dry-run
```

Options: `--client <name>`, `--all`, `--name <name>`, `--dry-run`, `--force`.

### `pilot mcp` [#mcp]

Starts a local stdio MCP server that relays Pilot's remote server: the bridge for assistants that can only start a local program. In such an assistant's configuration:

```json title="stdio client configuration"
{
  "mcpServers": {
    "pilot": {
      "command": "npx",
      "args": ["-y", "@braike/pilot", "mcp"]
    }
  }
}
```

- **Credential**: the [access key](/en/docs/brancher-son-assistant#autres) in the `PILOT_API_KEY` variable when it is set, otherwise the `pilot login` sign-in, read again at every request: a sign-in made elsewhere serves at once. The bridge renews the token before it expires.
- **Without a sign-in**, the bridge opens the Pilot sign-in in your browser by itself and answers the assistant with an error while you sign in; then try again. When no browser can open (a server, `PILOT_NO_BROWSER`), each request gets an error that says to run `npx @braike/pilot login`.
- **A specific workspace**: `--workspace <id>`, or the `PILOT_WORKSPACE` variable.

### `pilot tools` [#tools]

Lists the tools Pilot serves you, one per line.

```bash title="Terminal"
pilot tools
pilot tools --json | jq '.[].name'
```

### `pilot call` [#call]

Calls a tool and prints its response. A tool in error returns exit code 1, for scripts.

```bash title="Terminal"
pilot call pilot_data_freshness
pilot call google_get_campaign_performance --arg customer_id=1234567890 --arg date_range=LAST_7_DAYS
pilot call google_analytics_run_report --json-args '{"dateRanges":[{"startDate":"28daysAgo","endDate":"yesterday"}],"dimensions":["sessionDefaultChannelGroup"],"metrics":["sessions"]}'
```

`--arg key=value` can be repeated and follows the type the tool's schema declares: a number, a boolean, an array or an object are read as such, anything else stays text. `--arg key:=<json>` passes a JSON value as is. `--json-args` passes an object, which `--arg` values complete or override. The tools and their parameters are on [Ad platforms and their tools](/en/docs/regies).

### `pilot skills list` and `pilot skills install` [#skills]

Lists the [skills](/en/docs/skills) catalogue and installs them where your assistant reads them.

```bash title="Terminal"
pilot skills list
pilot skills install
pilot skills install google-ads-account-audit --target claude-code
pilot skills install --target claude --out ./archives
pilot skills install --target ./.github/skills
```

| `--target` | Where |
| --- | --- |
| `claude-code` | `~/.claude/skills/<skill>/` |
| `codex` | `~/.agents/skills/<skill>/`, read by Codex and the ChatGPT desktop app |
| `cursor` | `~/.cursor/skills/<skill>/` |
| `claude` | a `<skill>.zip` archive in `--out` (the current folder by default), to upload in Claude: **Customize**, **Skills**, **+**, **+ Create skill**, **Upload a skill** |
| a path | that folder, for example `./.github/skills` for VS Code |

Without a skill name, the CLI installs the whole catalogue; without `--target`, it installs in every assistant found among Claude Code, Codex and Cursor. It replaces a skill's folder as a whole; a folder edited by hand since its installation is left as is, unless `--force`. `--dry-run` shows what would be installed.

The CLI reads the catalogue this documentation publishes, `https://pilot.braike.com/skills/index.json`, and checks each file's size and SHA-256 fingerprint before writing: one mismatch refuses the whole skill.

### `pilot doctor` [#doctor]

Checks your setup: Node.js version, the CLI version against the latest published, network access, discovery of Pilot's sign-in, your credential, and the configured assistants. A newer version is only a warning, with the update command. A failed check returns exit code 1. See [Troubleshooting](#depannage).

```bash title="Terminal"
pilot doctor
```

### `pilot open` [#open]

Opens your workspace console, the **Claude & ChatGPT** page, in your browser; without a known workspace, the list of your workspaces. `--no-browser` prints the address.

```bash title="Terminal"
pilot open
pilot open --workspace <workspace id>
```

`pilot --version` gives the version, `pilot help <command>` the help for a command.

## Common options [#options]

| Option | Effect |
| --- | --- |
| `--base-url <address>` | Pilot's address (default `https://app.pilot.braike.com`). The CLI refuses any address that is not Pilot's. |
| `--allow-local` | Accepts a local address (`http://localhost:3000`), for development only. |
| `--json` | JSON output, for scripts. |
| `--lang fr` or `en` | Language of the messages; otherwise `PILOT_LANG`, then your system's language. |
| `--verbose` | Details what the CLI does, without ever showing a token, a key or a secret. |
| `-h`, `--help` | Help for the command. |

## Environment variables [#environnement]

| Variable | Use |
| --- | --- |
| `PILOT_API_KEY` | An access key (`ulys_...`), used by `mcp`, `tools`, `call` and `doctor` instead of the sign-in. |
| `PILOT_WORKSPACE` | The workspace, when `--workspace` is not given. |
| `PILOT_BASE_URL` | Pilot's address, when `--base-url` is not given. |
| `PILOT_CONFIG_DIR` | The CLI's folder instead of `~/.config/pilot`. |
| `PILOT_LANG` | `fr` or `en`. |
| `PILOT_NO_BROWSER` | `1`: never opens a browser (also the case on a Linux machine without a display). |
| `PILOT_LOGIN_TIMEOUT_MS` | How long a sign-in waits for the browser, in milliseconds (5 minutes by default). |
| `npm_config_registry` | The registry `doctor` asks for the latest version (npm's by default). |

## Exit codes [#codes-de-sortie]

| Code | Meaning |
| --- | --- |
| `0` | Success. |
| `1` | Failure: a tool in error, no usable sign-in for `status`, a sign-in kept by `logout` because Pilot could not answer, a file left to you by `setup` or `remove`, a failed `doctor` check. |
| `2` | Usage error: unknown command or option, missing value. |

## Security [#securite]

- **Your tokens stay with you**, in `~/.config/pilot/credentials.json`: a folder only you can read (permissions 0700, file 0600), written in one go. Loosened permissions are tightened again; on Windows, the protection of your user profile applies.
- **A token only goes to the address that issued it.** The authorization server's metadata must name the address you chose, and each of its endpoints must belong to it, or the sign-in is refused. Redirections are never followed.
- **Only Pilot's addresses**, over HTTPS; a local address only with `--allow-local`.
- **OAuth 2.1 sign-in**: PKCE `S256` and a checked `state`, return to `http://127.0.0.1` on a random port, a client registered once then reused, resource indicator. `pilot logout` revokes the tokens, and a new sign-in revokes, when it can, the token it replaces.
- **Nothing shown**: no token, no key, no code or secret, even with `--verbose`. Control sequences in text that comes from a server are removed.
- **Your configurations protected**: a dated copy before any change, only the Pilot entry changes, no write outside your folders or over someone else's entry without `--force`, and `--dry-run` to see first.
- **No dependency**: the package relies on Node.js alone, with no other npm package: no third-party package touches your tokens.

## Troubleshooting [#depannage]

Run `pilot doctor` first: each failed check says where to look.

<Accordions>
<Accordion title="Node.js is too old">

The CLI requires Node.js 20 or later. Check with `node --version`, then update Node.js.

</Accordion>
<Accordion title="A newer version is published">

`pilot doctor` says so with the update command: `npm install -g @braike/pilot@latest`. With `npx`, the latest version is taken by itself.

</Accordion>
<Accordion title="The token is missing or no longer valid">

Sign in again with `pilot login`. If your access was removed in the console, the old token no longer works. `pilot status` tells whether a sign-in is still usable.

</Accordion>
<Accordion title="The assistant answers that Pilot is waiting for a sign-in">

The `pilot mcp` bridge opened the sign-in in your browser: finish it, then ask your question again. If no window opened, run `npx @braike/pilot login`.

</Accordion>
<Accordion title="setup leaves a file to you">

The message says why: a `pilot` entry that is not Pilot's (choose another name with `--name`), a file with comments, or a file outside your folders. `--dry-run` shows the change; `--force` writes it anyway.

</Accordion>
<Accordion title="An assistant is not configured">

Run `pilot setup --client <name>` again, adding `--dry-run` to see the change, then restart the assistant. `pilot remove --client <name>` removes the registration if you want to start over.

</Accordion>
<Accordion title="The network or the sign-in discovery fails">

Check the address: `https://app.pilot.braike.com`, with `app.`. Behind a corporate proxy, ask for access to `app.pilot.braike.com`. `--verbose` details the failing request, without secrets.

</Accordion>
<Accordion title="The assistant does not see an ad platform's tools">

`pilot tools` lists what Pilot serves you. A missing platform is not connected to the workspace, has no account chosen, or is not included in your plan: see [Errors and troubleshooting](/en/docs/erreurs#depannage).

</Accordion>
</Accordions>
