# Dbrij CLI Documentation

The complete reference for the dbrij command line tool: sign in, link a folder, deploy, logs and variables, Secrets, Ship releases, the git credential helper and the local MCP server for AI coding tools.

Canonical page: https://dbrij.com/developers/cli

## Introduction

`dbrij` is the Dbrij command line tool. It deploys a folder on your machine to Dbrij Hosting, reads and changes a service's variables and logs, runs your app with its Dbrij Secrets opened on your own machine, ships over the air releases with Dbrij Ship, signs git in to Dbrij Source, and runs a local MCP server so an AI coding tool can do the same for you.

What is on disk is what ships. There is no repository to connect and no webhook: `dbrij deploy` packs the folder, uploads it straight to storage and asks Dbrij to build it.

From nothing to a deployed folder

```
npm i -g dbrij

dbrij login      # confirm the code in your browser
dbrij link       # point this folder at a service
dbrij deploy     # ship it
```

Every command talks to the Dbrij API at `https://api.dbrij.com/api/v1` with the token `dbrij login` saved. It acts as you, through the same API the dashboard uses, so every permission, plan limit and card rule applies unchanged.

COMMANDS

|  |  |  |
| --- | --- | --- |
| dbrij login | command | Sign in through your browser. --force signs in again as someone else. |
| dbrij logout | command | Revoke this machine’s token and forget it. |
| dbrij whoami | command | Who you are signed in as. |
| dbrij link | command | Point this folder at a Hosting service, creating the project or service if you ask. |
| dbrij deploy | command | Pack, upload, build and roll out this folder. |
| dbrij status | command | The linked service’s state and its last five deployments. |
| dbrij logs | command | Runtime logs. --build for a build log. |
| dbrij url | command | Give the service its free public URL, or show the one it has. |
| dbrij open | command | Open the deployed site in your browser. |
| dbrij ls | command | Every project and service you can reach. Also dbrij list. |
| dbrij rollback | command | Put a previous build back without rebuilding. |
| dbrij env | command | List, add, remove and pull the service’s variables. |
| dbrij secrets | command | Dbrij Secrets on this machine. dbrij secrets help lists everything. |
| dbrij ship | command | Over the air releases with Dbrij Ship. |
| dbrij git setup | command | Push to Dbrij Source with your Dbrij sign in. |
| dbrij mcp | command | Run the local MCP server for an AI coding tool. |
| dbrij help | command | The command list. Also dbrij, dbrij --help and dbrij -h. |
| dbrij --version | command | The installed version. Also dbrij -v and dbrij version. |

## Install

The CLI is the `dbrij` package on npm and needs Node.js 20 or newer. Installing it puts one command on your path, `dbrij`.

Install it globally

```
npm i -g dbrij
dbrij --version
```

Or run it without installing, which is what CI jobs and AI coding tools usually do:

Run it through npx

```
npx dbrij deploy
npx -y dbrij mcp
```

Server access through `dbrij secrets access` uses the WebSocket built into Node.js 22, so that one family of commands needs Node.js 22 or newer.

`dbrij help` prints the command list and `dbrij secrets help` the full Secrets list. Both exit 0. An unknown command prints `Unknown command` and exits 1.

## Signing in

`dbrij login` uses the device authorization flow. The terminal shows a short confirmation code and an address, and opens that address in your browser. You check the code matches, confirm it in the browser where you are already signed in, and the terminal receives a token. Your password never touches the terminal, and a machine with no browser (a server, a container) can be confirmed from your phone by opening the printed address.

dbrij login

```
$ dbrij login

  Confirmation code: <the code>
  Open: <the address>

  Check the code in the browser matches the one above before confirming.

✓ Signed in as you@example.com.
```

- The CLI asks for the code as `Dbrij CLI on` followed by your machine's host name, so you can tell your machines apart.
- It checks with Dbrij at the interval the server sets (never more often than every two seconds) until the code expires.
- A network error while it waits does not end the sign in; it keeps waiting.
- Refused in the browser, expired, or timed out: it says so and exits 1. Run `dbrij login` again.
- Already signed in: it says as whom and exits 0. `dbrij login --force` signs in again, as someone else if you like.

The token is saved in `~/.dbrij/auth.json`, readable only by you (mode 600), with the API address and your name and email. When `DBRIJ_TOKEN` is set, it is used instead of the file and nothing is written.

ACCOUNT COMMANDS

|  |  |  |
| --- | --- | --- |
| dbrij login [--force] | command | Sign in. --force signs in even when a token is already saved. |
| dbrij logout | command | Revokes the token on Dbrij first, then deletes ~/.dbrij/auth.json and the cached Source push token. Not signed in: says so and exits 0. |
| dbrij whoami | command | Prints your name, email and username. |

### In CI

Set `DBRIJ_TOKEN` and skip `dbrij login`. A token from the environment always wins over a saved file, so a file left on a shared machine can never stand in for the credential the job was given.

A pipeline step

```
- run: npx dbrij deploy --no-wait --no-url
  env:
    DBRIJ_TOKEN: ${{ secrets.DBRIJ_TOKEN }}
```

## Linking a folder

`dbrij link` points the current folder at one Hosting service. It is interactive: it lists every project you can deploy to, in your personal space and in every company you belong to, and asks which one. Answer with a number, or `n` to create a new one. Nothing is chosen for you, even when there is only one option.

1. **Project.** Pick one, or create one. A new project's name defaults to the folder's name, lowercased, with anything other than letters, digits and dashes turned into dashes, up to 40 characters. If you belong to a company you are asked which space it belongs to: personal, or one of your companies.
2. **Service.** Only services that take uploads are listed, since those are the ones `dbrij deploy` can ship to. A new service is a web service that takes uploads, named the same way.

An answer that is not one of the options stops the command with exit 1, and nothing is created. Run `dbrij link` again. In a folder that is already linked it asks whether to link somewhere else; anything but `y` keeps the current link.

.dbrij/project.json

```
{
  "projectId": "6f1c…",
  "serviceId": "a93e…",
  "projectName": "shop",
  "serviceName": "web"
}
```

The link lives in `.dbrij/project.json`. Next to it the CLI writes `.dbrij/.gitignore` (when there is none), which keeps everything in `.dbrij` out of git except `secrets.toml`. A link is a fact about one checkout on one machine, so it is not meant to be committed.

Every command that needs a link looks for `.dbrij/project.json` in the current folder and then in each parent folder, as git does, so `dbrij deploy` works from anywhere inside a linked project. The folder that holds the link is the one that ships.

## Deploying

`dbrij deploy` ships the linked folder. In order: it asks the API for an upload address (so a service that cannot take the upload fails in a second, before anything is read), packs the folder into a compressed archive, uploads it straight to storage with that address (the archive never passes through the API, and carries no Dbrij credential), then starts the build and watches it.

Deploy with a label

```
dbrij deploy -m "New checkout page"
```

FLAGS

|  |  |  |
| --- | --- | --- |
| -m, --message <text> | string | A label for the deployment, shown in status and the dashboard. --message=text works too. |
| --no-wait | switch | Start the build and return at once with the deployment id, instead of watching it. |
| --url | switch | Give the service its free public URL once the build succeeds, without asking. |
| --no-url | switch | Never ask about a public URL and do not create one. |

### The public URL question

A web service with no URL yet is asked, before the build starts, whether it should get a public URL when it deploys (the default answer is yes). The URL is only created after a successful build, so a failed deploy never leaves a hostname pointing at nothing. Without `--url` or `--no-url`, the question is only asked when there is a terminal: with no terminal on stdin, or with `CI` set, the answer is no. A service that already has a URL, or is not a web service, is never asked. Change your mind later with `dbrij url`.

### Watching the build

Without `--no-wait` the CLI checks every two and a half seconds and shows where the deployment is: queued, waiting for a build slot, building, rolling out. A free plan deploy can wait for a build slot while paid ones build; that wait is shown, and does not count against the watch. The CLI stops watching after 25 minutes of work; the deployment is not cancelled, it says so and exits 1. A dropped connection while watching is not a failed build: it keeps watching.

- **Success:** prints `Deployed.` and the URL (a certificate can take a minute on a new hostname). Exit 0.
- **Failure:** prints the error, Dbrij's plain reading of what went wrong, up to six matching lines of the build log, what usually fixes it, and the command for the full log (`dbrij logs --build` and the deployment's id). Exit 1.
- **Cancelled or replaced by a newer deployment:** says so. Exit 1.

### What gets uploaded

Every file in the linked folder, minus three layers of rules, applied in this order:

1. **Always left out:** installed dependencies (`node_modules`, `vendor`, `.venv`, `venv`, `.bundle`), version control and build output (`.git`, `.next`, `.nuxt`, `.turbo`, `.cache`, `dist`, `build`, `target`, `coverage`), language caches (`__pycache__`, `*.pyc`, `.pytest_cache`, `.mypy_cache`, `.ruff_cache`, `.tox`, `*.egg-info`, `.gradle`, `.phpunit.result.cache`, Laravel's `bootstrap/cache` and `storage/framework` caches and `storage/logs`), `.DS_Store`, `.dbrij`, and secrets: `.env`, `.env.local`, `.env.*.local`, `*.pem`, `*.key` and `id_rsa`.
2. The folder's own `.gitignore`.
3. The folder's `.dbrijignore`, if there is one.

A later rule wins, so a `!pattern` in `.dbrijignore` can ship something git ignores, even something on the always left out list. Nothing secret goes up by accident; sending it is a line somebody had to write. Only the ignore files at the root of the linked folder are read.

Both files use gitignore patterns: `#` starts a comment, `*` matches within one folder name, `**` crosses folders, `?` is one character, a trailing `/` matches folders only, a leading `/` or a slash inside the pattern anchors it to the root, and a pattern with no slash matches at any depth.

.dbrijignore

```
# Large local data the build does not need
fixtures/large/
*.mp4

# Ship a build output that .gitignore leaves out
!public/generated/
```

The archive has a size limit the API sets per upload. A packed folder over it fails with its size and the limit; a folder far over it (ten times the limit, before compression) stops while packing. Either way, add what you do not need to `.dbrijignore`. A folder where every file is ignored fails with `Nothing to deploy`. Files are packed in sorted order, so the same folder makes the same archive on any machine.

## Status, logs and rollback

Each of these works on the service the current folder is linked to, and exits 1 with an instruction to run `dbrij link` when there is none (except `dbrij ls`, which needs no link).

COMMANDS

|  |  |  |
| --- | --- | --- |
| dbrij status | command | The service name and state, its URL, and its last five deployments: the first eight characters of each id, its status, when it was created and its label. |
| dbrij logs | command | What the running service printed recently. |
| dbrij logs --build [id] | command | The build log of the newest deployment, or of the one you name. The eight character id prefix status prints is enough; --build=id works too. No deployments yet: exit 1. |
| dbrij url | command | Prints the service’s URL, or creates its free public URL when it has none. Only web services get one: anything else exits 1. |
| dbrij open | command | Prints the URL and opens it in your browser. No URL yet: exit 1. |
| dbrij ls | command | Every project you can reach, in every space, with each service’s status and URL. Also dbrij list. |
| dbrij rollback [id] | command | Puts a previous build back without rebuilding. Without an id, the newest successful build that is not the one running now. With an id (or its prefix), that deployment. Nothing to go back to: exit 1. |

A failed build

```
dbrij status
dbrij logs --build 3f2a9c1e
dbrij rollback
```

A build that failed before it wrote anything has no log to show. `dbrij logs --build` then says the build produced no output, with the error and the first line Dbrij matched, instead of an empty screen.

## Environment variables

`dbrij env` reads and changes the linked service's environment variables. Values are never printed: the list shows names only, because this gets run in shared terminals and on shared screens.

COMMANDS

|  |  |  |
| --- | --- | --- |
| dbrij env | command | The variable names, values hidden. Also dbrij env ls and dbrij env list. |
| dbrij env add KEY=value | command | Set one variable. Everything after add is read as one KEY=value, so a value may hold spaces. Also dbrij env set. It applies on the next deploy. |
| dbrij env rm KEY | command | Remove one variable. Also dbrij env remove. A name the service does not have: exit 1. |
| dbrij env pull [file] | command | Write every variable with its value to a local file, .env.dbrij unless you name one, readable only by you (mode 600). |

Set, remove and pull

```
dbrij env add DATABASE_POOL=10
dbrij env rm OLD_FLAG
dbrij env pull .env.local
```

A change touches only the names you give. Dbrij merges it on the server, so a variable someone else changed in the meantime (a teammate, an assistant, another terminal) is kept.

`dbrij env pull` quotes any value with a line break, a `#` or spaces around it, so the file reads back exactly as it was. The file now holds real secrets: the CLI warns you, and it is not added to `.gitignore` for you.

## Secrets

`dbrij secrets` reads an environment from Dbrij Secrets and opens it on this machine. Values are sealed before they reach Dbrij, which cannot open them; the CLI opens them here, with your vault key (people, after `dbrij login`) or the key half of a machine token (servers and CI).

Run your app with its secrets

```
dbrij login
dbrij secrets link --project my-app --env development
dbrij secrets run -- npm start
```

USE THEM

|  |  |  |
| --- | --- | --- |
| dbrij secrets run -- CMD | command | Start a command with the secrets in its environment. Everything after -- belongs to the command. --watch restarts it when the secrets change. |
| dbrij secrets export | command | Print every secret. --format env, json, yaml, docker or shell (env by default). --out FILE writes a file readable only by you; --force replaces one that exists. |
| dbrij secrets get NAME | command | Print one value. --plain prints it with no line break after. A name that is not there: exit 1. |

CHANGE THEM

|  |  |  |
| --- | --- | --- |
| dbrij secrets set NAME=value … | command | Save one or more. set NAME alone reads the value from stdin (one at most), without its last line break. --template saves a value with ${…} references, filled in where it is read. |
| dbrij secrets delete NAME … | command | Remove one or more. Also dbrij secrets rm. |
| dbrij secrets diff | command | Compare with a local file (.env unless --file). Values are hidden unless --show-values. --exit-code exits 1 when they differ. |
| dbrij secrets pull | command | Write the secrets to a local .env (or --file), readable only by you. --force replaces a file that exists. |
| dbrij secrets push | command | Save a local file (.env unless --file) into the environment: new and changed names. --prune also deletes names the file lacks. --format dotenv, json, yaml or csv; otherwise read from the file extension. |

SET UP

|  |  |  |
| --- | --- | --- |
| dbrij secrets link | command | Remember the project and environment for this folder in .dbrij/secrets.toml. Needs --project and --env; also takes --space and --path. |
| dbrij secrets status | command | Who is reading, and against which API. With a project and environment, your role there and how long your vault key stays unlocked; this also unlocks it. |
| dbrij secrets lock | command | Forget the unlocked vault key, the device key and the local copies on this device. |
| dbrij secrets help | command | Every subcommand and flag. Also --help and -h. |

### Choosing what to read

Each value is taken from the first place that has it: the flag, then the environment variable, then the nearest `.dbrij/secrets.toml`.

FLAGS

|  |  |  |
| --- | --- | --- |
| --project NAME | DBRIJ_SECRETS_PROJECT | The project’s short name, as in Dbrij Secrets. |
| --env NAME | DBRIJ_SECRETS_ENV | The environment’s short name. |
| --space ID | DBRIJ_SECRETS_SPACE | A company space id. Leave it out for your personal space. |
| --path /api | DBRIJ_SECRETS_PATH | A folder to read; repeat it for several, merged in order, a later folder winning. The variable takes a comma separated list. The top level / by default. |
| --recursive | switch | Read the folders inside the named folders too. |
| --watch | switch | run only: restart the command when the secrets change. |
| --allow-missing | switch | Go on when a template cannot be filled in. It is left out, never set to an empty value. |
| --offline-max-age HOURS | DBRIJ_SECRETS_OFFLINE_HOURS | How old a local copy may be when Dbrij cannot be reached. 24 by default; 0 never uses it. |
| --token TOKEN | DBRIJ_SECRETS_TOKEN | A machine token to read with, instead of your sign in. |
| --api-url URL | DBRIJ_API_URL | Another Dbrij API address, for this one command. |
| --message TEXT, -m | string | set, delete and push: the title of the change, or of the approval request it becomes. |
| --yes | switch | set, delete and push: confirm a change to a protected environment. |

.dbrij/secrets.toml

```
# Dbrij Secrets: which project and environment this folder reads.
# Names only, never a value or a token: safe to commit.
project = "my-app"
environment = "development"
paths = ["/", "/api"]
```

`.dbrij/secrets.toml` holds names only, so it is meant to be committed: the whole team then runs `dbrij secrets run` with no flags. The nearest one up the folder tree wins, so a folder in a monorepo can name its own. `dbrij secrets link` also makes sure `.dbrij/.gitignore` lets this one file in.

### How run behaves

- The command gets the secrets as environment variables. `DBRIJ_SECRETS_TOKEN` and `DBRIJ_SECRETS_KEY` are taken out of its environment: it gets its secrets, not the key to all of them.
- Ctrl+C, SIGTERM and SIGHUP are passed on to the command, and `dbrij secrets run` exits with the command's own exit code.
- With `--watch`, a burst of saves is one restart, never more than one every ten seconds. The command gets SIGTERM, and SIGKILL ten seconds later if it is still running.
- A template that cannot be filled in stops the command before it starts, naming the reference, unless `--allow-missing`.

### Changes, protected environments and approvals

`set`, `delete` and `push` seal values on this machine before they leave it. A protected environment needs `--yes`; in a company project the confirmed change goes to the project's approvers as a request instead of applying, and the CLI says so. With several folders read, name the one to change with `--path`.

`push` compares only the secrets in the folder it writes to, so another folder is never touched. It also takes an encrypted .env file whose values carry their own public key encryption: the private key comes from `DOTENV_PRIVATE_KEY` (or `DOTENV_PRIVATE_KEY_PRODUCTION` for `.env.production`, and so on) or a `.env.keys` file beside it. The values are opened on this machine and sealed again before they leave it.

### People and machines

A person reads after `dbrij login`. The first time, the CLI asks for your vault passphrase (three tries) and keeps the unlocked key on this device, sealed, for 12 hours by default (`DBRIJ_SECRETS_UNLOCK_HOURS`, up to 168; 0 asks every time). The passphrase can only be typed in a terminal.

A machine reads with a machine token in `DBRIJ_SECRETS_TOKEN`, or with a login key in `DBRIJ_SECRETS_KEY` on a pipeline or cloud platform Dbrij Secrets can log in from. The [Secrets documentation](https://dbrij.com/products/secrets/docs) covers machine tokens and login keys.

### What stays on this machine

Under `~/.dbrij/secrets/`, readable only by you: a sealed copy of the last values read, used when Dbrij cannot be reached or answers with a server error (never when it refuses), for up to 24 hours; and for people, the unlocked vault key. A machine's copy is sealed with the key half of its token. A person's files are sealed with a device key kept in the system keychain (macOS Keychain, the Secret Service on Linux, or Windows data protection), or in `~/.dbrij/secrets/device.key` when there is none. `DBRIJ_SECRETS_CACHE=off` stops the local copy; `dbrij secrets lock` removes all of it.

## Leases, keys, SSH and access

These `dbrij secrets` commands also take `--project`, `--space` and `--token` as above.

### Short lived database users

`dbrij secrets lease SOURCE` asks for a database user from a lease source a project admin set up. With a command after `--`, the command gets the user's address in `DATABASE_URL` and the lease is revoked when the command ends, whatever happens to it; the CLI exits with the command's exit code. Without a command, the address is printed and the lease lasts until it runs out or you revoke it.

Leases

```
dbrij secrets lease postgres-readonly -- psql
dbrij secrets lease postgres-readonly --ttl 1h
dbrij secrets lease revoke 9b1e…
```

LEASE FLAGS

|  |  |  |
| --- | --- | --- |
| --ttl | length | How long it lasts: 30m, 1h, 1h30m, or a bare number of minutes. |
| --var | name | The environment variable the command gets the address in. DATABASE_URL by default. |
| --format json | switch | Without a command: print the whole lease as JSON. |

A person names the project with `--project` or `.dbrij/secrets.toml`; a machine uses its own token. When the database is not open to the internet the CLI says the address only works from inside its Dbrij Hosting project. `lease revoke ID` ends one early; it reports revoked once the database confirms the user is gone, and pending otherwise.

### Key management

`dbrij secrets keys` uses a key in Dbrij Secrets Key management; the key itself never leaves Dbrij. KEY is a key's id, or when you are signed in, its name (add `--project` when two projects share a name). Text comes as an argument or on stdin, and results go to stdout alone, so they can be piped.

COMMANDS

|  |  |  |
| --- | --- | --- |
| dbrij secrets keys | command | The keys you can see. --format json for JSON. Also keys list. A machine uses ids and cannot list. |
| keys encrypt KEY [TEXT] | command | Print a ciphertext. --context name=value (repeatable) binds it to a context. |
| keys decrypt KEY [CIPHERTEXT] | command | Print what it decrypts to. Give the same --context as when it was made. |
| keys sign KEY [TEXT] | command | Print a signature. |
| keys verify KEY SIGNATURE [TEXT] | command | Exit 0 when valid, 1 when not. --key-version checks against one version. |
| keys mac KEY [TEXT] | command | Print a MAC. |
| keys verify-mac KEY MAC [TEXT] | command | Exit 0 when it matches, 1 when not. |
| keys public-key KEY | command | Print the public key as PEM. |
| keys rotate KEY | command | Make a new version; older versions still decrypt and verify. Project admins, signed in. |
| keys import KEY --file F | command | Import key material made elsewhere: raw AES or HMAC bytes, or a private key (PEM or PKCS #8 DER). It is wrapped on this machine before it is sent. Project admins, signed in. |

### SSH certificates

COMMANDS

|  |  |  |
| --- | --- | --- |
| dbrij secrets ssh | command | The SSH authorities you can see. Signed in only. |
| ssh sign CA [KEY.pub] | command | Sign a public key and write the certificate beside it (id_ed25519.pub gets id_ed25519-cert.pub), where ssh finds it on its own. Without a key: the first of ~/.ssh/id_ed25519.pub, id_ecdsa.pub and id_rsa.pub. Only the public key is sent. |
| ssh ca CA | command | Print the authority’s public key, for servers to trust. By id it needs no sign in. |

SIGN FLAGS

|  |  |  |
| --- | --- | --- |
| --principal | string | A name to sign for; repeat it for several. |
| --hours | number | How long the certificate lasts, in whole hours. |
| --policy | id | The policy to sign under. A machine must name it; a person gets the first policy that allows every principal asked for. |
| --out | path | Write the certificate somewhere else. |

### Server access

`dbrij secrets access` is for people, signed in. A session runs through Dbrij's access gateway from a local port, so ssh, psql and mysql work as usual while nobody sees a password, and every session is recorded. Each connection gets its own ticket.

COMMANDS

|  |  |  |
| --- | --- | --- |
| dbrij secrets access | command | Your requests and open windows, and requests waiting on you. |
| access servers | command | The servers and accounts you can ask for, with each window’s length and how many approvals it needs. |
| access request ACCOUNT | command | Ask for a window. --reason is required (three characters or more); --minutes is 60 by default; --task links a task. |
| access ssh REQUEST | command | A terminal on the server through the gateway. Anything after the id goes to ssh. |
| access psql REQUEST | command | psql on the database through the gateway. |
| access mysql REQUEST | command | mysql on the database through the gateway. |
| access shell REQUEST | command | A shell in a Dbrij Hosting container. Needs a terminal, not a pipe. |
| access connect REQUEST | command | A local port on 127.0.0.1 for any client, until Ctrl+C. --port picks it; any free port otherwise. Each connection is its own recorded session. |

`access ssh`, `psql` and `mysql` exit with the client's exit code, or 127 when the client could not start.

### Finding leaks

`dbrij secrets scan [folder]` looks for secrets written into files, with the same rules Dbrij Source uses on a push. Nothing leaves your machine. Inside a git repository it reads the files git tracks or would track; elsewhere it walks the folder. It exits 1 when it finds something and 0 when it does not.

FLAGS

|  |  |  |
| --- | --- | --- |
| --staged | switch | Only what is staged for the next commit. |
| --history | switch | Every commit. |
| --range | range | Some commits, like main..HEAD. |
| --json | switch | The findings as JSON. |
| --install-hook | switch | Install a git hook that runs the staged scan before every commit. A hook of your own already there is left alone unless --force. |

A line that is meant to be there (a test fixture) can carry the comment `dbrij-scan: ignore`. To commit past the hook once, deliberately: `git commit --no-verify`.

## Ship releases

`dbrij ship` cuts over the air releases with Dbrij Ship from a terminal or a pipeline, so the thing that goes out is the thing that was just built. What a release carries depends on the app: a JavaScript stack ships a bundle; every other stack ships an asset pack of the files the app reads at runtime. `dbrij ship apps` says which.

COMMANDS

|  |  |  |
| --- | --- | --- |
| dbrij ship apps | command | Every app in every company you belong to, with its id, what its releases carry, and whether its kill switch is on. |
| dbrij ship releases --app <id> | command | Release history: label, status, rollout percentage and id. |
| dbrij ship release <file> --app <id> | command | Upload a bundle or an asset pack and release it. |
| dbrij ship rollout <releaseId> <percent> --app <id> | command | Widen or narrow a rollout, from 1 to 100. |
| dbrij ship rollback <releaseId> --app <id> | command | Stop serving a release. Devices running it go back on their next check in. |
| dbrij ship | command | The usage. Exits 0; an unknown subcommand prints it and exits 1. |

RELEASE FLAGS

|  |  |  |
| --- | --- | --- |
| --app <id> | required | The app. Every ship command but apps needs it. |
| --channel <name> | string | The channel to release on. production by default. |
| --label <version> | string | The release label. By default the version in the file name (app-1.4.2.zip gives 1.4.2), or the file name. |
| --target <version> | string | The store binaries this runs on, like 1.2.x. Any by default. |
| --rollout <percent> | 1 to 100 | How many devices get it. 100 by default. |
| --mandatory | switch | Apply on receipt rather than at next launch. Asset packs apply as soon as they unpack, so it does nothing there. |
| --notes <text> | string | What changed. |

Release to a tenth of devices, then everyone

```
dbrij ship release build/app-1.4.2.zip --app 5c0d… --rollout 10 --notes "Faster checkout"
dbrij ship rollout 8e7a… 100 --app 5c0d…
```

Ship flags take their value after a space (`--app 5c0d…`). A file over 50 MB is refused before anything is sent: a release carries the parts of the app that change, never the whole app. The upload may take up to ten minutes. When a test target holds the app's production releases until its tests pass, the release is uploaded and held, devices keep the current release, and it goes live by itself once the tests pass.

Narrowing a rollout does not take a release off devices that already have it; to recall it, use `dbrij ship rollback`.

## Git credential helper

Pushing to Dbrij Source over HTTPS needs a Source token as the password. `dbrij git setup` makes the CLI git's password helper for Dbrij Source, so git signs in as you with no token to make, copy or paste.

Set it up once

```
dbrij login
dbrij git setup
git push
```

It needs git on your path and a sign in. It changes your global git config for one host only, the Source git host (the API's own address, `https://api.dbrij.com` unless `DBRIJ_API_URL` says otherwise):

What it writes to ~/.gitconfig

```
[credential "https://api.dbrij.com"]
	helper =
	helper = !dbrij git-credential
```

The empty entry first clears helpers inherited from elsewhere for this host alone, so an old pasted token is never offered ahead of a fresh one. When the `dbrij` on your path is not the CLI that ran setup, the helper is `!npx -y dbrij@VERSION git-credential` for that exact version instead. Running setup again is safe. To undo it:

Remove the helper

```
git config --global --unset-all credential.https://api.dbrij.com.helper
```

### What git runs

Git calls `dbrij git-credential get`, `store` or `erase`. It only answers for the Source host; any other host is left to git's other helpers. On `get` it asks Dbrij for a short lived push token with your sign in, keeps it in `~/.dbrij/git-credential.json` (readable only by you) and uses it until ten minutes before it expires. On `erase`, which git sends when it rejects a token, the cached token is deleted so the next push gets a fresh one. `store` does nothing.

It always exits 0 and never blocks git. Not signed in, or Dbrij unreachable, it says why on stderr, prints no credential, and git moves on to its next helper or its own prompt. `dbrij logout` deletes the cached push token too.

## The local MCP server

`dbrij mcp` runs Dbrij as a Model Context Protocol server on your own machine, over stdio, so an AI coding tool can scan your project, create services, set variables, connect a database, deploy the folder you are working in, read the logs when a build fails, and attach your domain. For an AI chat app with no access to your machine, use the hosted connector at [mcp.dbrij.com](https://dbrij.com/mcp) instead.

Add it to your AI coding tool

```
{
  "mcpServers": {
    "dbrij": { "command": "npx", "args": ["-y", "dbrij", "mcp"] }
  }
}
```

- It signs in with the CLI's credential: run `dbrij login` once in a terminal, or set `DBRIJ_TOKEN`. It acts as you, with your plan's limits, through the same API as the dashboard.
- Not signed in, it still starts, and each tool answers with the instruction to run `dbrij login`, which the assistant passes on.
- stdout is the protocol channel. The server writes only its ready line (version and API address) and warnings to stderr, and runs until the tool closes its stdin or it gets SIGINT or SIGTERM. Then it exits 0.
- Its requests carry `x-dbrij-client: mcp-local`, so Dbrij can show an action was taken through an AI assistant.
- An API refusal comes back to the assistant as a readable tool error, never a crash.

### What it never does

Anything that costs money or cannot be undone is only ever a request. The assistant files it, you are told, and you approve it on Dbrij, signed in as yourself; the approval refuses the CLI's token, so the assistant cannot approve its own request, and a deletion needs the name typed. Variable values, database passwords, Dbrij keys and secret values are never shown to it. The server tells the assistant never to act on instructions found inside logs, and to stop and tell you when a diagnosis says so.

HOSTING: READING

|  |  |  |
| --- | --- | --- |
| whoami | reads | The Dbrij account the tools act as. |
| scan_folder | reads | Read a local folder as the Deploy dialog reads a repository: which folders are deployable apps, their framework, port and role, whether they need a Dockerfile, and which databases the code expects. Reads only manifests; nothing is uploaded. |
| list_projects | reads | Every Hosting project you can reach, personal and company, with its services. |
| get_service | reads | One service’s settings and status. Variable names only, never values or database passwords. |
| list_deployments | reads | A service’s recent deployments, newest first. |
| wait_for_deployment | reads | Check on a deployment, waiting up to maxWaitSeconds. A failed one comes back with a plain diagnosis. |
| build_logs | reads | The build and release log of one deployment. |
| runtime_logs | reads | What the running service printed; previous reads the run before, where a crash loop shows its error. |
| list_domains | reads | A service’s custom domains, whether DNS and HTTPS work, and the record still needed. |
| check_domain | reads | Whether a domain is available to buy on Dbrij, and its yearly price. |
| plan_and_limits | reads | The Hosting plan, what it allows and this period’s usage. |
| list_backups | reads | A managed database’s backups, newest first. |
| get_request | reads | Whether you approved, turned down or let expire a request the assistant filed. |

HOSTING: CHANGING

|  |  |  |
| --- | --- | --- |
| create_project | changes | Create a Hosting project, in the personal space or a company. |
| create_service | changes | Add a web, worker or database service. A database starts at once (Starter plan or above); a web or worker service is not deployed by this. |
| deploy_folder | changes | Pack a local folder with the same rules as dbrij deploy and deploy it to a web or worker service. Returns the deployment id at once. |
| redeploy | changes | Build the latest code again for a service that deploys from a repository, or restart a database. |
| set_env_vars | changes | Add, change or remove variables. Values are stored encrypted and never read back. A deployed service restarts with them. |
| link_database | changes | Put a database’s connection string into an app’s variables (DATABASE_URL by default; REDIS_URL or MONGODB_URI for those engines). The string is never shown to the assistant. |
| create_public_url | changes | Switch on a web service’s free Dbrij URL. |
| add_domain | changes | Attach a domain you already own to a web service (Starter plan or above) and return the DNS record to create. |
| verify_domain | changes | Check a domain’s DNS now. |
| apply_suggested_fix | changes | Apply the fix a failed build’s diagnosis offers (a different install command, for example) and deploy again. |
| rollback | changes | Put a previous successful build back without rebuilding. |
| restart | changes | Restart a service’s running instances without rebuilding. |
| withdraw_request | changes | Take back a request you have not decided yet. |

REQUESTS YOU APPROVE ON DBRIJ

|  |  |  |
| --- | --- | --- |
| request_plan_change | asks | Move to a paid Hosting plan: starter, pro or reserved. |
| request_domain_purchase | asks | Buy an available domain, optionally pointing it at a web service. |
| request_resize | asks | Change a service’s copies, memory or CPU. |
| request_delete_service | asks | Delete a service (a database’s data goes with it). You approve by typing its name. |
| request_delete_project | asks | Delete a project and every service in it. You approve by typing its name. |
| request_backup_restore | asks | Put a database back to a backup. Everything written since is lost. |
| request_domain_removal | asks | Detach a custom domain from a service. You approve by typing the domain. |

DOMAINS, SEND, SEARCH AND STORAGE

|  |  |  |
| --- | --- | --- |
| list_my_domains | reads | Domains registered on or connected to Dbrij in a space. |
| list_dns_records | reads | The records of a domain whose DNS Dbrij runs. |
| add_dns_record | changes | Add one record, keeping every existing one. Refuses duplicates and CNAME clashes; changing or removing a record is done by you in Domains. |
| list_sending_domains | reads | Domains set up for sending email with Send, and the records each needs. |
| add_sending_domain | changes | Set up a domain for sending email with Send and return the records to publish. |
| verify_sending_domain | changes | Check a sending domain’s records again and verify it. |
| list_search_indexes | reads | Search indexes in a space. |
| create_search_index | changes | Create a search index. |
| list_buckets | reads | Storage buckets in a space and how much is stored. |
| create_bucket | changes | Create a private Storage bucket. Making one public is done by you in Storage. |
| connect_send | changes | Make a Send key for an app and write it into the app’s variables (DBRIJ_API_KEY unless named). Never overwrites a variable that exists. |
| connect_search | changes | Give an app a Search key and the API address (DBRIJ_SEARCH_KEY and DBRIJ_SEARCH_URL unless named). |
| connect_storage | changes | Give an app an S3 compatible Storage key: DBRIJ_KEY_ID, DBRIJ_KEY_SECRET, DBRIJ_S3_ENDPOINT, DBRIJ_S3_REGION, and DBRIJ_BUCKET when limited to one bucket. readOnly makes a key that cannot write. |

SECRETS

|  |  |  |
| --- | --- | --- |
| list_secret_projects | reads | Secrets projects in a space, with their environments. Names only. |
| list_secret_names | reads | The secret names in one environment, with their folders. Never values. |
| compare_secret_names | reads | Which names each environment of a project has and lacks. |
| set_secret | changes | Save a value, sealed on this machine before it leaves. A protected environment is changed by you in Dbrij. |
| run_with_secrets | runs | Run a command on this machine with an environment’s secrets, as dbrij secrets run does. The assistant gets the exit code and the output with every secret value hidden. |
| send_request_with_secrets | runs | Send an HTTPS request with placeholders like {{secret:NAME}} filled in on this machine. A secret only goes to the hosts listed on it in Dbrij Secrets; redirects are not followed; values are hidden in the answer. |
| run_with_database_lease | runs | Lease a database user, run a command with its address in an environment variable, then revoke it. The password and address are hidden. |
| list_keys | reads | Key management keys you can see, and what each may be used for. Never key material. |
| encrypt_with_key | uses a key | Encrypt a short text (up to 4 KB) with a key. Assistants cannot decrypt. |
| sign_with_key | uses a key | Sign a text with a signing key, or check a signature. |

Tools that work in a space take an optional `organizationId`; left out, they work in your personal space.

### Secrets tools and your vault key

Opening an environment needs a key. A machine token in `DBRIJ_SECRETS_TOKEN` works as it does for `dbrij secrets`. For a person, the vault key has to be unlocked on this device first, by a command run in a terminal; the assistant is never asked for the passphrase. When it is locked, the tool tells the assistant which command to ask you to run:

Unlock your vault key for the assistant

```
dbrij secrets status --project my-app --env development
```

## Environment and files

ENVIRONMENT VARIABLES

|  |  |  |
| --- | --- | --- |
| DBRIJ_TOKEN | token | Use this token instead of ~/.dbrij/auth.json. It always wins over the file. For CI. |
| DBRIJ_API_URL | URL | The Dbrij API to talk to. https://api.dbrij.com/api/v1 by default, or the address saved at sign in. |
| DBRIJ_CONFIG_DIR | path | Where the CLI keeps its own files. ~/.dbrij by default. |
| DBRIJ_DEBUG | any value | Print the full stack trace after an error message. |
| CI | any value | dbrij deploy never asks about a public URL and does not create one, unless --url. |
| DBRIJ_SECRETS_TOKEN | token | A machine token for dbrij secrets and the Secrets tools of dbrij mcp. |
| DBRIJ_SECRETS_KEY | login key | A machine login key, used when there is no token. |
| DBRIJ_SECRETS_PROJECT | name | The Secrets project, when --project is not given. |
| DBRIJ_SECRETS_ENV | name | The Secrets environment, when --env is not given. |
| DBRIJ_SECRETS_SPACE | id | The company space, when --space is not given. |
| DBRIJ_SECRETS_PATH | list | Comma separated folders to read, when no --path is given. |
| DBRIJ_SECRETS_OFFLINE_HOURS | hours | How old a local copy may be when Dbrij cannot be reached. 24 by default; 0 never. |
| DBRIJ_SECRETS_CACHE | off | off keeps no local copy at all. |
| DBRIJ_SECRETS_UNLOCK_HOURS | hours | How long an unlocked vault key is kept on this device. 12 by default, at most 168; 0 asks every time. |
| DBRIJ_SECRETS_KEYCHAIN | file, macos, secret-service, dpapi | Where the device key is kept, instead of the one the CLI picks. file suits containers. |
| DOTENV_PRIVATE_KEY… | key | dbrij secrets push: the private key that opens an encrypted .env file. |

FILES

|  |  |  |
| --- | --- | --- |
| ~/.dbrij/auth.json | mode 600 | Your token, the API address and your name and email. Written by dbrij login, deleted by dbrij logout. |
| ~/.dbrij/git-credential.json | mode 600 | The cached Source push token. |
| ~/.dbrij/secrets/cache/ | sealed | Local copies of the environments you read. |
| ~/.dbrij/secrets/unlocked.sealed | sealed | Your unlocked vault key, for as long as DBRIJ_SECRETS_UNLOCK_HOURS allows. |
| ~/.dbrij/secrets/device.key | mode 600 | The device key, only when there is no system keychain. |
| .dbrij/project.json | per folder | Which project and service this folder deploys to. Not committed. |
| .dbrij/secrets.toml | per folder | Which Secrets project, environment, space and folders this folder reads. Names only; meant to be committed. |
| .dbrij/.gitignore | per folder | Keeps .dbrij out of git, except secrets.toml. |
| .dbrijignore | per folder | Extra rules for what dbrij deploy leaves out, read after .gitignore. |

Default API address`https://api.dbrij.com/api/v1`

`dbrij secrets` commands also take `--api-url`, which sets the API address for that one command.

## Exit codes and errors

The CLI exits 0 when the command did what it was asked, and 1 when it did not. An error prints the API's own message, which is written for people, with no stack trace; set `DBRIJ_DEBUG=1` to see one.

EXIT CODES

|  |  |  |
| --- | --- | --- |
| 0 | success | Done. Also help, --version, dbrij git with no subcommand, and every git-credential call. |
| 1 | failure | Any error, refused input, an unknown command, a failed or cancelled deployment, or a watch that ran past 25 minutes. |
| 1 | a result | secrets scan found something; secrets diff --exit-code found a difference; keys verify or verify-mac did not match; secrets get found no such name. |
| the command’s | passed on | secrets run, secrets lease with a command, and access ssh, psql and mysql exit with the command’s own code. |
| 127 | not started | The command given to secrets run, secrets lease or access could not be started. |
| 128 + signal | signal | The command was ended by a signal: 130 for SIGINT, 143 for SIGTERM. |

### Common errors

|  |  |  |
| --- | --- | --- |
| You are not signed in. Run `dbrij login` first. | sign in | No DBRIJ_TOKEN and no ~/.dbrij/auth.json. Run dbrij login, or set DBRIJ_TOKEN in CI. |
| … Run `dbrij login`. | 401 | The token was revoked or is not valid any more. Sign in again. |
| Could not reach https://… | network | The API address could not be reached. Check your connection and DBRIJ_API_URL. |
| The request timed out. | network | A call took longer than 60 seconds. |
| The server did not return a sign in code. Check DBRIJ_API_URL. | address | DBRIJ_API_URL does not point at a Dbrij API. |
| This directory is not linked to a service. | link | Run dbrij link in the project folder, or run the command from inside a linked one. |
| That is not one of the options. | link | An answer to dbrij link that was not on the list. Nothing was created; run it again. |
| Nothing to deploy: every file in this directory is ignored. | deploy | The ignore rules leave nothing. Check .gitignore and .dbrijignore. |
| The packed source is … over the … limit. | deploy | Add what the build does not need (data, media, local output) to .dbrijignore. |
| Only web services get a public URL. | url | dbrij url on a worker or a database. |
| Your vault passphrase is needed, and this is not a terminal. | secrets | Run a secrets command in a terminal once to unlock your vault key, or use a machine token. |
| Say which project and environment | secrets | Give --project and --env, or run dbrij secrets link once in the folder. |
| … is protected. Add --yes | secrets | Confirm a change to a protected environment with --yes. |
| … already exists. Add --force to replace it | secrets | export --out and pull never overwrite a file unless told. |
| --env needs a value | secrets | A flag that takes a value (here --env) was given none. |
| Server access from the CLI needs Node 22 or newer | access | Upgrade Node.js to use dbrij secrets access. |
| Which app? Pass --app <id>. | ship | Every ship command but apps needs --app. dbrij ship apps lists the ids. |
| git is not installed, or not on your PATH. | git | dbrij git setup needs git. |
