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 [--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

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. Run cloudgate 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.

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 as link --whole-project does, 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 production with 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 as cloudgate.yaml, and deploy ends with Add 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. --detach stops once every build is queued and prints a table of them (--json prints 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.

  • list shows NAME and VALUE, where the value reads set or linked to <service>.<output>. --json prints [{ "name": "DATABASE_URL", "linkedTo": "db.url" }, { "name": "STRIPE_KEY", "linkedTo": null }]. With none: No variables.
  • set KEY=VALUE splits at the first =. set KEY asks for the value hidden, or reads it from stdin with one trailing newline dropped.
  • unset removes 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.

  1. A template template check would hide is refused with the check’s reason (exit 1). One with no compose part prints <id>: no compose part, nothing to try and exits 0.
  2. Values are made as setup makes them: generated inputs are generated, a Domain’s URL is http://localhost:<port>, and an ask input takes its value from test-values.yaml, else its default, else a sample that fits its format or pattern.
  3. Each Domain’s container port is published on a free 127.0.0.1 port, and after docker compose up --wait each 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.