queenctl is a single static Go binary built on the Go client. It exposes the
broker’s data plane (push, pop, ack, transaction, lease) and its management plane (queues,
partitions, consumer groups, DLQ, traces, maintenance, metrics, analytics). Version 1.0.0, aligned
with the broker.
Every command below is registered in clients/client-cli/cmd. Nothing else is: if a name is not
in this page, the binary does not have it.
Install
make -C clients/client-cli buildPuts the binary in clients/client-cli/bin/queenctl. make install runs go install into $GOBIN
(or $HOME/go/bin). Both pass -ldflags that stamp the version, commit and build date; a build
without them reports dev, none and unknown.
Global flags
Bound to the root command, so they work on every subcommand.
| Flag | Default | Effect |
|---|---|---|
--context <name> |
none | Named context from the config file. Overrides current-context. |
--server <url> |
none | Broker URL. Overrides the context; same as $QUEEN_SERVER. |
--token <token> |
none | Bearer token. Overrides the context; same as $QUEEN_TOKEN. |
-o, --output <fmt> |
table on a TTY, json on a pipe |
See the formats table. |
--no-color |
false |
Disable ANSI colour. |
--color |
false |
Force ANSI colour. |
--insecure |
false |
Skip TLS verification. |
-q, --quiet |
false |
Suppress non-essential output. |
--no-headers |
false |
Omit table headers. |
--config <path> |
~/.queen/config.yaml |
Config file path. |
Output formats
-o value |
Notes |
|---|---|
table |
Column view. Default when stdout is a TTY. |
wide |
Table with the extra columns a command declares. |
json |
Pretty JSON. Default when stdout is not a TTY, so queenctl tail | queenctl push composes without extra plumbing. |
ndjson, jsonl |
One JSON object per line. |
yaml |
|
raw |
The body as returned. |
jsonpath=<expr>, json-path=<expr> |
Extract one value, e.g. -o jsonpath=.messages[0].transactionId. |
pop and tail always emit NDJSON regardless of -o: they are designed to be piped.
Exit codes
| Code | Meaning |
|---|---|
0 |
Success. |
1 |
User error: bad flag, bad input, missing argument. Also the code for a route the proxy refuses to a tenant, since no retry helps. |
2 |
Server error, or the server was unreachable. The default for an unclassified error. |
3 |
Authentication or authorization failure. |
4 |
Successful no-op: an empty pop, no DLQ rows, nothing applied. |
Code 4 is the only one whose message is not printed to stderr. It is not a failure, so scripts
can treat it as “nothing to do”.
Configuration
Resolution order
- Context name:
--context, then$QUEEN_CONTEXT, thencurrent-contextfrom the file. - Server: the context’s
server, then$QUEEN_SERVER, then--server. - Token: the context’s
token-refresolved, then$QUEEN_TOKEN, then--token. - Insecure: the context’s
insecure, then--insecure, but only when the flag was actually passed, so an absent flag never overrides the file withfalse.
With no server resolved, every command that talks to a broker fails with
no server configured: set --server, QUEEN_SERVER, or run 'queenctl config set-context'.
Environment variables
| Variable | Effect |
|---|---|
QUEEN_CONFIG |
Config file path. Beaten by --config. |
QUEEN_CONTEXT |
Context name. |
QUEEN_SERVER |
Broker URL. |
QUEEN_TOKEN |
Bearer token, and the value read by token-ref: env. |
Config file
~/.queen/config.yaml, kubectl-shaped. A missing file is not an error: first-run users get the
environment-only experience.
current-context: prod
contexts:
- name: prod
server: https://queen.internal:6632
token-ref: keychain://prod
- name: local
server: http://localhost:6632
insecure: truetoken-ref is one of:
| Form | Meaning |
|---|---|
absent or "" |
No token. |
env |
Read $QUEEN_TOKEN at runtime. |
keychain://<id> |
Read from the OS keychain under service queenctl. |
file:///abs/path |
Read from a file. |
literal:<token> |
The token itself, in the config file. For CI; not recommended. |
Writes are atomic (a .tmp file renamed over the target), with the file at 0600 and the parent
directory at 0700.
Authentication
queenctl login
| Flag | Default | Effect |
|---|---|---|
--method <m> |
inferred | token, password, google or github. |
-u, --user <email> |
none | Email for the password flow. |
--password <pw> |
none | Password. Prefer the interactive prompt. |
--token <token> |
none | JWT or qk_ API key to store, skipping the prompt. |
--context <name> |
active context | Which context to bind the credential to. |
--no-browser |
false |
Do not auto-open the browser for the OAuth flows. |
With no --method: --token implies token, --user implies password, otherwise token.
The context must already exist: run config set-context first. An unknown --method exits 1.
The captured credential goes into the OS keychain and the config file keeps only
keychain://<context>. If the keychain is unavailable (a CI container, a headless box), the CLI
prints a warning to stderr and falls back to literal:<token> in the config file.
| Method | What happens |
|---|---|
token |
Prompts for a JWT or a qk_ cluster API key (hidden input on a TTY, a stdin line otherwise) and stores it. |
password |
Form-POSTs /auth/login on the proxy and reads the session JWT out of the cookie jar. Falls back to the legacy POST /api/login when the response cannot have come from that endpoint. Bad credentials exit 3. |
google, github |
Probes GET /auth/<provider> for availability, opens the browser at /auth/<provider>?next=/auth/session-token, and asks you to paste the token the browser lands on. |
queenctl logout deletes the keychain entry, clears token-ref on the context and saves the file.
It takes --context <name>.
Data plane
queenctl push <queue>
Reads NDJSON from stdin by default, one JSON object per line, and pushes in batches.
| Flag | Default | Effect |
|---|---|---|
--partition <name> |
none | Static partition for every message. |
--partition-key <path> |
none | JSON path inside each payload to use as the partition, e.g. user_id, order.id. One ordered lane per distinct key. |
--batch <n> |
100 |
Messages per HTTP request. |
--data <json> |
none | A single inline payload; skips stdin. |
-f, --file <path> |
none | Read NDJSON from a file instead of stdin. |
--trace-id <uuid> |
none | Attach this UUID as the trace id. |
--transaction-id <id> |
none | Explicit transactionId for the first item. |
--wrapped |
false |
Input lines are full SDK items: {transactionId?, traceId?, partition?, data}. |
--dry-run |
false |
Parse and group the input, send nothing. |
cat events.ndjson | queenctl push events --batch 500 --partition-key user_id--wrapped is what makes replication between brokers possible: it lets each line carry its own
partition and transaction id, so dedup stays meaningful on the receiving side.
queenctl pop [queue]
One-shot pop, printed as NDJSON. The queue argument is optional: omit it and use
--namespace / --task.
| Flag | Default | Effect |
|---|---|---|
--cg <name> |
none | Consumer group. |
--partition <name> |
none | A specific partition. |
-n, --limit <n> |
1 |
Maximum messages printed. |
--batch <n> |
--limit |
Batch size sent to the broker. |
--max-partitions <n> |
1 |
Claim up to N partitions in one call. |
--auto-ack |
false |
Ack server-side, inside the pop transaction. |
--wait |
true |
Long-poll until messages arrive or the timeout fires. |
--timeout <dur> |
10s |
Long-poll timeout. |
--namespace <name> |
none | Filter the queue-less pop by namespace. |
--task <name> |
none | Filter the queue-less pop by task. |
--from-mode <mode> |
none | Subscription mode: all, new, new-only. |
--since <t> |
none | Subscription start: now, RFC3339, 5m ago. |
Each emitted line carries queue, partition, transactionId, partitionId, createdAt,
retryCount and data, plus leaseId and producerSub when present. An empty pop exits 4.
queenctl tail <queue>
Live-tail, always NDJSON on stdout regardless of -o.
| Flag | Default | Effect |
|---|---|---|
--cg <name> |
queenctl-tail |
Consumer group. Without it an ephemeral group name is used. |
--partition <name> |
any | Single partition to tail. |
-f, --follow |
false |
Keep long-polling after the queue drains. |
-n, --limit <n> |
0 (no limit) |
Stop after N messages. |
--batch <n> |
0 |
Messages per long-poll round-trip. |
--max-partitions <n> |
1 |
Claim up to N partitions per pop. |
--auto-ack |
false |
Ack server-side as messages are emitted. |
--from <mode> |
none | Subscription mode: all, new, new-only. |
--since <t> |
none | Subscription start. |
--idle-millis <n> |
0 |
Stop after N ms with no messages. |
--concurrency <n> |
0 |
Parallel handlers. |
--timeout <dur> |
0 → 30 s, or --idle-millis when smaller |
Per-pop long-poll timeout. |
queenctl tail src --auto-ack | queenctl push dst --batch 100queenctl ack [transactionId]
| Flag | Default | Effect |
|---|---|---|
--partition-id <uuid> |
none | Internal partition UUID, as printed by pop / tail. |
--lease-id <uuid> |
none | Lease UUID returned at pop time. |
--cg <name> |
none | Consumer group. |
--error <msg> |
none | Attach an error message; use with --failed. |
--failed |
false |
Mark as failed instead of completed. |
--batch <file> |
none | Ack many messages from an NDJSON file; - for stdin. |
Each line of a --batch file must be a JSON object with at least transactionId, partitionId
and leaseId, exactly the shape pop and tail emit.
queenctl tail q --cg c -n 100 | queenctl ack --batch -queenctl tx -f <bundle.json>
Posts a bundle to /api/v1/transaction: pushes and acks in one PostgreSQL transaction.
| Flag | Default |
|---|---|
-f, --file <path> |
required; - for stdin |
--dry-run |
false (parse and count, do not commit) |
The file shape maps directly to the route:
{
"operations": [
{"type": "ack", "transactionId": "…", "partitionId": "…", "status": "completed"},
{"type": "push", "items": [{"queue": "orders", "payload": {"id": 1}}]}
],
"requiredLeases": ["lease-uuid"]
}Only ack and push operation types are accepted; anything else exits 1. Push items are grouped
by queue and partition before being handed to the builder, preserving first-seen order.
queenctl lease extend <leaseId>
Renews one lease, POST /api/v1/lease/:leaseId/extend. No flags of its own.
Queues and partitions
queenctl queue (aliases queues, q)
| Subcommand | Aliases | Arguments |
|---|---|---|
list |
ls |
none |
describe <queue> |
get, show |
exactly one |
configure <queue> |
none | exactly one |
delete <queue> |
rm |
exactly one |
stats |
none | none |
queue list flags: --namespace, --task, --limit (0), --offset (0).
queue stats flags: --namespace, --task.
queue delete requires --yes.
queue configure flags:
| Flag | Default | Wire key |
|---|---|---|
--namespace <name> |
none | namespace |
--task <name> |
none | task |
--lease-time <s> |
0 |
leaseTime |
--retry-limit <n> |
0 |
retryLimit |
--delayed-processing <s> |
0 |
delayedProcessing |
--window-buffer <s> |
0 |
windowBuffer |
--retention <s> |
0 |
retentionSeconds |
--completed-retention <s> |
0 |
completedRetentionSeconds |
--encrypt |
false |
encryptionEnabled |
--dlq |
true |
deadLetterQueue and dlqAfterMaxRetries |
A positive --retention or --completed-retention sets retentionEnabled: true automatically,
because the broker’s retention service only sweeps queues with that flag set.
With -o json or -o yaml, configure renders the full response including the echoed options
block, which is what to assert against in tests. Without -o, it prints configured "<queue>".
queenctl partition (aliases partitions, p)
| Subcommand | Aliases | Arguments | Flags |
|---|---|---|---|
list <queue> |
ls |
exactly one | none |
describe <queue> <partition> |
get, show |
exactly two | none |
seek <queue> <partition> |
none | exactly two | --cg (required), --to (default end) |
partition seek only supports seek-to-end: the stored procedure behind
POST /api/v1/consumer-groups/:cg/queues/:q/partitions/:p/seek takes no timestamp. --to accepts
end, now, latest or an empty value; anything else exits 1. For a timestamp, use
queenctl cg seek, which is queue-wide.
queenctl namespace (aliases namespaces, ns)
namespace list (alias ls) lists namespaces with their queues. No flags.
queenctl task (alias tasks)
task list (alias ls) lists tasks with their queues. No flags.
Consumer groups
queenctl cg (aliases consumer-group, consumer-groups)
| Subcommand | Aliases | Arguments | Flags |
|---|---|---|---|
list |
ls |
none | none |
describe <name> |
get, show |
exactly one | none |
lag |
none | none | --min-seconds (0) |
seek <cg> <queue> |
none | exactly two | --to, --dry-run |
delete <cg> |
rm |
exactly one | --queue, --metadata, --yes |
refresh-stats |
none | none | none |
cg delete without --queue deletes the group everywhere; with it, only for that queue.
--metadata also removes the subscription metadata rows. --yes is required.
queenctl lag
--min-seconds <n> (default 0). At 0 it lists every group from /api/v1/consumer-groups;
above 0 it queries /api/v1/consumer-groups/lagging. queenctl cg lag is the same command.
queenctl replay [queue]
Moves a consumer group’s cursor so the next pop returns messages from --to onward.
| Flag | Default | Effect |
|---|---|---|
--cg <name> |
required | Consumer group to seek. |
--to <t> |
required | Target time. |
--dry-run |
false |
Print the action, send nothing. |
--to accepts:
| Form | Result |
|---|---|
now, end, latest |
{toEnd: true}. Jumps past the latest message. |
beginning, earliest, start |
Timestamp 1970-01-01T00:00:00Z. The route takes toEnd or a timestamp, so “beginning” is expressed as the epoch. |
5m ago, 2h ago, 1d ago, 1w ago |
Relative to now. Bare forms like 30s are also read as “ago”. |
RFC3339, YYYY-MM-DD, YYYY-MM-DD HH:MM:SS, unix seconds |
Absolute. Date-only is UTC midnight. |
queenctl cg seek <cg> <queue> is the same operation with the arguments the other way round.
Messages, DLQ and traces
queenctl messages (aliases msg, msgs)
| Subcommand | Aliases | Arguments |
|---|---|---|
list |
ls |
none |
get <partitionId> <transactionId> |
describe, show |
exactly two |
delete <partitionId> <transactionId> |
rm |
exactly two |
traces <partitionId> <transactionId> |
none | exactly two |
messages list flags: --queue, --partition, --status (pending, processing, completed,
failed), --cg, --limit (100), --offset (0).
messages delete requires --yes.
queenctl dlq
| Subcommand | Aliases | Arguments |
|---|---|---|
list |
ls |
none |
describe <partitionId> <transactionId> |
get |
exactly two |
drain |
none | none |
list and drain share the filters: --queue, --cg, --partition, --from, --to,
--limit (0), --offset (0). drain adds --dry-run and --yes, and refuses to run without
one of them.
queenctl traces
| Subcommand | Aliases | Arguments | Flags |
|---|---|---|---|
names |
list, ls |
none | --limit (100), --offset (0) |
by-name <name> |
none | exactly one | --limit (100), --offset (0) |
by-message <partitionId> <transactionId> |
none | exactly two | none |
traces by-message is the same as messages traces.
Status and observability
queenctl status [queue]
No argument prints the cluster view: queues with depth, completed, failed and lag. With a queue name it prints the detailed view.
| Flag | Default | Effect |
|---|---|---|
--namespace <name> |
none | Filter. |
--task <name> |
none | Filter. |
--partitions |
false |
Include per-partition detail. |
queenctl ping
Calls /health. Exits 0 when the broker reports healthy with the database connected, 2
otherwise. Prints status, database, version and measured latency.
| Flag | Default |
|---|---|
--timeout <dur> |
5s |
queenctl version
Prints the CLI’s build metadata, then probes the server for its version, status and database state,
and echoes the active context. --short prints only the CLI version and contacts nothing.
queenctl metrics
Reads /metrics (a JSON snapshot) by default. --prometheus reads /metrics/prometheus and
prints the raw text/plain exposition.
queenctl metrics --prometheus | grep queue_pop_messagesqueenctl analytics (aliases a, an)
Every subcommand takes --from and --to (both empty by default), which accept the same time
forms as replay --to.
| Subcommand | Route |
|---|---|
overview |
GET /api/v1/status/analytics (composite dashboard data) |
queue-lag |
GET /api/v1/analytics/queue-lag |
queue-ops |
GET /api/v1/analytics/queue-ops |
queue-parked |
GET /api/v1/analytics/queue-parked-replicas |
retention |
GET /api/v1/analytics/retention |
system |
GET /api/v1/analytics/system-metrics |
worker |
GET /api/v1/analytics/worker-metrics |
postgres |
GET /api/v1/analytics/postgres-stats |
system, worker and postgres are operator-only through a proxy.
Operations
queenctl apply -f <file>
Applies YAML or JSON manifests. Multiple documents separated by ---; -f - reads stdin.
Operations are idempotent and tolerant of resources that already exist.
| Flag | Default |
|---|---|
-f, --file <path> |
required; - for stdin |
--dry-run |
false (parse and validate only) |
Two kinds, flat, with no apiVersion dance. kind defaults to Queue; a document with no name is
skipped, and an unknown kind exits 1.
kind: Queue
name: orders
namespace: billing
task: ingest
config:
leaseTime: 60
retryLimit: 5
---
kind: ConsumerGroup
name: analyzer
queue: orders
seek-to: beginningQueue accepts name, namespace, task and a config block whose keys are the Go
QueueConfig field names in camelCase. ConsumerGroup accepts name, queue (required) and
seek-to, which takes the same forms as replay --to; a ConsumerGroup with no seek-to has
nothing to apply and is reported as skipped. Applying nothing exits 4.
The zero-value omission described under queue configure applies to the config block too: a key
you set to 0 or false is not sent, and /configure replaces the whole configuration. Spell out
every option you care about with a non-zero value.
queenctl maintenance (alias maint)
| Subcommand | Flags |
|---|---|
get |
none |
on |
--yes (required) |
off |
none |
--pop is a persistent flag on the parent, so it applies to all three: it scopes the operation to
pop-only maintenance (/api/v1/system/maintenance/pop) instead of push maintenance
(/api/v1/system/maintenance).
queenctl bench
An end-to-end smoke benchmark: push --total messages across --partitions partitions in
--batch-sized batches from --producers goroutines, then drain with --consumers goroutines.
| Flag | Default |
|---|---|
--queue <name> |
queenctl-bench |
--total <n> |
10000 |
--batch <n> |
100 |
--partitions <n> |
4 |
--producers <n> |
4 |
--consumers <n> |
4 |
--payload-size <bytes> |
64 |
--skip-pop |
false |
--auto-create |
true |
--auto-delete |
false |
It reports the push wall time, the pop wall time, and per-message residency percentiles.
Utility
queenctl config
| Subcommand | Aliases | Arguments |
|---|---|---|
view |
none | none |
current-context |
current |
none |
get-contexts |
list, ls |
none |
set-context <name> |
none | exactly one |
use-context <name> |
none | exactly one |
delete-context <name> |
rm |
exactly one |
set-context flags:
| Flag | Default | Effect |
|---|---|---|
--server <url> |
none | Broker URL. |
--token <token> |
none | Bearer token, stored in the keychain by default. |
--token-ref <ref> |
none | Explicit reference: env, keychain://<id>, file:///abs, literal:<value>. |
--insecure |
false |
Skip TLS verification. |
--no-keychain |
false |
Store --token literally in the config file. Less secure. |
view prints the resolved configuration as YAML. delete-context also clears current-context
when it pointed at the removed context.
queenctl completion [bash|zsh|fish|powershell]
Writes a completion script to stdout. Exactly one argument, from that list.
queenctl docs
Prints a list of documentation links, with --open to launch the site in the default browser and
--topic <name> to deep-link.