https://github.com/altinity/acmctl
CLI tool for Altinity Cloud Manager API
https://github.com/altinity/acmctl
Last synced: 20 days ago
JSON representation
CLI tool for Altinity Cloud Manager API
- Host: GitHub
- URL: https://github.com/altinity/acmctl
- Owner: Altinity
- Created: 2026-04-03T17:12:13.000Z (3 months ago)
- Default Branch: master
- Last Pushed: 2026-06-21T14:07:32.000Z (26 days ago)
- Last Synced: 2026-06-21T16:08:05.680Z (26 days ago)
- Language: Go
- Size: 186 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# acmctl
Slim CLI for the [Altinity Cloud Manager API](https://acm.altinity.cloud/docs/),
paired with an `altinity-cloud` Claude Code skill for agent use.
## Who uses what
| Caller | Path |
|---|---|
| Human at a terminal | `acmctl` directly |
| Bash script / CI | `acmctl` — stable interface, JSON output, single binary |
| Agent in Claude Code | `altinity-cloud` skill — curl-direct with workflow recipes |
The skill and the CLI both hit the same API; pick whichever has lower
overhead for your context. Agents save tokens by skipping `--help` and
calling `curl` directly with the patterns the skill provides; humans get
discoverability and tab completion from `acmctl`.
## Design
acmctl exposes a small set of high-touch commands — login, env list/get,
cluster list/get/launch/update/delete/temp-creds — plus a generic `raw`
passthrough for the rest of the API. All output is JSON.
The full hand-curated mapping of all 269 endpoints is preserved in `_legacy/`
as reference material — Go's toolchain ignores `_`-prefixed dirs, so it stays
greppable without participating in the build. Cherry-pick from there if a
specific tier-2 endpoint becomes hot enough to warrant typing.
## The companion skill
The `altinity-cloud` skill lives in this repo at
`skills/altinity-cloud/`. Contents:
- `SKILL.md` — setup, common ops, conventions, per-tag index
- `endpoints/.md` — 20 per-tag endpoint digests (clusters,
environments, billing, …)
- `workflows.md` — multi-step recipes (launch-and-wait,
diagnose-slow-query, …)
Loaded lazily by Claude Code — ~30 tokens of static context until
triggered. When triggered, ~3 KB of guidance loads. Per-tag files
load only when the agent needs an endpoint outside the common-ops
list in SKILL.md.
### Installing the skill
`acmctl skills install` downloads the latest skill bundle (a
`.zip` published by this repo's
[Skill bundle](.github/workflows/skill-bundle.yml) GitHub Action)
and copies it into the per-agent skills directory:
```bash
acmctl skills install # default: --scope global, --agent claude
acmctl skills install --agent codex # ~/.codex/skills/altinity-cloud/
acmctl skills install --all # claude + codex
acmctl skills install --scope project # ./.claude/skills/ (CWD)
acmctl skills install --dry-run # preview, no writes
acmctl skills install --ref v1.0 # pin to a tagged release
acmctl skills update # refresh whatever's installed
```
`install` errors if a local file would be overwritten (rerun with
`--force`); `update` always overwrites — use it when you've made
local edits you want reverted, or just to pull the latest content.
## Installation
```bash
go build -o acmctl .
cp acmctl ~/bin/
```
## Profiles (multi-environment)
A single `~/.acmctl.yaml` can hold multiple ACM environments —
prod, dev, stage, …— and you switch between them per command or
per shell.
```yaml
# ~/.acmctl.yaml
default_profile: prod
profiles:
prod:
url: https://acm.altinity.cloud/api
token:
dev:
url: https://acm.dev.altinity.cloud/api
token:
stage:
url: https://acm.staging.altinity.cloud/api
token:
```
Manage profiles via:
```bash
acmctl config add-profile prod --url https://acm.altinity.cloud/api
acmctl config add-profile dev --url https://acm.dev.altinity.cloud/api
acmctl config add-profile stage --url https://acm.staging.altinity.cloud/api
acmctl config list # show all profiles + which is default
acmctl config get # show the active profile's url + token state
acmctl config use-profile dev # change the default
acmctl config remove-profile dev
```
Select per command (highest precedence wins):
1. `--profile ` flag
2. `ACMCTL_PROFILE` env var
3. `default_profile:` in the config
4. fallback: the only profile, if exactly one is defined
```bash
acmctl --profile dev cluster list
ACMCTL_PROFILE=stage acmctl cluster list
```
Tokens for `login` / `oauth` / `logout` apply to the **active**
profile. `acmctl logout --all` clears tokens from every profile.
A legacy flat config (top-level `url`/`token`, no `profiles:`
section) is auto-loaded as a synthetic `default` profile and
rewritten in the new layout on first save.
## Authentication
Three ways to populate a profile's token, in order of preference:
### 1. 1Password-resolved API key (recommended for unattended use)
Mint a long-lived API key once via the ACM web UI (Account → API
tokens), store it in 1Password, then resolve it at shell start:
```bash
# in ~/.acm.env or your shell rc, with ACM_API_KEY_OP_REF set to
# the op:// reference of the item:
export ACM_API_KEY=$(op read --no-newline "$ACM_API_KEY_OP_REF")
```
`ACM_API_KEY` overrides any token saved in the active profile, so
nothing needs to be on disk. This is what `iso-acm` (the sandboxed
acm wrapper) uses.
### 2. `acmctl oauth` — browser-based PKCE (interactive)
```bash
acmctl --profile prod oauth
```
Opens your default browser to the Auth0 sign-in for the configured
Auth0 tenant, listens on a fixed loopback port (49152, fallback
49153/49154) for the callback, and saves the resulting ACM session
token to the active profile.
> **Status: blocked on an ACM backend change.** The full PKCE flow
> works against Auth0 (token exchange returns a valid id_token), but
> `POST /api/singleauth` rejects id_tokens minted by a Native CLI
> client with "Bad credentials" — the endpoint expects state from
> a flow ACM itself initiated server-side. Tracking:
> [issue #1](https://github.com/Altinity/acmctl/issues/1).
> Until that's resolved, `acmctl oauth` exits with a clear error;
> use the API-key path above instead.
Auth0 setup required (one-time, by an admin of the
`altinity.auth0.com` tenant):
- Native application, **Token Endpoint Authentication Method: None**
- Allowed Callback URLs:
```
http://localhost:49152/cb
http://localhost:49153/cb
http://localhost:49154/cb
```
- Connections enabled: at least the SSO connection users sign in
with (`google-oauth2` and/or any enterprise SSO)
### 3. `acmctl login` — email / password (legacy)
```bash
acmctl --profile prod login
```
Prompts for email + password. Most ACM tenants are SSO-only and
won't accept this; use `oauth` or the API-key path instead. Writes
the token to the active profile.
`--token ` non-interactively writes a known API key without
prompting.
### Sources, in precedence order
For each request, the URL and token are resolved separately:
- **URL**: `--url` flag → `ACMCTL_URL` env → active profile's `url`
- **Token**: `--token` flag → `ACM_API_KEY` env → active profile's `token`
### Logging out
```bash
acmctl logout # clear active profile's token
acmctl --profile dev logout # clear a specific profile's token
acmctl logout --all # clear every profile's token
```
## Commands
### Lifecycle
```bash
acmctl env list
acmctl env get 37
acmctl cluster list # all clusters
acmctl cluster list --env 37 # filter by environment (client-side)
acmctl cluster get 337
acmctl cluster delete 337 # keep resources
acmctl cluster delete 337 --terminate # tear down resources
acmctl cluster temp-creds 337 # → {"password":"..."}
```
### Launch / Update (JSON body on stdin)
```bash
cat < ` covers everything else. Body is auto-detected:
- **No body** — most GETs and DELETEs:
```bash
acmctl raw GET /cluster/337/status
acmctl raw POST /cluster/337/backup
acmctl raw DELETE /cluster/337/0
```
- **JSON body** — pipe on stdin:
```bash
echo '{"name":"foo"}' | acmctl raw POST /cluster/337
```
- **Form-urlencoded** — `-F key=value` (repeatable, supports `@file` to load):
```bash
acmctl raw POST /cluster/337/query -F query='SELECT 1' -F user=admin
acmctl raw POST /cluster/337/kafka-configuration -F filename=k.xml -F xml=@./kafka.xml
```
Combining stdin JSON with `-F` flags is an error.
## Output
All commands emit JSON to stdout. Pipe to `jq` for filtering / extraction. No
table or YAML formatting — agents and scripts both want JSON.
## Restoring richer commands
The 269-endpoint hand-curated implementation lives in `_legacy/cmd/` and
`_legacy/pkg/`. Go's build toolchain ignores directories starting with `_`, so
those files don't compile against the slim build but stay easy to grep.
To bring back, e.g., billing:
```bash
cp _legacy/cmd/billing.go cmd/
cp _legacy/pkg/api/billing.go pkg/api/
# Re-add helpers if needed: collectFieldFlags, flagsToParams (in _legacy/cmd/helpers.go)
go build ./...
```
See `_legacy/README.md`.
## Shell completion
```bash
source <(acmctl completion bash)
acmctl completion zsh | source
acmctl completion fish | source
```