CLI command reference
Every command the cloudgate CLI has, what it prints and how it exits. Run cloudgate <command> --help for the same usage lines in your terminal.
Applies to: Hosted and self-hostedBeta
The CLI groups its commands by what they act on: your login, the folder you are in, and templates.
This page matches CLI 0.0.2-beta.3, on the npm next tag; the latest tag, 0.0.1, has fewer
commands. For a walk-through in order, read the CLI guide; for automation, see
CI recipes; for exit codes and error messages, see
troubleshooting.
| Command | What it does |
|---|---|
login |
Log in to an Instance through your browser |
logout |
Log out and delete this computer’s key |
whoami |
Show who you are logged in as, and where |
instance list |
Show the Instances you are logged in to |
instance use |
Switch the current Instance |
link |
Link this folder to a Service, or a whole Project |
unlink |
Remove this folder’s link |
config pull |
Replace this Project folder’s cloudgate.yaml with Cloudgate’s |
config plan |
Send this Project folder’s cloudgate.yaml as a Plan, and apply it |
deploy |
Upload this folder and deploy it |
status |
Show the Service and its latest Deployment |
logs |
Show the Service’s logs |
vars |
List, set and unset the Service’s variables |
template check |
Check templates as Cloudgate will read them |
template pack |
Build the catalogue.zip a release publishes |
template try |
Start a template’s compose part on local Docker |
Global flags
Every command accepts these:
| Flag | What it does | Variable |
|---|---|---|
--instance <url> |
The Instance to use | CLOUDGATE_INSTANCE |
--json |
Print the result as JSON (commands that support it) | |
--no-input |
Never ask a question; refuse instead | CI (any value) |
--no-color |
Print without colour | NO_COLOR |
--allow-http |
Allow a plain http:// Instance address other than localhost |
|
-h, --help |
Show help for a command | |
--version |
Show the CLI’s version |
Target flags
link, deploy, status, logs and vars find their Service with these. A flag wins over its
variable, and both win over the folder’s link.
| Flag | Picks | Variable |
|---|---|---|
--org <name or id> |
Organization | CLOUDGATE_ORG |
--project <name or id> |
Project | CLOUDGATE_PROJECT |
--env <name or id> |
Environment | CLOUDGATE_ENV |
--service <name or id> |
Service, by its Config name | CLOUDGATE_SERVICE |
Each value is tried as an id, then as a name ignoring case; a name two share is refused with their ids. The Organization is picked for you when you belong to only one. The link fills a level only while the levels above it are the link’s too, and its Service Config name always applies.
A Project folder names no Service, so there status, logs and vars ask for
one, or take --service; with no terminal a missing --service is refused (exit 2). A folder below
it with its own one-Service link still uses that link.
Environment variables
| Variable | Effect |
|---|---|
CLOUDGATE_KEY |
A Personal key. Wins over any saved login, is never saved, and ignores the current Instance |
CLOUDGATE_INSTANCE |
The Instance address |
CLOUDGATE_ORG, CLOUDGATE_PROJECT, CLOUDGATE_ENV, CLOUDGATE_SERVICE |
The target, as the flags above |
CLOUDGATE_CONFIG_DIR |
The settings folder, instead of ~/.config/cloudgate/ or %APPDATA%\cloudgate\ |
CLOUDGATE_NO_UPDATE_NOTIFIER |
No new-version notice |
CI |
No questions, no spinner, no new-version notice |
NO_COLOR |
No colour |
Log in
cloudgate login
cloudgate login [--instance <url>]
Prints an address and a code. Open the address on any device, check the code and approve; this
computer then gets a Personal key that ends in 90 days, and the Instance becomes the current one.
Without --instance (or CLOUDGATE_INSTANCE) it logs in to https://cloudgate.octabyte.app; it
never uses a folder link’s Instance.
| Flag | Default | What it does |
|---|---|---|
--instance <url> |
Hosted instance | The Instance to log in to. https:// is added when missing |
--allow-http |
off | Allow a plain http:// address |
$ cloudgate login --instance cloud.northwind.example
Using instance https://cloud.northwind.example
Open https://cloud.northwind.example/device and enter the code WDJB-MJHT
Waiting for you to approve…
✓ Logged in to https://cloud.northwind.example as sam@northwind.example
Your key is in the system keychain and ends on 2027-02-10.
The key goes in the system keychain; where there is none, in credentials.json in the settings
folder, readable only by you. Logging in again on the same Instance replaces that login and deletes
the old key. A denied or expired code exits 3 and saves nothing.
cloudgate logout
cloudgate logout [--instance <url> | --all]
Deletes this computer’s key on the Instance, then forgets the login. Without a flag it logs out of the Instance this folder would use: the link’s, else the current one.
| Flag | What it does |
|---|---|
--instance <url> |
Log out of this Instance instead |
--all |
Log out of every saved Instance, carrying on past any that fail |
If the Instance cannot be reached, the login is still forgotten here and the command prints
Error: its key was not deleted on <instance>: … with a hint to delete it in the console, then
exits 1. A key that had already ended is a clean logout. Not logged in prints
You are not logged in to <instance>; nothing to do. and exits 0. With CLOUDGATE_KEY set it
refuses (exit 2): delete that key in the console instead.
cloudgate whoami
cloudgate whoami [--json]
Prints the Instance, your email, the Organization in use and when your key ends.
$ cloudgate whoami
Instance https://cloudgate.octabyte.app
Logged in as sam@northwind.example
Organization Northwind Labs
Key ends 2027-02-10 (in 90 days)
The key’s end reads YYYY-MM-DD (in N days), (in less than a day), (ended), or never.
--json prints:
{
"instance": "https://cloudgate.octabyte.app",
"email": "sam@northwind.example",
"organization": { "id": "…", "name": "Northwind Labs" },
"keyFrom": "login",
"keyEndsAt": "2027-02-10T09:14:00.000Z"
}
keyFrom is "login" for a saved login and "env" for CLOUDGATE_KEY.
cloudgate instance list
cloudgate instance list [--json]
Shows every Instance you are logged in to, under INSTANCE and LOGGED IN AS, marking the current
one with *. It sends no request. --json prints one entry per Instance with instance, email,
current and keyEndsAt. With none: You are not logged in to any Instance. Run: cloudgate login.
cloudgate instance use
cloudgate instance use <url>
Makes a saved login the current Instance and prints ✓ Now using <url>. Commands then use it when
no --instance, CLOUDGATE_INSTANCE or folder link names another. Not logged in there exits 3 with
the hint Run: cloudgate login --instance <url>.
This folder
cloudgate link
cloudgate link [--org] [--project] [--env] [--service] [--yes]
cloudgate link --whole-project [--org] [--project] [--env] [--yes]
Asks for the Organization, Project, Environment and Service, skipping any a flag answers, then
saves .cloudgate/link.json and adds .cloudgate/ to .gitignore. It never creates a Service and
never changes the Project config. The Project whose config is kept in this folder’s git repository
is listed first.
| Flag | What it does |
|---|---|
| Target flags | Answer that question without asking |
--whole-project |
Link the whole Project, with no Service: this folder becomes a Project folder |
--yes |
Ask nothing, and replace an existing link or cloudgate.yaml without asking |
--instance <url> |
The Instance to link to |
cloudgate link --project storefront --env production --service web --yes
# ✓ Linked ./ to web in production of Project storefront on cloudgate.octabyte.app
With no terminal, or with --yes, a missing value is refused naming its flag, for example
Error: no Project. Pass --project or set CLOUDGATE_PROJECT. (exit 2).
--whole-project makes a Project folder, usually a monorepo’s root. It asks for the
Organization, Project and Environment (the default one for later commands), never a Service, and
saves the Project config here as cloudgate.yaml: a working copy, which Cloudgate never reads on its
own. The link records the config’s version, and .gitignore gains /cloudgate.yaml beside
.cloudgate/, so the working copy is never committed. It takes no --service.
$ cloudgate link --whole-project --project storefront --env production
✓ Linked ./ to the whole Project storefront, production by default, on cloudgate.octabyte.app
✓ Saved the Project config, version 7, as cloudgate.yaml
A cloudgate.yaml already here that is not the one downloaded is asked about, or refused with no
terminal unless --yes. A Project whose config is kept in a repository is refused (exit 1), naming
the repository: move it into Cloudgate first, on the Project’s Config tab with
Move into Cloudgate. See Project config.
cloudgate unlink
cloudgate unlink
Deletes the link this folder uses: its own .cloudgate/link.json, or the nearest one above it. It
sends no request and needs no login. The .gitignore line stays.
$ cloudgate unlink
✓ Removed this folder's link. Nothing changed on the Instance.
cloudgate config pull
cloudgate config pull [--yes]
Replaces the Project folder’s cloudgate.yaml with the Project config kept in Cloudgate and records
its version. Run it when a teammate or the console has changed the config since your download.
$ cloudgate config pull
✓ Saved the Project config, version 8, as cloudgate.yaml
A cloudgate.yaml edited since its download is asked about first; with no terminal it is refused
(exit 2) unless --yes. Outside a Project folder it is refused (exit 2) with the hint to run
cloudgate link --whole-project.
cloudgate config plan
cloudgate config plan [--yes]
Sends the Project folder’s cloudgate.yaml to Cloudgate as a Plan,
naming the Config version it was downloaded at, prints what each
Environment’s Plan creates, changes and destroys, and applies it on a yes. After applying, the link
records the new version.
$ cloudgate config plan
production: 1 to create, 1 to change, 0 to destroy
+ api (web) create
~ web (web) change size
? Apply the plan in production? (y/N) y
✓ Applied the plan in production
| Flag | What it does |
|---|---|
--yes |
Apply without asking. A Plan that destroys a Service or makes a major version upgrade is still refused, naming each (exit 2) |
- A Service the Plan destroys, or upgrades to a new major version, is applied only once you type its Config name.
- With no terminal it is refused (exit 2) unless
--yes. - A copy the Project config has moved on from is refused and nothing is sent (exit 1):
Error: cloudgate.yaml is version 7 of the Project config, which has changed in Cloudgate since; nothing was sent. Runcloudgate config pull, then make your edits again. - A no or a mistyped Config name applies nothing and exits 1, so a script can tell it from an apply.
- A run that applies nothing (a no, a mistyped name, a refusal) dismisses the Plans it sent, so none is left open in the console. A role that may not dismiss is told they are left open.
cloudgate deploy
cloudgate deploy [folder] [--env <name|id>] [--detach [--json]]
[--switch-source] [--full] [--yes]
Uploads a folder to its Application, starts a Deployment and prints the Deployment log until the
Deployment ends. The folder is the one holding the nearest .cloudgate/, not the subfolder you
stand in; [folder] names another, and that folder’s own link picks the Service. With no link, a
terminal asks which Project first. In a
Project folder it deploys every app built from a subfolder.
| Flag | Default | What it does |
|---|---|---|
| Target flags | from the link | --env deploys the same Config name in another Environment. In a Project folder, --service deploys one app only |
--detach |
off | Don’t wait: print the Deployment and exit once it is queued |
--json |
off | With --detach only: print the Deployment as JSON |
--switch-source |
off | Switch a git or image source to uploaded files without asking. Needed in CI |
--full |
off | Upload every file, not only the ones that changed |
--yes |
off | In a Project folder, apply the Plan without asking. One that destroys a Service or makes a major upgrade is still refused |
--instance <url> |
The Instance to deploy to |
Left out of the upload: .git/, .cloudgate/, anything a .gitignore or .cloudgateignore in the
folder lists, .env and .env.* except .env.example, and symlinks. File modes are not kept. The
upload lands at the build root.
Only the changed files are uploaded
deploy sends the folder’s file list with the SHA-256 of each file, asks the Instance which ones its
build host lacks or holds different, and uploads only those. Files you deleted locally are deleted
there too, and the new files replace the old ones only once every file matches.
Uploading 3 changed files, 12.0 kB (211 unchanged, 1 deleted)…
When nothing is new, missing or deleted, deploy prints Nothing changed since the last upload and
skips the upload; the build still runs. The .env file a build writes on the build host is not
counted as deleted.
The size, there and in the 100 MB warning, is the size of the zip sent. If the files on the build
host changed during the upload, deploy prints the Instance’s reason and compares once more; a
second refusal fails with exit 1. --full sends every file, as earlier versions did. An Instance
older than 0.2.0 gets the full upload without a question.
$ cloudgate deploy --detach
Deployment Xq7Tn2LwP9aRk4sVb1cHd
Status pending
Console https://cloudgate.octabyte.app/applications/…/deployments
--detach --json:
{ "deploymentId": "Xq7Tn2LwP9aRk4sVb1cHd", "status": "pending", "consoleUrl": "https://cloudgate.octabyte.app/applications/…/deployments" }
Watching ends on ✓ Deployment <id> done in 1m 42s (exit 0), or
Error: Deployment <id> failed after <time> with Its log: cloudgate logs --deployment <id>
(exit 1). Ctrl-C stops watching (exit 130); the build goes on:
Stopped watching. The build goes on.
Follow it: cloudgate logs --deployment Xq7Tn2LwP9aRk4sVb1cHd -f
Cancel it: https://cloudgate.octabyte.app/applications/…/deployments
Before it uploads, deploy refuses a Compose stack or a database (exit 1), asks before switching a
git or image source (no terminal: exit 2 unless --switch-source), refuses a source a
repository-kept Project config owns, and waits for a pending or running
build of the same Service.
A first deploy in a folder with no link
In a terminal, with no target flag or CLOUDGATE_ORG, _PROJECT, _ENV or _SERVICE set, a first
deploy asks which Project, listing the one whose config this repository keeps first, plus
Create a new Project:
- An existing Project asks
One app or the whole Project?(one app by default). One app asks the Environment and Service and saves a one-Service link, then deploys. The whole Project links the folder aslink --whole-projectdoes, then deploys it whole. A Project whose config is kept in a repository is deployed as one app, and the CLI says why. - Create a new Project asks its name (this folder’s by default) and once where its apps run: a
ready Server of the Organization, or a Cloud account and a region. It makes the Project, one
Environment named
productionwith that Deploy target, and a Project config kept in Cloudgate with no app yet and one commented example. This folder becomes its Project folder with that text ascloudgate.yaml, anddeployends withAdd your apps to cloudgate.yaml, then run cloudgate deploy again.
Creating a Project needs the project: create permission (exit 1 without it), and an Organization
with no Server or Cloud account is refused before anything is made. Without a terminal, or with a
target flag or variable, nothing new is asked.
Deploy in a Project folder
In a folder linked with link --whole-project, deploy first runs the same step as config plan
(--yes works the same way). Then it uploads the whole folder, less what an upload always leaves
out, to each app whose config entry names a subfolder of it as its source, builds each from that
subfolder, and follows every build to its end:
services:
web:
kind: web
source: { folder: apps/web }
jobs:
kind: worker
source: { folder: apps/jobs }
$ cloudgate deploy
production: no changes
Nothing to change.
Deploying ./ to web in production of Project storefront on cloudgate.octabyte.app, built from apps/web
…
✓ web: Deployment Xq7Tn2LwP9aRk4sVb1cHd done in 1m 42s
✓ jobs: Deployment Lp3Vd8QmT2wNc6yHs0bKf done in 58s
- pg-main: skipped, a database
- Apps from a repository or an image, console-managed entries, databases and buckets are listed as skipped and sent nothing.
- A subfolder that is not there is refused before the Plan is sent, so nothing is created or uploaded (exit 1).
- It exits 0 only when every build is done.
--detachstops once every build is queued and prints a table of them (--jsonprints a list).--service <name>deploys one app only. - A
[folder]argument is refused (exit 2): a Project folder is deployed whole. - A plan line that removes a setting says so, for example
build.context (removed). - Applying the Plan does not also rebuild each folder-source app from its previous upload; the build that follows the upload is its Deployment.
A subfolder of a Project folder can also be linked to one Service with plain cloudgate link. When
that Service’s config entry names the subfolder as its source, deploy there uploads the whole
Project folder with that subfolder as the build path, exactly as a root deploy does for that app,
so shared code beside it is included.
cloudgate status
cloudgate status [--json]
Shows the Service and its kind, Environment, Project, Instance, state, source, Domains and latest Deployment. It reports and does not judge: it exits 0 whenever it could read them, even when the Service is stopped or its last Deployment failed. It works on every kind of Service; a database shows its image and has no Domains or Deployment.
$ cloudgate status
Service web (Application)
Environment production
Project storefront
Instance https://cloudgate.octabyte.app
State running
Source uploaded files
Domains shop.northwind.example
Latest Deployment Xq7Tn2LwP9aRk4sVb1cHd done 4 minutes ago
Source also reads github northwind-labs/storefront or image ghcr.io/northwind-labs/web:1; a plain
git URL is never printed. --json prints one object with instance, organization, project,
environment, service, state, source, domains and latestDeployment.
cloudgate logs
cloudgate logs [-f] [-n <lines>] [--deployment [id]]
Prints the last lines of the Service’s Runtime log, on a Server or in a Cloud account (there, from
the last hour at most). Only log lines go to stdout. Applications only, except that a Compose stack’s
Deployment logs can be read with --deployment.
| Flag | Default | What it does |
|---|---|---|
-f, --follow |
off | Keep printing new lines until Ctrl-C |
-n, --lines <lines> |
100 |
How many of the last lines, from 1 to 10000 |
--deployment [id] |
A Deployment log: the latest Deployment’s, or [id]’s |
|
| Target flags | from the link |
With --deployment -f it follows that Deployment from its first line and ends by itself when the
Deployment does, printing Deployment <id> done or failed and exiting 0 either way. There is no
--json.
cloudgate logs -f -n 50
cloudgate logs --deployment Xq7Tn2LwP9aRk4sVb1cHd
cloudgate vars
cloudgate vars list [--json]
cloudgate vars set KEY=VALUE [KEY=VALUE …]
cloudgate vars set KEY
cloudgate vars unset KEY [KEY …]
Lists, sets and unsets the Service’s own runtime variables in one Environment. Values are never printed, not even in an error. Applications only.
listshowsNAMEandVALUE, where the value readssetorlinked to <service>.<output>.--jsonprints[{ "name": "DATABASE_URL", "linkedTo": "db.url" }, { "name": "STRIPE_KEY", "linkedTo": null }]. With none:No variables.set KEY=VALUEsplits at the first=.set KEYasks for the value hidden, or reads it from stdin with one trailing newline dropped.unsetremoves the named variables. Only the names you give are touched.
printf %s "$STRIPE_KEY" | cloudgate vars set STRIPE_KEY
# ✓ Set STRIPE_KEY on web in production. Run cloudgate deploy to pick it up.
Nothing redeploys. A variable linked to another Service’s output is refused (exit 1). Project and Environment variables, build arguments and build secrets are managed in the console; see environment variables.
Templates
These three commands are for template authors, such as contributors to the official catalogue. They need no login and send no request to an Instance. The check they run is the CLI’s bundled copy of the backend’s own Template check, so the Cloudgate version the CLI was built with is the one that judges.
cloudgate template check
cloudgate template check <path>
<path> is a catalogue.zip, a template folder, or a folder of template folders. Prints ✓ <id>
for each template Cloudgate would offer and ✗ <id>: <reason> for each it would hide, and exits 1
if any is hidden. A folder is checked as the catalogue.zip it would be packed into: the website’s
index.md and screenshots/ and the test-values.yaml that template try
reads are skipped, and any other file a template does not have refuses the whole catalogue. An old
catalogue.json is refused with a message naming catalogue.zip.
cloudgate template pack
cloudgate template pack <folder> <out> [--revision <sha>]
Checks the templates exactly as template check does, then writes the catalogue.zip to <out>,
leaving index.md, screenshots/ and test-values.yaml out. If any template would be hidden, or
the folder holds no template, it writes nothing and exits 1.
| Flag | Default | What it does |
|---|---|---|
--revision <sha> |
unpublished |
The revision every template is published at, usually the release’s commit |
cloudgate template try
cloudgate template try <template folder> [--timeout <minutes>]
Starts a template’s compose part on this computer’s Docker the way an Instance would, checks that each Domain answers, and removes everything. It needs Docker with Compose 2.1.1 or newer.
- A template
template checkwould hide is refused with the check’s reason (exit 1). One with no compose part prints<id>: no compose part, nothing to tryand exits 0. - Values are made as setup makes them: generated inputs are generated, a Domain’s URL is
http://localhost:<port>, and anaskinput takes its value fromtest-values.yaml, else its default, else a sample that fits its format or pattern. - Each Domain’s container port is published on a free
127.0.0.1port, and afterdocker compose up --waiteach Domain is asked every 2 seconds until it answers anything but a 5xx.
Each Domain prints ✓ <service>:<port><path> or ✗ <service>:<port><path>: <last status or "no answer">;
it exits 0 when every Domain passes and 1 otherwise. On a failure it prints
docker compose ps --all and docker compose logs --no-color first. After a pass, a fail, the time
limit or Ctrl-C (exit 130), the stack is removed with its volumes and its folder deleted.
| Flag | Default | What it does |
|---|---|---|
--timeout <minutes> |
10 |
How long the whole run may take, image pulls included, before it stops and exits 1 |
test-values.yaml
A template folder may hold test-values.yaml: a map of an ask input’s name to the text
template try uses for it, ahead of the input’s default and a sample. Each value still passes the
input’s own rule, and a name that is not an ask input fails try before anything starts.
# test-values.yaml, for a template whose template.yaml asks for admin_email
admin_email: owner@northwind.example
template check skips the file and template pack leaves it out of catalogue.zip.
template check and template pack arrived in 0.0.2-beta.2, template try and test-values.yaml
in 0.0.2-beta.3.
Questions
Which commands print JSON?
whoami, instance list, status, vars list and deploy --detach take --json. logs is text only. With --json, stdout is empty when the command fails.
Where does the CLI print errors?
On stderr, as Error: <message> with at most one hint line under it. Data goes to stdout and everything else, including Using instance <url>, goes to stderr.
Is there a command to read a variable''s value?
No. There is no vars get or vars pull: values are never printed. vars list says only whether each one is set or linked to another Service.
Is there a command to update the CLI?
No. Update it with npm. The CLI prints a one-line notice at most once a day when a newer version is on npm.
Which commands need a Project folder?
config pull and config plan work only in a folder linked with cloudgate link --whole-project. In one, deploy builds every app the Project config builds from a subfolder, and status, logs and vars ask which Service, or take --service.
Something missing or wrong on this page? Email support@octabyte.io, or start a free trial and try it in the console.