From 5eddc2dd9e32de3e6679c5f83bce426e2e5d410e Mon Sep 17 00:00:00 2001 From: lolwierd Date: Tue, 4 Aug 2026 12:42:48 +0530 Subject: [PATCH] Document switch, print-id-token, email, stream, and volume attachment commands The skill had drifted from the CLI: exc switch, exc print-id-token, the entire exc email and exc stream command groups, and volume attach/detach were all missing. The output-formats section also claimed there was no universal JSON flag, which is no longer true now that --output json is global on every command. --- skills/excloud-cli/SKILL.md | 62 ++++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 11 deletions(-) diff --git a/skills/excloud-cli/SKILL.md b/skills/excloud-cli/SKILL.md index 2eee8cf..2ef80a5 100644 --- a/skills/excloud-cli/SKILL.md +++ b/skills/excloud-cli/SKILL.md @@ -1,6 +1,6 @@ --- name: excloud-cli -description: Drive Excloud resources (compute, networking, security groups, volumes, snapshots, public IPs, IAM, billing, Kubernetes, object storage buckets, secrets) through the `exc` CLI. Use when a user asks to plan or execute `exc` commands - creating / inspecting / updating / deleting VMs, running commands on them via `exec` / `scp` / `console`, managing security groups and public IPs, pulling Kubernetes kubeconfigs, managing buckets/objects/access keys, or saving / revealing / rotating org secrets - with safety guardrails and auth checks. +description: Drive Excloud resources (compute, networking, security groups, volumes, snapshots, public IPs, IAM, billing, Kubernetes, object storage buckets, secrets, transactional email, stream/Kafka clusters) through the `exc` CLI. Use when a user asks to plan or execute `exc` commands - creating / inspecting / updating / deleting VMs, running commands on them via `exec` / `scp` / `console`, managing security groups and public IPs, pulling Kubernetes kubeconfigs, managing buckets/objects/access keys, saving / revealing / rotating org secrets, sending transactional email, or managing stream clusters - with safety guardrails and auth checks. --- # Excloud CLI @@ -23,7 +23,7 @@ Everything below has been observed working at some point; the model should still - Confirm before anything destructive (see Safety). - If authentication is missing or expired, tell the user to run `exc login` and stop — do not invent tokens. - When flag names or behaviours look odd, run `exc <...> --help` rather than guessing. Generated CLIs evolve between releases. -- Read `list` / `get` output shapes carefully before trying to parse them; there is no universal `-o json` flag today (see Output formats). +- Read `list` / `get` output shapes carefully before trying to parse them; pass the global `--output json` flag for machine-readable output (see Output formats). ## Authentication @@ -37,6 +37,10 @@ If none of those are present or valid, commands that need a token (`exec`, `scp` `exc me`, `exc org list`, `exc account list`, `exc config list` are useful "where am I?" probes after login. +`exc switch [account] [organization] [--list]` lists or switches between account/org contexts already logged into `~/.exc/config`. With no args on an interactive TTY it opens a `j`/`k`/arrow-key picker; non-interactively (or with `--list`, or `--output json`) it prints the context table instead — use that form when scripting or running non-interactively. `exc switch ` switches directly if the account has exactly one org, otherwise pass `[organization]` too. It also silently prunes stale (401/403) contexts from the config file on every run. + +`exc print-id-token` prints the current user's raw ID token (from env or `~/.exc/config`) to stdout — useful for piping into other tools that need a bearer token. Treat its output as a credential. + ## Safety guardrails Require explicit user confirmation before running any of these: @@ -50,6 +54,8 @@ Require explicit user confirmation before running any of these: - `exc buckets delete`, `exc buckets rm`, `exc buckets objects delete`, recursive bucket/object deletes, and `exc buckets multipart abort`. - `exc buckets keys delete`; also treat `exc buckets keys create` output as sensitive because the secret is shown once. - `exc secret delete` (soft-delete, no undo); also `exc secret reveal` — every call writes an audit event, so don't run it for "discovery". +- `exc compute volume detach`, `exc stream terminate`, `exc stream topic delete`, `exc stream user delete`, `exc stream acl delete`. +- `exc email domain delete`, `exc email template delete`, `exc email smtp delete`, `exc email config-set delete`, `exc email suppression delete`; also treat `exc email smtp create` output as sensitive (one-time password) like bucket key creation. For shell commands delivered through `exc compute exec` or an `exec` script file, refuse or confirm explicitly before running anything like `shutdown`, `reboot`, `rm -rf`, `mkfs`, `dd`, `wipefs`, rewrites of `/etc/fstab`, bootloader edits, or `systemctl stop ssh*` (the last one will make the VM unreachable over SSH — see Interactive access). @@ -262,6 +268,13 @@ exc compute volume list # the root volume should disappear / move to - `exc compute volume delete --volume_id ` (destructive). - `exc compute snapshot list` / `exc compute snapshot create --volume_id ` / `exc compute snapshot delete --snapshot_id ` +### Volume attachment (non-root volumes) + +- `exc compute volume attach --vm_id --volume_id [--wait]` — attaches an existing volume to a running VM as a secondary disk. +- `exc compute volume detach --vm_id --volume_id [--wait]` +- `exc compute volume attachments list [--vm_id ] [--volume_id ]` — cross-VM attachment table; omit both filters to list every attachment in the account. +- `exc compute volumes --vm_id ` — shortcut table of every volume (root and attached) on one VM, including `ATTACHMENT_STATE` and `IS_ROOT`. Note this is a sibling of `exc compute volume` (singular), not a subcommand of it. + ## SSH key catalog - `exc compute key list` / `exc compute key get --id ` @@ -277,7 +290,7 @@ exc compute volume list # the root volume should disappear / move to - The response contains the admin kubeconfig inline. Passing `-o ` writes it to disk (mode 0600, creating parent dirs) and strips it from stdout — strongly preferred. - `exc k8s cluster delete --cluster_id ` (destructive). - `exc k8s cluster worker list --cluster_id ` -- `exc k8s cluster worker create --cluster_id --worker_image_id --worker_instance_type --subnet_id --root_volume_size_gib [--allocate_public_ipv4] [--security_group_ids ] [--ssh_pubkey ""]` +- `exc k8s cluster worker create --cluster_id --worker_image_id --worker_instance_type --subnet_id --root_volume_size_gib [--allocate_public_ipv4] [--security_group_ids ] [--ssh_pubkey ""] [--karpenter_managed]` - `exc k8s cluster worker delete --cluster_id --worker_id ` (destructive). - `exc k8s cluster kubeconfig get --cluster_id [-o ]` — fetches the current kubeconfig and prints to stdout (or writes to `-o` with mode 0600). Returns a clear 404 if the cluster id is unknown. - `exc k8s cluster kubeconfig merge --cluster_id [--kubeconfig ] [--backup=true|false]` — merges into `~/.kube/config` (or `--kubeconfig`) using `kubectl config view --merge --flatten --raw`. Requires `kubectl` on PATH. `--backup` defaults to `true` and writes `.bak`, `.bak1`, ... before overwriting. @@ -406,7 +419,7 @@ Notes: - `--count`, `--root_volume_gib`, `--baseline_iops`, `--baseline_throughput_mbps`, and `--monthly_egress_gib` are optional numeric inputs. Omitted or zero values let the service apply its defaults where supported; pass explicit values when mirroring a planned `compute create`. - `--monthly_egress_gib` is a floating-point flag, so decimal values are valid if the installed help shows it. - `--has_public_ipv4` is boolean; pass `--has_public_ipv4=true` when estimating a public IPv4 allocation. -- The command uses the default zone from CLI config; there is normally no user-facing `--zone_id` flag in the generated command. +- The command uses the default zone from CLI config; there is normally no `--zone_id` flag. - Output is a human-readable cost table with component rows (`Instance`, optional `Storage`, optional `Network`) and `TOTAL` / hourly summary rows. It is for display and comparison, not JSON scripting. - If the service has no price data for an instance type, the command prints `No pricing data found for instance type: `. @@ -434,6 +447,32 @@ Notes: - `--granularity` accepts `auto`, `hourly`, `daily`, or `monthly`. Hourly is limited to about 7 days, daily to about 31 days, and monthly to about 6 months. - Table output includes `TOTAL`, cost, share percentage, and a best-effort usage display. Use `--json` for scripts. +## Transactional email + +`exc email` sends/manages transactional email through Excloud's email service. Always check `exc email --help` and the relevant subgroup `--help` first — most email subcommands have their own `--json` flag in addition to the global `--output json`. + +- `exc email domain create --name [--mail-from-domain ] [--auto-create-dns] [--wait]` — register a sender domain. `--auto-create-dns` provisions the verification DNS records automatically if the domain lives in an Excloud DNS zone; otherwise use `check-dns` to see what to add manually. +- `exc email domain list` / `exc email domain get --id ` / `exc email domain verify --id [--wait]` / `exc email domain check-dns --name ` / `exc email domain delete --id [--yes]` (destructive). +- `exc email send --from --to [--to ...] [--cc ...] [--bcc ...] [--reply-to ...] --subject (--text | --text-file ) [--html | --html-file ] [--template --data key=value ...] [--config-set ] [--tag key=value ...]` — `--from` and at least one `--to` are required; repeat `--to`/`--cc`/`--bcc`/`--reply-to`/`--data`/`--tag` for multiple values. +- `exc email message get --message-id ` / `exc email event list [--message-id ]` / `exc email metrics [--domain-id ]` +- `exc email template create --name --subject (--html | --html-file ) [--text | --text-file ]` / `exc email template list` / `exc email template delete --id [--yes]` +- `exc email smtp create --name --domain-id [--show-password | --copy-password]` — generates SMTP credentials; the one-time password is only ever shown/copied at creation, capture it immediately. Treat it as sensitive. +- `exc email smtp list` / `exc email smtp delete --id [--yes]` +- `exc email config-set create --name [--webhook-url ] [--suppression-reason BOUNCE|COMPLAINT ...] [--list-management] [--track-opens] [--track-clicks]` / `exc email config-set list` / `exc email config-set delete --id [--yes]` +- `exc email suppression put --email --domain-id [--reason MANUAL|BOUNCE|COMPLAINT|UNSUBSCRIBE]` / `exc email suppression list [--domain-id ]` / `exc email suppression delete --email --domain-id [--yes]` + +## Stream (managed Kafka-compatible clusters) + +`exc stream` manages stream clusters and their topics/users/ACLs. Always check `exc stream --help` first; cluster create takes compute-style sizing flags similar to `exc compute create` (instance type, subnet, root volume, security groups) plus stream-specific `--allowed_cidrs`. + +- `exc stream create --name --instance_type --subnet_id --root_volume_size_gib [--security_group_ids ] [--allowed_cidrs ] [--ssh_pubkey ""] [--baseline_iops ] [--baseline_throughput_mbps ] [--wait]` — `--wait` polls for `RUNNING`. +- `exc stream list` / `exc stream get --id ` / `exc stream bootstrap --id ` (bootstrap-server connection metadata) +- `exc stream restart --id [--wait]` / `exc stream terminate --id [--wait]` (destructive) +- `exc stream topic create --id --name [--partitions ] [--replication_factor ] [--retention_ms ] [--cleanup_policy ]` +- `exc stream topic list --id ` / `exc stream topic patch --id --name [--partitions ] [--retention_ms ] [--cleanup_policy ]` / `exc stream topic delete --id --name ` (destructive) +- `exc stream user create --id --username ` — creates a SCRAM user. `exc stream user list --id ` / `exc stream user rotate --id --username ` (rotates password) / `exc stream user delete --id --username ` (destructive) +- `exc stream acl create --id --principal

--resource_type --resource_name --operation [--permission_type ] [--pattern_type ] [--host ]` / `exc stream acl list --id ` / `exc stream acl delete --id --acl_id ` (destructive) + ## Config and misc - `exc me` / `exc version` / `exc completion ` @@ -442,14 +481,15 @@ Notes: ## Output formats -Every command either prints a column table (or TSV) or prints JSON — no command should print raw Go-struct dumps anymore. Both shapes are machine-parseable; pick your tool accordingly. +Every `exc` command accepts a **global `--output table|json` flag** (default `table`): `exc compute list --output json`, `exc compute create ... --output json`, etc. Prefer this over scraping tables for any scripting. -- **Column tables / TSV** (awk / `cut` / `awk -F\t` friendly): `compute list`, `compute get`, `compute create`, `compute terminate` (TSV `vm_id\tstate`), `compute instancetype list` / `capacity`, `compute image list`, `compute subnet list`, `compute volume list`, `compute volume get`, `compute snapshot list`, `compute publicip list`, `compute key list`, `securitygroup list` / `rule list` / `binding list`, `org list`, `account list`, `apikey list`, `policy list`, `billing estimate`, `billing costs`, `config list`, `compute seriallogs`, `buckets list`, `buckets ls`, `buckets objects list`, `buckets keys list`, `buckets multipart list`. -- **JSON** (pipe through `jq`): `me`, `quota`, `billing get`, `compute health` (`{"raw":"OK"}`), `k8s health`, `compute subnet get`, `compute publicip get`, `compute key get`, `securitygroup get`, `compute metrics`, `compute connect`, `serviceaccount list`, `compute protect`, `compute unprotect`, `compute rename`, `k8s cluster kubeconfig get` (raw kubeconfig YAML, not JSON-wrapped), `buckets get`, `buckets usage`, `buckets keys create`, multipart create/uploadpart/complete/abort, and the inline `kubeconfig` field inside the JSON response from `k8s cluster create` when `-o` is not set. +- With `--output json`, commands print the API response as indented JSON to stdout instead of their normal table/line output. `--wait` progress lines go to stderr in this mode so stdout stays clean JSON. +- Without `--output json`, commands print a column table (or TSV for a couple of terse ones like `compute terminate`). +- `exc email ...` subcommands and most of `exc buckets ...` (`buckets list --json`, `buckets objects list --json`, `billing costs --json`, etc.) also accept their **own** `--json` flag alongside the global `--output json`. For those, check the command's own `--help` rather than assuming `--output json` alone covers it. +- `buckets objects presign` and `buckets objects share` intentionally print only the URL (plus expiry for `share`) regardless of output mode, so they can be piped to tools like `pbcopy`. +- `k8s cluster kubeconfig get` prints raw kubeconfig YAML to stdout (not JSON-wrapped) unless `-o ` is set. -Many bucket list/delete commands and `billing costs` have explicit `--json`; use it for scripts instead of scraping tables. `buckets objects presign` intentionally prints only the URL so it can be piped to tools like `pbcopy`. - -Before scripting heavy logic against a command, run it once and check the shape. The split between "table" and "JSON" is not always guessable — lists tend to be tables, getters tend to be JSON, but verify. +Before scripting heavy logic against a command, run it once with and without `--output json` and check the shape — coverage of the global flag varies by command family, so verify rather than assume. ## Metrics @@ -461,7 +501,7 @@ Before scripting heavy logic against a command, run it once and check the shape. ## Error messages to recognise - `not authenticated; run \`exc login\`` — no valid token in env or `~/.exc/config`. -- `required flag(s) "" not set` — cobra-level enforcement. Read `--help` again. +- `required flag(s) "" not set` — a required flag is missing. Read `--help` again. - `Could not parse your request!! Are you sure you passed the correct flags?` — generic backend 400. Typically means an unknown ID, a value of the wrong type, or a server-side required field that the CLI accepted as empty. Verify every ID against a `list` before retrying. - `Oops could not find the you specified, maybe try checking if the exists?` — backend 404-ish. Trust the hint. - `Oops the IP provided is invalid` — syntactic IP validation on `compute localip`.