Skip to content
kaitencloudPublic

About

No description, website, or topics provided.

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

Kaiten CLI

CI Release Go Report Card License

kaiten is the command-line interface for the Kaiten API. It manages customers, instances, licenses, entitlements, feature flags, components, releases and service accounts from a terminal or a script, with table, JSON and YAML output and exit codes a script can branch on.

Installation

Every method below installs the same binary from the GitHub release. Check what you got with kaiten version.

macOS

curl -fsSL https://raw.githubusercontent.com/kaitencloud/cli/main/install/install.sh | sh

The script verifies the archive against the release's checksums.txt and installs into /usr/local/bin (KAITEN_INSTALL_DIR changes that).

Linux

curl -fsSL https://raw.githubusercontent.com/kaitencloud/cli/main/install/install.sh | sh

Or a package for your distribution (replace amd64 with arm64 as needed). Each installs the binary and shell completions:

# Debian, Ubuntu
curl -fsSLO https://github.com/kaitencloud/cli/releases/latest/download/kaiten_linux_amd64.deb
sudo dpkg -i kaiten_linux_amd64.deb

# Fedora, RHEL, openSUSE
sudo rpm -i https://github.com/kaitencloud/cli/releases/latest/download/kaiten_linux_amd64.rpm

# Alpine
curl -fsSLO https://github.com/kaitencloud/cli/releases/latest/download/kaiten_linux_amd64.apk
sudo apk add --allow-untrusted kaiten_linux_amd64.apk

Windows

irm https://raw.githubusercontent.com/kaitencloud/cli/main/install/install.ps1 | iex

The script verifies the archive against checksums.txt, installs kaiten.exe into %LOCALAPPDATA%\Programs\kaiten (no administrator rights needed) and adds it to your user PATH.

Container

docker run --rm -e KAITEN_BASE_URL -e KAITEN_AUTH_TOKEN ghcr.io/kaitencloud/cli:latest instances list

ghcr.io/kaitencloud/cli is tagged latest and with each version, built for linux/amd64 and linux/arm64, and runs as a non-root user. Pass the configuration through the environment: the image keeps no config file between runs.

Go

With Go 1.25 or newer:

go install github.com/kaitencloud/cli/cmd/kaiten@latest

Binaries

Every release attaches kaiten_<os>_<arch>.tar.gz (.zip on Windows) for Linux, macOS and Windows on amd64 and arm64, with a checksums.txt of SHA-256 sums. Unpack it and put kaiten on your PATH.

A specific version

curl -fsSL https://raw.githubusercontent.com/kaitencloud/cli/main/install/install.sh | sh -s -- 1.2.3
& ([scriptblock]::Create((irm https://raw.githubusercontent.com/kaitencloud/cli/main/install/install.ps1))) -Version 1.2.3

go install ...@v1.2.3 and the container tags pin a version directly.

Shell completion

The Linux packages and the archives ship completions for bash, zsh and fish. Any other install can generate them from the binary:

kaiten completion zsh > "${fpath[1]}/_kaiten"
kaiten completion bash > /etc/bash_completion.d/kaiten
kaiten completion fish > ~/.config/fish/completions/kaiten.fish
kaiten completion powershell | Out-String | Invoke-Expression

Quick start

kaiten config set base-url https://kaiten.example.com/api
kaiten config set auth-token "$KAITEN_TOKEN"
kaiten doctor                      # checks the configuration and reaches the API
kaiten instances list
kaiten instances get acme-production --output json

The base URL includes the API's path prefix, and the token is an organization-scoped Kaiten token. See the Kaiten documentation for how to obtain one.

Configuration

Three settings are resolved for every invocation, in this order: flag, environment variable, config file.

Setting Flag Environment variable Config key
API base URL --base-url KAITEN_BASE_URL base_url
Bearer token --auth-token KAITEN_AUTH_TOKEN auth_token
Output --output KAITEN_OUTPUT output

The config file lives in the user's configuration directory (~/.config/kaiten/config.yaml on Linux, ~/Library/Application Support/kaiten/config.yaml on macOS, %AppData%\kaiten\config.yaml on Windows) and is written with 0600 permissions. kaiten config manages it:

kaiten config set output json
kaiten config view
kaiten config unset auth-token

kaiten doctor shows the base URL and (masked) token the current invocation resolves to, then lists the instances with them to prove the API is reachable and the token accepted.

Commands

Command Operations
kaiten customers list, get, create, update, delete
kaiten instances list, get, create, update, delete, audit-trails, usage list|get|report
kaiten licenses list, get, create, update, delete, entitlements list|get|associate|update|delete
kaiten entitlements list, get, create, update, delete
kaiten entitlement-groups list, get, create, update, delete, add-entitlement, remove-entitlement, usage
kaiten feature-flags list, get, create, update, delete
kaiten components list, get, create, update, delete
kaiten releases list, get, create, delete
kaiten service-accounts list, get, create, update, tokens list|create|delete
kaiten deployment-zones list, get, create, update, delete
kaiten config set, unset, view
kaiten doctor Validate configuration and API connectivity
kaiten version Print version, commit and build date

kaiten <command> --help lists every flag.

Usage

Reading

kaiten customers list
kaiten licenses get team-v1 --output yaml
kaiten licenses entitlements list team-v1
kaiten instances audit-trails acme-production --event-name INSTANCE_UPDATED --after 2026-01-01T00:00:00Z --limit 100

--output (or KAITEN_OUTPUT) selects table, json or yaml.

Without it, the format follows what the command returns. A list prints a table. A single resource (get, create, a usage report, a new token) prints YAML, and so does --output table there, a single resource having no columns. A command the API answers with no body (delete, most updates) prints one line, or a document with a message key under --output json and --output yaml.

JSON and YAML output carry the same document: the API's field names and values, in the same order.

Writing

Every create and update accepts its input three ways. They are mutually exclusive.

# Inline flags, for the fields a resource has
kaiten customers create --name "Acme Corp" --external-customer-id crm-4711

# A JSON or YAML file; "-" reads stdin
kaiten instances create --file instance.yaml
cat instance.json | kaiten instances update acme-production --file -

# An inline JSON or YAML payload
kaiten components create --payload '{"name": "api", "version": "1.4.0"}'

Feature flags carry targeting rules and variants, so feature-flags create and update take --file or --payload only.

A file or a payload uses the API's field names, in JSON or in YAML, and both make the same request:

# customer.yaml
name: Acme Corp
externalCustomerId: crm-4711

A YAML document is read as the JSON it stands for. A value written bare for a text field stays text (version: 1.0 is the version 1.0), and a YAML key the request has no field for is an error that names the key, before anything is sent. JSON skips such a key instead, so a resource printed with --output json can be edited and written back with the fields only the API sets (id, createdAt, ...) still in it; printed as YAML, it has to lose them first.

With inline flags, instances update keeps what its optional flags leave out: the deployment zone, the slug, and the metadata, which the command reads from the instance and sends back unless --metadata-json gives another (--metadata-json '{}' clears it).

Licenses and entitlements

kaiten licenses entitlements associate team-v1 seats --number 25
kaiten licenses entitlements associate team-v1 sso --boolean=true
kaiten licenses entitlements associate team-v1 limits --object-payload '{"max": 10}'

# A soft limit: 1000 orders a month, refused past 1200
kaiten entitlements create --name "Monthly orders" --slug monthly-orders --type NUMBER \
  --aggregation-method SUM --reset-period MONTH --warning-threshold-percent 80
kaiten licenses entitlements associate team-v1 monthly-orders --number 1000 --overage-percent 20

# Change the value; the grant keeps its 20 % allowance
kaiten licenses entitlements update team-v1 monthly-orders --number 1500

The API replaces an entitlement or a grant with what it is sent, resetting what the request leaves out. So both update commands read the resource first and send back what the invocation does not change, each in its own way:

  • entitlements update does it with inline flags: every field the flags do not name is sent back as it was read, so a periodic entitlement keeps its window, which the API refuses to see dropped. --file and --payload are sent as written there, and carry every field the entitlement keeps.
  • licenses entitlements update does it whenever --overage-percent is absent, whatever carries the value: --number, --boolean, an object, or --file and --payload, which hold the value and nothing else. The grant keeps its allowance when the new value is a finite number. --overage-percent sets another, and the grant is then not read.

The API numbers the versions of a license itself. licenses create has no --version, and on licenses update the flag does not set the version: it states the one the license is expected to have, and the API refuses the update when the license has another.

Usage metering

# Report a delta (the default behaviour) or set the absolute value
kaiten instances usage report acme-production api-calls --value 1
kaiten instances usage report acme-production seats --value 18 --behavior set

kaiten instances usage list acme-production
kaiten entitlement-groups usage compute acme-production

Service account tokens

kaiten service-accounts tokens create deploy-bot --name "zone-eu-west-1" \
  --scope write:instances --scope read:feature_flags \
  --expires-at 2026-12-31T00:00:00Z

The plaintext token is printed once; the API stores a hash.

Destructive commands

delete, remove-entitlement and config unset echo their target and ask for confirmation. When stdin is not an interactive terminal they refuse to run instead of prompting, so scripts and CI pipelines pass --yes:

kaiten customers delete acme --yes

Without --yes (-y), a run that cannot prompt changes nothing and exits with code 2. At the prompt, any answer but y or yes cancels the command, which exits with code 1.

Exit codes

Every command reports the kind of failure through its exit code, so a script can branch on it without parsing the error text.

Code Meaning
0 The command succeeded.
1 The command failed for a reason the CLI could not classify.
2 Wrong invocation: an unknown command or flag, the wrong number of arguments, a nonsensical flag combination, or a configuration the CLI cannot use.
3 The API refused the credentials or the operation (HTTP 401, 403).
4 The addressed resource does not exist (HTTP 404).
5 The API understood the request and refused it: a validation failure, a conflict, a rate limit (any other HTTP 4xx). Retrying unchanged will not help.
6 The operation did not happen for reasons outside your control: the API could not be reached, timed out, or answered HTTP 5xx. Retrying may help.
130 The run was cancelled by SIGINT or SIGTERM.
kaiten customers get acme || case $? in
  4) echo "no such customer" ;;
  6) echo "kaiten is unreachable, retrying later" ;;
esac

Development

Install Task and Go 1.25+. Tools run through go run <tool>@<version> against the versions pinned in Taskfile.yml, so local runs match CI.

task build          # bin/kaiten
task test           # go test -race -shuffle=on -cover ./...
task lint           # golangci-lint, the version CI runs
task fmt            # gofumpt + gci
task vuln              # govulncheck over reachable code
task release:check     # validate .goreleaser.yaml and the install scripts
task release:snapshot  # build every release artifact into dist/, publish nothing

The API client is github.com/kaitencloud/sdk-go; a change to a request or response shape belongs there. This repository holds the command surface: flags, input sources, output formatting, confirmation prompts and exit codes.

Releasing

Releases are automatic. Nobody pushes a tag.

  1. Every merge to main runs .github/workflows/release.yml. release-please reads the Conventional Commit messages since the last release and opens, or updates, one pull request titled chore: release X.Y.Z. It bumps the version in .release-please-manifest.json and adds the entry to CHANGELOG.md.
  2. Merging that pull request is the release. release-please tags vX.Y.Z and creates the GitHub release with the changelog entry. GoReleaser (.goreleaser.yaml) then builds and attaches everything the Installation section points at: the six binaries and their archives with completions, checksums.txt, the .deb/.rpm/.apk packages and the ghcr.io/kaitencloud/cli image, each with a build-provenance attestation (gh attestation verify <file> --repo kaitencloud/cli).

The commit types decide the version. Before 1.0.0, fix: bumps the patch, and feat: and breaking changes (feat!:, or a BREAKING CHANGE: footer) bump the minor. From 1.0.0, feat: bumps the minor and breaking changes the major. perf:, revert: and build: (dependency bumps included) cut a patch too; docs:, chore:, ci:, test:, refactor: and style: get no changelog entry and cut no release on their own. To force a version, pre-releases included, add a Release-As: 1.2.0-rc.1 footer to a commit. A pre-release is published as a GitHub pre-release: the install scripts' "latest" and the latest image tag keep pointing at the last stable version.

If the GoReleaser job fails after the tag exists, fix the cause and run the Release workflow by hand (Actions → Release → Run workflow) with that tag.

task release:snapshot builds every artifact locally into dist/ without a tag, and task release:check validates the configuration and the install scripts; CI runs the latter on every pull request.

One-time setup, for maintainers:

  • A GitHub App installed on this repository with Contents, Pull requests and Issues set to read and write. Its ID goes in the RELEASE_APP_ID Actions variable and its private key in the RELEASE_APP_PRIVATE_KEY Actions secret. release-please needs it because the release pull request has to run the required checks, and GitHub starts no workflow for a pull request opened with GITHUB_TOKEN.
  • After the first release, make the cli package public in the organization's package settings; new GHCR packages start private.
  • Leave immutable releases off: GoReleaser attaches the artifacts to the release release-please has already published.

Contributing

Issues and pull requests are welcome. Before opening one, run task fmt, task lint and task test. A new command or flag should come with a test in internal/cmd, and a change to what a command prints should keep --output json and --output yaml stable, since scripts depend on them.

License

The Kaiten CLI is open source and licensed under the Apache License, Version 2.0.

By contributing, you agree to certify your contribution under the Developer Certificate of Origin 1.1.

The Kaiten name and logos are not licensed under Apache-2.0. See the Kaiten trademark policy.

About

No description, website, or topics provided.

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages