From mirrord
Generates MirrordSplitConfig and MirrordPropertyList Kubernetes CRD YAMLs, mirrord.json split_queues config, and Helm guidance for Kafka queue splitting with mirrord Operator.
How this skill is triggered — by the user, by Claude, or both
Slash command
/mirrord:mirrord-kafkaThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> **Which CRDs?** Kafka splitting is now configured with **`MirrordSplitConfig`** (which queues to split + how the app finds their names) and **`MirrordPropertyList`** (the Kafka client connection). These replace the deprecated `MirrordKafkaTopicsConsumer` + `MirrordKafkaClientConfig`, which still work for backward compatibility. **Generate the new resources for any new setup.** Only produce th...
Which CRDs? Kafka splitting is now configured with
MirrordSplitConfig(which queues to split + how the app finds their names) andMirrordPropertyList(the Kafka client connection). These replace the deprecatedMirrordKafkaTopicsConsumer+MirrordKafkaClientConfig, which still work for backward compatibility. Generate the new resources for any new setup. Only produce the deprecated ones if the user explicitly asks or is maintaining an existing deployment. Requires operator 3.170.0+ and CLI 3.221.0+.
IMPORTANT: Follow these security rules for all operations in this skill.
MirrordPropertyList YAML. Reference a Kubernetes Secret with valueFrom.secretKeyRef per property.kubectl create secret generic ... --from-file=... reading values from files (then delete the files). Do not suggest --from-literal for credential values — it exposes secrets in argv/shell history.^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$ and reject shell metacharacters before interpolating into commands.kubectl get / kubectl config calls are read-only and safe. Never run kubectl apply/create/delete or helm install/upgrade on the user's behalf — present generated YAML and cluster-modifying commands for the user to review and run themselves.Guide DevOps engineers through the full setup of mirrord Operator's Kafka queue splitting:
operator.kafkaSplitting (and the Kafka sidecar for Kafka Streams)feature.split_queues section developers use to filter messages (message_filter on headers, jq_filter on record content)Step 1: Load reference files
references/mirrord-split-config-crd.md — MirrordSplitConfig field spec (current)references/mirrord-property-list-crd.md — MirrordPropertyList field spec, auth patterns (current)references/known-issues.md — active bugs, gotchas, and workaroundsreferences/kafka-topics-consumer-crd.md, references/kafka-client-config-crd.md — deprecated CRDs; read only when helping with an existing legacy setupAlways read the relevant CRD reference for any resource you generate.
Step 2: Inspect the cluster (if kubectl is available)
kubectl config current-context
kubectl cluster-info 2>/dev/null | head -5
# Operator present?
kubectl get ns mirrord --no-headers 2>/dev/null
kubectl get deploy mirrord-operator -n mirrord --no-headers 2>/dev/null
# Kafka splitting enabled? (current CRDs)
kubectl get crd mirrordsplitconfigs.queues.mirrord.metalbear.co --no-headers 2>/dev/null
kubectl get crd mirrordpropertylists.mirrord.metalbear.co --no-headers 2>/dev/null
# Existing configs
kubectl get mirrordsplitconfigs --all-namespaces --no-headers 2>/dev/null
kubectl get mirrordpropertylists --all-namespaces --no-headers 2>/dev/null
# Legacy CRDs (only if migrating an existing setup)
kubectl get crd mirrordkafkatopicsconsumers.queues.mirrord.metalbear.co --no-headers 2>/dev/null
Inspect the target workload to extract container names and env vars:
kubectl get deployment/<name> -n <ns> -o yaml 2>/dev/null # or statefulset / rollout
kubectl get svc --all-namespaces --no-headers 2>/dev/null | grep -i kafka
This auto-discovery reduces the questions you need to ask (bootstrap server from a Kafka service; topic/group-id env vars from the target's pod spec). If kubectl isn't available, ask.
Step 3: Gather remaining context
For MirrordPropertyList:
For MirrordSplitConfig:
MirrordPropertyList name to referenceRemind the user once, early, to enable Kafka splitting:
operator:
kafkaSplitting: true
# For Kafka Streams consumers only:
kafkaSplittingSidecar:
enabled: true
Rules:
group.id — mirrord manages the operator's consumer group.valueFrom.secretKeyRef for any credential (SASL password, SSL PEMs, key password).mirrord.auth.kind: MSK_IAM + mirrord.auth.aws_region (auto-adds OAUTHBEARER + SASL_SSL).mirrord.client_implementation: java.security.protocol to SASL_SSL when the user mentions SASL without specifying transport, and flag it: "defaulted to SASL_SSL — change to SASL_PLAINTEXT if your broker uses plaintext transport."apiVersion: mirrord.metalbear.co/v1
kind: MirrordPropertyList
metadata:
name: kafka-connection
namespace: <target-namespace>
spec:
properties:
- name: bootstrap.servers
value: <broker-address>
- name: security.protocol
value: PLAINTEXT
# credentials via valueFrom.secretKeyRef, MSK IAM keys, or client_implementation as needed
See references/mirrord-property-list-crd.md for MSK IAM, SSL-via-Secret, Streams, and JKS→PEM.
Rules:
spec.targetRef = { apiVersion, kind, name } (Deployment/StatefulSet/Rollout).spec.queues[] needs id, kind: kafka, a clientConfig (the MirrordPropertyList name; or set once via spec.clientConfigs.kafka), and appConfig.topic.appConfig.groupId (standard consumers) or appConfig.appId (Kafka Streams) per queue.spec.restart.timeout and spec.drainTimeout (keeps the split warm so a new session skips the restart).apiVersion: queues.mirrord.metalbear.co/v1
kind: MirrordSplitConfig
metadata:
name: <workload>-split
namespace: <target-namespace>
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: <workload-name>
queues:
- id: <topic-id>
kind: kafka
clientConfig: kafka-connection
appConfig:
topic:
- env: <TOPIC_ENV_VAR>
fallback: <topic-name> # optional
containers: [<container>]
groupId:
- env: <GROUP_ID_ENV_VAR>
containers: [<container>]
appConfig.topic/groupId/appId sources also support envLike (regex over var names), valueSelector (jq, for JSON-valued env vars), and valuePattern (regex to swap an embedded name). See the split-config reference.
Show the developer-facing config referencing the topic IDs. Two filter kinds, and you can combine them:
Filter on Kafka headers (message_filter):
{
"operator": true,
"target": "deployment/<workload>/container/<container>",
"feature": {
"split_queues": {
"<topic-id>": {
"queue_type": "Kafka",
"message_filter": { "<header-name>": "<regex>" }
}
}
}
}
All specified headers must match. An empty message_filter: {} with no jq_filter is match-none (the local app gets zero messages).
Filter on record content (jq_filter) — NEW:
{
"operator": true,
"target": "deployment/<workload>/container/<container>",
"feature": {
"split_queues": {
"<topic-id>": {
"queue_type": "Kafka",
"jq_filter": ".payload | fromjson | .data.merchantId == 2137"
}
}
}
}
jq_filter runs a jq program over a JSON doc the operator builds per record: topic, partition, offset, timestamp, key, payload, headers. key/payload/header values are UTF-8 strings (or base64 when not valid UTF-8). A record matches if the program outputs true; a record whose program errors (e.g. fromjson on non-JSON) is treated as not matching and stays on the deployed app's path.
Notes to convey:
queue_mode is optional: steal (default, only your local app gets a matched message) or mirror (both your app and the deployed app get a copy).message_filter and jq_filter are set, both must match.jq_filter requires operator 3.183.0+, CLI 3.232.0+, and the default librdkafka client — it is not supported with the Java client (Kafka Streams), which fails with a clear error.queue_id per entry.If the user has the mirrord-config skill, point them there for the full mirrord.json.
MirrordPropertyList is in the target's namespace and has bootstrap.servers; does not set group.id.MirrordSplitConfig is in the target's namespace with spec.targetRef (apiVersion, kind, name).id, kind: kafka, a clientConfig (or spec.clientConfigs.kafka), and appConfig.topic.appConfig.groupId or appConfig.appId.kind (targetRef) is one of Deployment, StatefulSet, Rollout.clientConfig names a MirrordPropertyList in the same namespace (or a legacy MirrordKafkaClientConfig of that name in the operator namespace as fallback).target matches the MirrordSplitConfig targetRef.jq_filter is only used with librdkafka (not with mirrord.client_implementation: java).min.insync.replicas / acks workaround.mirrord-tmp-* topics.jq_filter won't work.Present results as:
✅ Validation passed
⚠️ Warning: [description + workaround]
❌ Error: [what's wrong + how to fix]
Full setup: brief overview of the 2 resources → MirrordPropertyList YAML → MirrordSplitConfig YAML → example mirrord.json → validation → warnings.
Single resource: YAML → validation → warnings.
Troubleshooting: read references/known-issues.md, use the Quick Symptom Lookup, ask for the operator version (kubectl get deploy mirrord-operator -n mirrord -o jsonpath='{.spec.template.spec.containers[0].image}'), match symptoms, suggest checking operator logs (kubectl logs -n mirrord deployment/mirrord-operator --tail 100).
"Set up Kafka splitting for my deployment" → ask for bootstrap servers, auth, workload name/namespace, topic + group-id env vars → generate MirrordPropertyList + MirrordSplitConfig + mirrord.json example.
"Filter by message body / a field in the payload" → use jq_filter (this is now supported). Confirm operator 3.183.0+/CLI 3.232.0+ and librdkafka (not Streams).
"We use Kafka Streams" → appConfig.appId + mirrord.client_implementation: java + operator.kafkaSplittingSidecar.enabled: true. Note jq_filter is unavailable with the Java client.
"We use AWS MSK with IAM" → mirrord.auth.kind: MSK_IAM + mirrord.auth.aws_region; annotate the operator SA with the role ARN via sa.roleArn.
"We use JKS for Kafka auth" → JKS→PEM conversion, then ssl.*.pem via a Secret.
"My session times out" → check known-issues (single-replica min.insync.replicas, ephemeral topic cleanup), tune spec.restart.timeout, check operator logs.
"Migrate our existing Kafka splitting config" → map MirrordKafkaTopicsConsumer→MirrordSplitConfig and MirrordKafkaClientConfig→MirrordPropertyList (mapping tables in the reference files). You can migrate the topics consumer first — clientConfig falls back to the legacy client config by name.
MirrordKafkaTopicsConsumer/MirrordKafkaClientConfig for a new setup — use MirrordSplitConfig + MirrordPropertyList.group.id — mirrord manages it.MirrordPropertyList in the operator namespace (that's the legacy model; the new one lives in the target's namespace).appConfig.groupId and appConfig.appId on one queue.jq_filter for Kafka Streams (Java client) sessions — it's librdkafka-only.jq_filter supports it.npx claudepluginhub metalbear-co/skills --plugin mirrordCreates, edits, and verifies skills using a test-driven development approach with pressure scenarios and subagents.