Cosmoner Docs
SDKs

CLI

The cosmoner command line tool — validate deployment files, deploy image apps, upload to web hosting, and manage secrets from a terminal or CI.

@cosmoner/cli is built on the JavaScript SDK and gives the most common pipeline steps a one-line command. Run it with npx, with nothing to install:

npx @cosmoner/cli validate

Or install it globally to get a cosmoner command:

npm install -g @cosmoner/cli

It is useful in any repository, not only JavaScript ones. A deployment file describes a deployment, not a Node project, so the CLI works the same in a Go or Rust repository.

Credentials

The file commands — validate, fmt, init, schema and agents — work offline. They need no account, no API key and no network.

deploy, upload, secrets and variables call the API, and read a key from one of two places:

  • On your own machine, run cosmoner login. It opens your browser, where you pick a project and approve. The CLI saves a key for that project that expires after 90 days. See Keys Created by the CLI.
  • In CI, set COSMONER_API_KEY to a key you created, and COSMONER_PROJECT_ID to its project. The environment variable always wins over a saved login.

There is deliberately no flag for passing a key: a flag ends up in shell history and CI logs. cosmoner whoami shows which key and project the CLI is using, and cosmoner logout revokes the saved key.

Exit codes

Every command uses the same three codes, so a CI step can tell a broken deploy from a typo in its own command line:

CodeMeaning
0Success.
1The operation failed — a file did not validate, a deploy failed, the API refused a request.
2The command itself was wrong — an unknown option, an unreadable path.

Validate a deployment file

cosmoner validate
.cosmoner/deployment.yaml
  2:11  error    Service names must be lowercase letters, numbers, or hyphens, and start with a letter or number  services.0.name
  4:18  error    Static sites cannot define a run_command  services.0.run_command
  5:11  warning  Unknown field "prot" — it will be ignored  services.0.prot

2 errors, 1 warning

With no argument, it finds the file the way the platform does. It runs the same check as the SDK validators and adds the line and column of each finding.

Option
--strictFail on warnings too, such as an unknown key.
--format text|json|githubgithub annotates findings on the pull request diff.
--quietReport through the exit code only.
# GitHub Actions
- name: Validate deployment file
  run: npx @cosmoner/cli validate --strict --format github

Other file commands

CommandWhat it does
cosmoner initWrites a starter .cosmoner/deployment.yaml, with comments on the fields you are most likely to set. --type static for a static site.
cosmoner fmtRewrites the file in canonical field order and adds a $schema header for editor completion. Comments are kept. --check exits 1 instead of writing.
cosmoner schemaPrints the JSON Schema for the file. --url prints its published URL.
cosmoner agentsAdds a short "Deploying to Cosmoner" section to AGENTS.md, so coding agents validate, deploy and handle secrets the way the CLI expects. Safe to re-run.

Deploy an image app

cosmoner deploy web --tag v2
Deploying web (tag v2)
  PENDING
  DEPLOYING
✓ web is live on registry.cosmoner.com/acme/web:v2 after 41s

Deploys an image app — one that runs an image from a Cosmoner registry — and waits for the rollout. web is the app's name or id. The key needs apps:read and apps:write.

Option
--tag <tag>Deploy this tag. A commit SHA pushed as a tag goes here.
--digest <digest>Deploy this exact image.
--no-waitReturn as soon as the deploy is accepted.
--timeout <seconds>How long to wait. Defaults to 600. A timeout stops the wait, not the deploy.
--project <id>Defaults to COSMONER_PROJECT_ID, then the project you logged in to.
--format text|jsonjson prints the app and the final deployment.

With neither --tag nor --digest, the image the app already names is pulled again.

# GitHub Actions
- name: Deploy
  run: npx @cosmoner/cli deploy web --tag ${{ github.sha }}
  env:
    COSMONER_API_KEY: ${{ secrets.COSMONER_API_KEY }}
    COSMONER_PROJECT_ID: ${{ vars.COSMONER_PROJECT_ID }}

Upload to a web hosting site

cosmoner upload my-site dist --delete
Uploading dist to my-site:/my-site.cosmoner.com/public_html (42 files, 1.3 MB)
✓ Uploaded 42 files (1.3 MB), removed 3 in 6s

Uploads a directory to a web hosting site over SFTP. The SFTP login is fetched with the API key, so CI needs no password of its own. The key needs hosting:read.

Existing files are overwritten. Files on the site that are not in the directory are left alone unless you pass --delete. An empty directory is refused, since it is usually a build that produced nothing.

Option
--remote <path>Folder to upload into. Defaults to the one the site's own hostname serves.
--deleteRemove what is on the site but not in the directory.
--dry-runList what would change without changing anything.
--host-key <sha256>Refuse a server with a different host key. Defaults to COSMONER_SFTP_HOST_KEY.

Pin the host key so the password is never sent to a server pretending to be ours. The gateway's key is:

SHA256:PfqYSl1pbMjfMKAbcmjzGZ0t1kpuCZ2mtymdyLu9HwA
# GitHub Actions
- name: Upload site
  run: npx @cosmoner/cli upload my-site dist --delete
  env:
    COSMONER_API_KEY: ${{ secrets.COSMONER_API_KEY }}
    COSMONER_PROJECT_ID: ${{ vars.COSMONER_PROJECT_ID }}
    COSMONER_SFTP_HOST_KEY: SHA256:PfqYSl1pbMjfMKAbcmjzGZ0t1kpuCZ2mtymdyLu9HwA

Secrets and variables

echo "$DB_PASSWORD" | cosmoner secrets set DB_PASSWORD --environment production
cosmoner variables set LOG_LEVEL --value debug
cosmoner secrets list

set creates a value, or replaces one that already exists with that name in that environment. rm removes it, and list shows what is there.

Option
--environment <env>default, development, staging or production. Defaults to default.
--value <value>The value, taken literally.
--from-file <path>Read the value from a file.
--description <text>Set alongside the value.
--format text|jsonjson output never includes a secret's value.

Pipe secret values in. A value passed with --value can be recovered from shell history and may be echoed by a CI runner. cosmoner secrets never prints a value back, for the same reason.

The key needs secrets:write or variables:write, and its owner must be an owner or admin of the project — see Secrets and Variables.

# GitHub Actions
- name: Set the database password
  run: echo "$DB_PASSWORD" | npx @cosmoner/cli secrets set DB_PASSWORD --environment production
  env:
    COSMONER_API_KEY: ${{ secrets.COSMONER_API_KEY }}
    COSMONER_PROJECT_ID: ${{ vars.COSMONER_PROJECT_ID }}
    DB_PASSWORD: ${{ secrets.DB_PASSWORD }}

On this page