@carbonbits/cli
v0.2.3
Published
Carbonbits platform CLI
Readme
carbonctl
Command-line client for the Carbonbits platform. Built with Bun, citty for the command tree and clack for the interactive prompts.
Install
On macOS or Linux, install the self-contained binary (no Bun needed) with:
curl -fsSL https://cli.carbonbits.co.ke/setup.sh | shIt installs to ~/.local/bin and checks the download against the release's
SHA256SUMS. Set CARBONCTL_VERSION=0.2.0 to pin a release or
CARBONCTL_INSTALL_DIR=/usr/local/bin to install elsewhere.
Keep it current with carbonctl update (--check to only look, or
carbonctl update 0.2.0 to install a specific release, older ones included).
With Bun (the package ships TypeScript source and needs Bun >= 1.3):
bunx @carbonbits/cli --help
bun install -g @carbonbits/cliOr download a self-contained binary for macOS, Linux or Windows from the
GitHub releases; verify it against
the attached SHA256SUMS.
From a checkout:
bun install
bun run dev -- --help # run from source
bun link # puts `carbonctl` on your PATH, running from this checkout
bun run build # self-contained binary at dist/carbonctl (stack charts embedded)
bun run build:release # binaries for every platform in dist/bin/
bun testReleases are cut automatically from conventional commits on master; see
CONTRIBUTING.md.
Commands
carbonctl auth login Authenticate (browser device flow or API token); --local keeps it in .carbon/
carbonctl auth status Show the current session and where it is stored (alias: whoami)
carbonctl auth token Print the access token, e.g. for curl
carbonctl auth logout Revoke and forget the session
carbonctl init Create carbon.yaml and .carbon/ for the app in the current directory
carbonctl deploy Generate Helm chart + ArgoCD Application from carbon.yaml
carbonctl shell Interactive shell with slash commands (default with no args)Every command accepts --help.
Authentication
carbonctl auth login offers two methods:
- Browser (device code) — the default. carbonctl requests a one-time code from
the platform, opens the verification page, and waits until you approve it.
Pass
--no-browserto only print the URL (SSH sessions, containers). - API token —
carbonctl auth login --token <TOKEN>, or setCARBON_TOKEN. The token is verified against the API before it is stored.
Where the session lives
Commands look for a session in this order and use the first one found:
| Scope | Source | Meant for |
| --------- | ---------------------------------------- | ------------------------------------------ |
| env | CARBON_TOKEN | CI. Nothing is written to disk. |
| project | <project>/.carbon/credentials.json | auth login --local: one org per checkout |
| global | ~/.config/carbonctl/credentials.json | auth login: your default identity |
In CI you only export CARBON_TOKEN; no auth login step is needed. Credential files are
written with mode 0600, and expiring tokens are refreshed transparently when a refresh
token is available. auth status shows which scope is in effect.
| Setting | Flag | Environment | Default |
| -------------- | ------------- | -------------------- | -------------------------- |
| API base URL | --api-url | CARBON_API_URL | https://api.carbonbits.co.ke |
| OAuth client | --client-id | CARBON_CLIENT_ID | carbonctl |
| Config folder | | CARBONCTL_CONFIG_DIR, XDG_CONFIG_HOME | ~/.config/carbonctl |
Both settings also read .carbon/config.yaml (project) before ~/.config/carbonctl/config.json
(user), so a project can pin the platform it deploys to.
Scripting:
curl -H "$(carbonctl auth token --header)" "$CARBON_API_URL/v1/me"
carbonctl auth status --jsonThe device flow follows RFC 8628. Endpoint paths are collected in
src/lib/auth/client.ts (AUTH_PATHS).
Slash commands
Run carbonctl with no arguments in a terminal to enter the shell. Every command is
available as a slash command with the same flags:
carbonctl /auth login --no-browser
carbonctl / ← pick from a menu
carbonctl /help auth login
carbonctl /exitSlash syntax also works directly from your shell: carbonctl /auth status.
The manifest and .carbon/
carbonctl init writes two things next to each other:
carbon.yaml the manifest — committed
.carbon/
.gitignore written by carbonctl; ignores credentials.json and cache/
config.yaml project settings (apiUrl, clientId) — committed
credentials.json session from `auth login --local` — never committed
cache/carbon.yaml describes the app:
name: n8n # lowercase, digits, dashes — becomes the Kubernetes name
stack: nodejs # a bundled stack, see src/stacks/
version: 18 # stack runtime versioncarbon.yml is accepted too. The old name carbon.app.yaml still works with a warning.
Every command finds the project by walking up from the current directory until it meets
.carbon/ or a manifest, stopping at the repository root.
Deploy
carbonctl deploy reads the manifest (-f PATH or CARBON_MANIFEST to pick one, e.g. in a
monorepo matrix job) and produces, next to it:
apps/v0/run/<name>-<stack>-<version>/ copy of src/stacks/<stack>/chart
apps/v0/templates/<name>-<stack>-<version>.yaml ArgoCD Application--app-version (or APP_VERSION) sets appVersion in the generated Chart.yaml.
Stack charts live under src/stacks/.
Layout
Every command is a handler class plus a thin citty adapter, so handlers can call each other
(init runs Login first when there is no session) and tests can drive them without argv:
bin/carbonctl.ts entrypoint
src/cli.ts root command, argv normalization, error reporting
src/commands/<group>/handlers/<name>/index.ts the handler: `class Name extends BaseHandler<Input, Output>`
src/commands/<group>/handlers/<name>/command/ the citty definition: argv → Input, Output → terminal
src/commands/auth/index.ts the `auth` group
src/commands/{init,deploy}/ root-level commands: same shape, no group
src/lib/core/handler/ BaseHandler (run, call, sign)
src/lib/core/context/ Context: cwd, UI port, resolved project
src/lib/ui.ts UI port (clack-backed and silent implementations)
src/lib/project.ts .carbon/ discovery and project config
src/lib/manifest.ts carbon.yaml lookup and validation
src/lib/auth/ OAuth client, session store (env/project/global)
src/lib/deploy/ GitOps artifact generation
src/stacks/ Helm charts per stack + ArgoCD templateImports use the @/ (src) and @root/ (repository) aliases from tsconfig.json; no relative paths.
Stack charts are embedded into the compiled binary through the generated
src/stacks/manifest.ts. After adding or removing files under src/stacks/, run
bun run gen:stacks (the build does this automatically, and a test checks it is current).
Set CARBONCTL_DEBUG=1 to see stack traces.
