kmq CLI
Drive KubeMQ from the terminal with the kmq command-line client — messaging, observability, contexts, roles, and the installable agent skill.
kmq is KubeMQ's command-line client — a single static Go binary that talks to the
KubeMQ management API on port :8080 (the same API the web dashboard uses). It is
built to be agent-native: predictable output, typed exit codes, and a
self-describing command tree make it a first-class tool for AI coding agents as well as
human operators.
Overview
kmq exposes every messaging pattern — Queues, Events, Events Store, and RPC
(Commands/Queries) — plus full observability (status, metrics, connections, audit,
connectors, agents) and a set of meta/discovery commands. Four properties make it
suited to automated and agent-driven use:
- Token-efficient — a
kmq queue sendis a few hundred tokens versus a multi-round exchange over a protocol like MCP. - Deterministic — typed exit codes and machine-readable
json/ndjsonoutput make results easy to branch on in a script or an agent loop. - Self-describing —
kmq schemaemits the whole command tree, offline, with no network call. - Bounded by default — every stream/subscribe/replay command honors
--count/--duration/--idle, so an agent can never loop forever waiting on it.
Scope
kmq is a client of the management API — it does not embed the broker, and it never
talks to the message broker directly. Every action is an HTTP call to the :8080
management API. kmq mcp reads the server's registered MCP tools; it does not make
kmq itself an MCP server.
Architecture
kmq never talks to the message broker directly. Every action is an HTTP call to the
:8080 management API: one-shot actions dispatch via POST /api/request
({type, data}) or dedicated REST routes, and streaming commands use Server-Sent
Events / WebSocket subscription endpoints. Meta commands (schema, cheat, skills)
serve content compiled into the binary, so they work fully offline and never need
the server.
Installation
# Primary — GitHub Releases (kubemq-io/kmq), no credentials
curl -sSfL https://raw.githubusercontent.com/kubemq-io/kmq/main/install.sh | sh
# Pin a version, or verify the cosign signature strictly
curl -sSfL https://raw.githubusercontent.com/kubemq-io/kmq/main/install.sh | sh -s -- --version v0.3.1
curl -sSfL https://raw.githubusercontent.com/kubemq-io/kmq/main/install.sh | sh -s -- --verify-signature
# Container image (no install)
podman run --rm europe-docker.pkg.dev/kubemq/images/kmq:latest versioninstall.sh detects OS (linux/darwin/windows) and architecture (amd64/arm64),
resolves the version, downloads the archive plus checksums.txt, and performs a
mandatory SHA-256 verification — the install aborts if it cannot verify the
checksum. An optional cosign signature check runs on top of that (best-effort by
default, strict when requested), and the binary installs to the first writable PATH
directory.
| Install env var | Purpose |
|---|---|
KMQ_VERSION | Explicit version to install (e.g. v0.3.1) |
KMQ_INSTALL_DIR | Target directory for the kmq binary |
KMQ_BASE_URL | Mirror/staging base URL (switches to mirror mode) |
KMQ_PREFIX | Object prefix for a mirror (default kmq) |
KMQ_VERIFY_SIGNATURE | Set to 1 to require a valid cosign signature |
Contexts & configuration
A context is a named connection profile (API address, token, TLS, defaults).
Contexts live under $XDG_CONFIG_HOME/kmq/ (~/.config/kmq/ by default):
$XDG_CONFIG_HOME/kmq/
├── contexts/
│ ├── default.json
│ └── prod.json
└── current-context # pointer file (active context name)kmq context create default --api-address http://localhost:8080
kmq context create prod \
--api-address https://kubemq.example.com:8080 \
--token kmq_<keyid>_<secret> --tls
kmq context use prod
kmq context list # (alias: ls) — current-context marked
kmq context current
kmq context edit prod --token kmq_<newkey>_<newsecret>
kmq context delete staging # (aliases: rm, remove)Configuration is resolved by precedence, highest to lowest:
| Precedence | Source |
|---|---|
| 1 (highest) | Persistent flags (--context, --api-address) |
| 2 | Environment variables |
| 3 | Active-context file |
| 4 (lowest) | Built-in defaults (http://127.0.0.1:8080) |
| Env var | Purpose |
|---|---|
KMQ_TOKEN | Service-account Bearer key (kmq_<keyid>_<secret>) — preferred in CI |
KMQ_CONTEXT | Active context name (overrides the pointer file) |
KMQ_API_ADDRESS | Management API URL |
Authentication & roles
Authentication is opt-in on the server — see Security
for the account model and roles. Check whether it is on with kmq doctor -o json | jq .auth
(on/off). When auth is on, supply a service-account key via KMQ_TOKEN or the active
context. Service-account roles gate what the CLI can do:
| Role | Grants |
|---|---|
read_only | list/inspect, metrics, status, overview, schema, doctor, billing |
read_write | the above + send/receive/stream/subscribe/purge, channel create/delete |
admin | the above + audit, account management |
Auth-exempt commands
A handful of commands and routes succeed with no token, even when server auth is
on: kmq doctor, kmq metrics scrape, kmq billing (routes /ready, /health,
/metrics, /billing, /api/v1/auth/status). Don't read the role table above as
universal gating — these are the exceptions.
config set/revert and account management require the admin role. Service accounts
never carry admin, so those operations are deliberate non-goals of the CLI.
Global flags & output discipline
Persistent flags are inherited by every subcommand:
| Flag | Default | Purpose |
|---|---|---|
-o, --output | json | Output format: json | ndjson | yaml | table |
--context | — | Use a specific context (overrides current-context) |
--api-address | — | Target :8080 endpoint (overrides context) |
--no-color | false | Disable color in table output |
--verbose | false | Request timing to stderr (token redacted) |
--yes | false | Confirm destructive operations without prompting |
--dry-run | false | Render the action without executing |
--fields | — | Project output to these camelCase wire fields |
--detail | summary | summary | full verbosity, for commands that support it |
Output discipline:
- Data → stdout, warnings/errors/diagnostics → stderr — safe to pipe.
- One-shot commands default to compact
json; streaming commands (queue stream,*subscribe,*replay,conn watch,command/query receive) default tondjson(one record per line, flushed per record). metrics scrapeemits raw Prometheus text;cheatandskills getemit raw markdown — for those,-ois ignored.
kmq queue receive orders --count 10 -o ndjson | jq .body # stream, per-line
kmq estore replay telemetry --from-first --count 100 -o json # buffer then array
kmq status --fields is_healthy,channels,clientsExit codes
kmq returns typed exit codes so scripts and agents can branch deterministically. On
error it also writes a JSON envelope to stderr: {"error":{"code":"...","message":"...","retryable":bool}}.
| Code | Name | Meaning | Retry? |
|---|---|---|---|
| 0 | OK | Success | — |
| 1 | Generic | Unclassified error | No |
| 2 | Usage | Bad flags / usage | No |
| 3 | NotFound | Resource not found | No |
| 4 | Auth | Auth required / failed / forbidden | No |
| 5 | Conn | Server unreachable | Yes (server down?) |
| 6 | Timeout | Request timed out | Yes |
| 7 | Partial | Partial success | Case-by-case |
| 8 | Retryable | Server initializing / too many attempts | Yes — kmq auto-retries |
Server wire codes map onto this table as follows: auth_required, auth_failed,
forbidden, must_change, and tls_required all map to exit code 4;
auth_initializing and too_many_attempts map to exit code 8 and are
auto-retried; seed_read_only, duplicate, and service_admin_forbidden map to exit
code 2; any empty or unknown wire code maps to exit code 1.
Command reference
Every send command reads its body from (in priority) a positional argument →
--body-base64 → -f/--file → stdin, and accepts --message-id/--client-id/
--metadata/-M/--tag k:v (repeatable). Every stream/subscribe/replay/receive
command accepts the bounding flags --count N, --duration 5m, --idle 30s —
whichever fires first stops it; Ctrl-C also exits cleanly with code 0.
Messaging
| Pattern | Send | Receive / Subscribe | Notes |
|---|---|---|---|
| Queue | kmq queue send <ch> <body> | kmq queue receive <ch> [--count N] | persistent, at-least-once |
| Queue (peek) | — | kmq queue peek <ch> [--count N] | non-consuming |
| Queue (interactive) | — | kmq queue stream <ch> [--visibility 60] [--wait 5] [--auto-ack] | WS poll/ack/reject session |
| Queue (drain) | — | kmq queue purge <ch> --yes | destructive |
| Events | kmq events send <ch> <body> | kmq events subscribe <ch> [--group g] | fire-and-forget pub/sub |
| Events Store | kmq estore send <ch> <body> | kmq estore subscribe <ch> | persistent + replayable |
| Events Store (replay) | — | kmq estore replay <ch> <offset-mode> | historical replay — one offset mode: --new-only (default), --from-first, --from-last, --from-sequence N, --from-time <RFC3339>, --since-seconds N, plus --group |
| Command (RPC) | kmq command send <ch> <body> --timeout 30 | kmq command receive <ch> [--respond-body '{}' | --command 'sh'] | request/ack |
| Query (RPC) | kmq query send <ch> <body> --timeout 30 | kmq query receive <ch> [--respond-body '{}' | --command 'sh'] | request/data |
Queue send extras: --max-receive-count, --dead-letter <ch>,
--expiration-seconds, --delay-seconds.
RPC responders: receive with --respond-body '<json>' echoes a static reply;
with --command '<shell>' the inbound body is piped to the command's stdin and its
stdout becomes the reply; with neither, requests are printed for manual handling.
--respond-body and --command are mutually exclusive.
Channels
kmq channel create <name> --type queues|events|events_store|commands|queries
kmq channel delete <name> --type queues --yes
kmq channel list [--type <t>]
kmq channel inspect <type> <name> # full detail: clients, rates, totals
# per-family shortcuts also exist: kmq queue list / kmq queue inspect <name>Cluster
kmq cluster info [--node] # (alias: snapshot) cluster-merged, or --node for local
kmq cluster health # /ready — leadership role, ready/healthy
kmq cluster nodes # topology: node, type, unavailable nodesObservability
kmq status # composite digest: /ready + snapshot, one-line health
kmq overview [--detail full] # per-pattern rollups (queues / pubsub / request-reply / totals)
kmq metrics scrape # raw Prometheus /metrics (auth-exempt)
kmq metrics history [--metric message_rate|volume_rate|error_rate|messages|bytes]
kmq conn list # active connections (first SSE snapshot)
kmq conn inspect <id>
kmq conn watch # live SSE stream of connection events
kmq audit query [--from ..] [--to ..] [--event-type queue.send] [--limit N] ...
kmq audit stats [--group-by event_type|client_id|category|channel|transport]
kmq connector list # aws / gcp / amqp / amqp10 / stomp / mqtt / ce
kmq connector inspect <name> [--operation <service/op>]
kmq agent list [--limit N] [--offset N] # A2A agents
kmq agent inspect <id>
kmq mcp list # server's registered MCP tools
kmq mcp inspect <tool>Kafka
kmq kafka probe --bootstrap host:port[,host:port] # dial a source cluster, read-only
kmq kafka probe -b host:port --dial-timeout 30s # override the 15s default
kmq kafka probe -b host:port \
--aws-access-key <key> --aws-secret-key <secret> --aws-session-token <token> # MSK IAMkmq kafka probe dials a source Apache Kafka / MSK / Confluent cluster over the
Kafka wire protocol and reports back the brokers plus their ApiVersions. It is
read-only — it never produces, commits, or auto-creates topics — so it's safe to
point at a production cluster. Flags: -b/--bootstrap host:port[,host:port...],
--dial-timeout (default 15s), and AWS MSK-IAM auth via
--aws-access-key/--aws-secret-key/--aws-session-token. Run it as a first
connectivity check ahead of the Migration family below, or see
Migrate from Kafka for the full
workflow.
Migration
| Command | Flags | Notes |
|---|---|---|
kmq assess kafka | --bootstrap, --tls, --sasl-mechanism | Read-only fit assessment of an external Kafka cluster → per-topic READY/CAVEAT/UNKNOWN/BLOCKED + a T1–T4 verdict. Never writes to the source. |
kmq migrate assess|replicate|translate|cutover | --state, --dry-run, --force | Beta four-phase migration (assess → replicate → translate → cutover) from a Kafka cluster to KubeMQ. |
For the full narrative (per-source auth, MirrorMaker 2 hybrid, rollback, staged dry-run) see Migrate from Kafka.
Meta & discovery
kmq version # binary version
kmq whoami # identity + role (auth on), or {"authenticated":false,"auth":"disabled"} (auth off)
kmq doctor # connectivity + auth check (no auth required)
kmq config get [--fields ..] # server config (read-only, server-redacted)
kmq billing # usage/license (auth-exempt)
kmq schema -o json # full command tree + roles + exit codes (offline)
kmq cheat [topic] # embedded recipes (offline)
kmq docs [topic] [--open] # signpost to the online docs + LLM corpus
kmq skills ... # serve/install the agent skill (see next section)kmq cheat topics (embedded, offline): queue, events, estore, rpc, drain,
subscribe, health, auth, context, output.
kmq schema -o json is the machine-readable contract — the full command tree (path,
description, required role, flags), the exit-code table, the server wire error-code
catalogue, and the CLI/server versions — with no network and no auth. It is the
recommended way for an agent to introspect the CLI.
Agent-skill distribution
Any coding agent can be taught to drive kmq with one command, and the instructions
always match the installed binary version — the skill content is served straight from
the binary, so it can never go stale between releases.
kmq skills # list skills (alias: kmq skills list) → 'core'
kmq skills get core # print the core skill (raw markdown)
kmq skills get core --full # + the full command reference
kmq skills get --all # every skill
kmq skills path [name] # skills source dir, or '(embedded)'
kmq skills install [--global] [--force] # install the stub locally (zero-Node)| Install path | Command | Reach |
|---|---|---|
| Universal installer | npx skills add kubemq-io/kmq | 70+ agents (Claude Code, Cursor, Codex, Gemini CLI, Windsurf, …) |
| Claude Code plugin | claude plugin marketplace add kubemq-io/kmq | Claude Code |
| Zero-Node fallback | kmq skills install | Local Claude Code install; --global installs it for the current user |
Server communication
kmq speaks to the management API over HTTP. One-shot actions dispatch as
POST /api/request with {type, data} (or dedicated REST routes); the server replies
HTTP 200 with an envelope:
{ "error": false, "error_string": "", "code": "", "data": {} }error: false decodes data into the requested output; error: true maps the code
field to an exit code via the wire-code table above. A handful of routes are auth-exempt
(no Bearer needed) — the same ones called out in the Auth-exempt commands note above.
Retryable server states (auth_initializing, too_many_attempts) are auto-retried
with exponential backoff, cancellable by SIGINT/SIGTERM. Streaming uses SSE/WebSocket
subscription endpoints and stops on the first of --count/--duration/--idle or a
signal. SIGINT/SIGTERM cancel the root context — streaming/waiting commands close
gracefully and exit 0 on clean cancellation.
Related
Web Dashboard
Same management API, different surface — a visual view over cluster health, channels, and clients.
Management API
The HTTP and WebSocket management API on port 8080 behind every kmq command.
Security
Control-plane authentication, roles, and the account model kmq's service-account tokens use.
KubeMQ Aiway
The A2A and MCP agents platform that kmq agent/mcp commands observe, and the agent skill teaches coding agents to drive.
Was this page helpful?