Skip to content

Latest commit

 

History

7 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

cloudconsole

Command-line interface for the Cloud Console. A single static binary for managing Xcloud instances, data volumes, images, networks, security groups and elastic IPs — from a terminal or from CI.

This repository is a read-only mirror, published from the Cloud Console monorepo on every release. Issues and feature requests are welcome here; pull requests are not, since changes here are overwritten by the next mirror — see CONTRIBUTING.md.

Install

Homebrew

brew install studio-ch/tap/cloudconsole

Shell installer (Linux and macOS, verifies the checksum)

curl -fsSL https://raw.githubusercontent.com/studio-ch/cloudconsole-cli/main/install.sh | sh

Pin a version, or choose where it lands:

CLOUDCONSOLE_VERSION=v0.1.0 CLOUDCONSOLE_INSTALL_DIR="$HOME/.local/bin" \
  sh -c "$(curl -fsSL https://raw.githubusercontent.com/studio-ch/cloudconsole-cli/main/install.sh)"

Go

go install github.com/studio-ch/cloudconsole-cli/cmd/cloudconsole@latest

Manual — download an archive from Releases, verify it against SHA256SUMS, and put cloudconsole on your PATH. Windows builds are published as .zip.

cloudconsole version

Authenticate

Issue an API key in the panel under Settings → API keys. The secret is shown once, at creation. Choose the Read + Write preset if you intend to change anything — a read-only key is rejected on mutations.

cloudconsole auth login     # prompts, without echoing
cloudconsole auth status    # organisation, key, scopes, expiry

In CI, set the token in the environment instead:

export CLOUDCONSOLE_API_TOKEN=sk_live_…

A key belongs to exactly one organisation. For several, use one profile per key (cloudconsole auth login --profile acme, then --profile acme or cloudconsole config use acme).

Use

cloudconsole region list
cloudconsole instance list
cloudconsole instance list -o json | jq -r '.[].name'

cloudconsole instance create \
  --name build-01 --region ZRH1 \
  --image ghcr.io/example/macos-sequoia:latest \
  --cpu 10 --memory 28 --disk 480 --wait

cloudconsole instance suspend <id> --wait      # suspend to disk
cloudconsole instance boot-mode <id> --recovery --wait
cloudconsole instance delete <id> --yes --wait

cloudconsole volume create --name scratch --region ZRH1 --size 500
cloudconsole volume attach <volume-id> --instance <instance-id>

Most instance operations are asynchronous. --wait blocks until the instance reaches its new state — use it whenever you script two operations in a row, because a second action while one is pending is rejected.

cloudconsole --help lists everything; cloudconsole <command> --help goes deeper.

Linux startup configuration

Pass a complete first-boot document with --user-data-file and --user-data-format. For Fedora CoreOS, use Ignition JSON (convert Butane YAML first):

cloudconsole instance create \
  --name coreos-01 --region ALP2 --platform linux \
  --image coreos --cpu 2 --memory 4 --disk 40 \
  --admin-username core \
  --user-data-file ./config.ign --user-data-format ignition --wait

Choose an image and sizing available in your region. For cloud-init images, use --user-data-file ./cloud-config.yaml --user-data-format cloud-init; the YAML must start with #cloud-config. Use --user-data-file - to read stdin.

The document replaces automatic setup. Define users and SSH keys inside it and omit --ssh-key. --admin-username records the user for connection information; it does not create a user when you provide custom data. Documents are limited to 64 KiB of UTF-8, encrypted by the API, and never returned by instance reads. They run only on first boot; changing a local file does not reconfigure an existing VM.

Scripting

--output json emits the API's response body unchanged, with only the list envelope unwrapped. Field names and types are exactly what the API returns, so jq recipes transfer between curl and cloudconsole. Table output carries no such promise — do not parse it.

Progress and warnings go to stderr, so this is safe:

id=$(cloudconsole instance create … --wait -o json | jq -r .id)

Exit codes are stable; cloudconsole exit-codes prints the full table. The ones worth branching on:

Code Meaning
0 success
3 authentication failed
4 permission denied (read-only key, or a disabled service)
5 not found
6 the resource is busy with another operation
7 quota exceeded
12 --wait timed out (the operation may still finish)

GitHub Actions

- name: Provision a build VM
  env:
    CLOUDCONSOLE_API_TOKEN: ${{ secrets.CLOUDCONSOLE_API_TOKEN }}
  run: |
    curl -fsSL https://raw.githubusercontent.com/studio-ch/cloudconsole-cli/main/install.sh | sh
    id=$(cloudconsole instance create \
      --name "ci-${GITHUB_RUN_ID}" --region ZRH1 \
      --image ghcr.io/example/macos-sequoia:latest \
      --cpu 10 --memory 28 --disk 480 \
      --wait -o json | jq -r .id)
    echo "INSTANCE_ID=$id" >> "$GITHUB_ENV"

- name: Tear down
  if: always()
  env:
    CLOUDCONSOLE_API_TOKEN: ${{ secrets.CLOUDCONSOLE_API_TOKEN }}
  run: cloudconsole instance delete "$INSTANCE_ID" --yes --wait

--yes is required for destructive commands without a terminal — the CLI refuses rather than guessing.

Configuration

~/.config/cloudconsole/config.yaml, created with 0600 permissions because it holds a token; the CLI refuses to read it if the permissions are looser.

Settings resolve per field: flag, then environment (CLOUDCONSOLE_API_URL, CLOUDCONSOLE_API_TOKEN, CLOUDCONSOLE_OUTPUT, CLOUDCONSOLE_PROFILE), then the profile, then the default. So a token from the environment combines with a URL from the profile — the usual CI arrangement. cloudconsole config explain shows what was resolved and from where.

The default endpoint is https://api.cloud.flow.swiss. Point the CLI at a different deployment with --api-url, CLOUDCONSOLE_API_URL, or an api_url in the profile — one profile per environment is the usual shape.

To keep the secret out of the file, use a command instead:

profiles:
  prod:
    api_url: https://api.cloud.flow.swiss
    token_command: op read op://Private/cloud/api-key

Troubleshooting

--debug traces every request to stderr with the credential redacted to its public prefix. Every error carries a request-id — quote it to support.

Related

  • REST API — the CLI is a client of the documented public API; anything it does can be done with curl.
  • MCP server — connect an AI client to your account with the same key.
  • Packer plugin — studio-ch/packer-plugin-cloudconsole bakes custom macOS images.

Not covered

The CLI authenticates with an API key, and some parts of the panel are not reachable that way: the VM console and terminal, the AI assistant, the admin area, and issuing or revoking API keys (listing works; issuing is a panel operation).

About

Command-line interface for the Cloud Console — source mirror, releases and installer

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages