Kubernetes-native YAML processor, linter, and query tool built with AffineScript.
Formerly kcq; renamed to kyq on 2026-10-14 (owner ruling D333, hyperpolymath/standards#1234). Old
metadatastician/kcqlinks redirect here.
kyq — the yq that understands Kubernetes
kyq is a Kubernetes YAML Query tool — a specialized YAML processor designed for the Kubernetes ecosystem. Built on AffineScript, it provides:
- Kubernetes-aware parsing — Understands K8s schemas, resource types, and conventions
- Resource safety — AffineScript's type system prevents resource leaks and double-frees
- Small footprint — Compiles to WebAssembly for minimal binary size (~1-5MB)
- Fast execution — Optimized for K8s manifests and workflows
- Extensible linting — Pluggable rule system for K8s best practices
While yq is excellent for generic YAML/JSON processing, kyq is optimized for Kubernetes:
| Feature | yq | kyq |
|---|---|---|
| K8s schema validation | ❌ | ✅ |
| Deprecated API warnings | ❌ | ✅ |
| Selector validation | ❌ | ✅ |
| Image tag warnings | ❌ | ✅ |
| Resource naming rules | ❌ | ✅ |
| Binary size | ~30-50MB | ~1-5MB |
| Startup time | ~50ms | ~10-20ms |
| Memory usage | Moderate | Smaller |
| Format support | YAML, JSON, XML, CSV, TOML, HCL | KYAML (K8s YAML), JSON |
For K8s: use kyq. For general YAML: use yq. Both can coexist.
# Prerequisites
git clone https://github.com/hyperpolymath/affinescript
# Follow AffineScript setup instructions
# Build kyq
cd meta-repos/kyq
make buildPre-built WebAssembly and native binaries will be available in Releases.
# Lint a Kubernetes manifest for common issues
kyq lint deployment.yaml
# Pretty-print a YAML file
kyq fmt deployment.yaml
# Query a value
kyq get deployment.yaml '.spec.replicas'
# Set a value
kyq set deployment.yaml '.spec.replicas' 5 -i
# Validate against K8s schemas
kyq validate deployment.yaml
# Convert YAML to JSON
kyq to-json deployment.yaml# Create a deployment with issues
cat > deployment.yaml <<EOF
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: my-app
spec:
replicas: "3"
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: apache
spec:
containers:
- name: nginx
image: nginx:latest
EOF
# Lint for issues
$ kyq lint deployment.yaml
✗ deployment.yaml:1:1 — deprecated API version: use apps/v1 instead of apps/v1beta2
✗ deployment.yaml:5:16 — type error: spec.replicas must be integer, got string
✗ deployment.yaml:14:10 — image uses :latest tag (nginx:latest)
✗ deployment.yaml:8:5 — selector mismatch: spec.selector.matchLabels does not match spec.template.metadata.labels
# Fix issues with kyq
kyq set deployment.yaml '.apiVersion' 'apps/v1' -i
kyq set deployment.yaml '.spec.replicas' 3 -i
kyq set deployment.yaml '.spec.template.spec.containers[0].image' 'nginx:1.25' -i
# Verify
$ kyq lint deployment.yaml
✓ deployment.yaml — all checks passedLint Kubernetes manifests for common issues.
Rules:
required-fields— All K8s-required fields are presenttype-check— Fields have correct typesdeprecated-api— Warn on deprecated API versionslatest-tag— Warn on:latestimage tagsselector-mismatch— Check selector matches pod template labelsresource-names— Enforce DNS-1123 naming conventionslabel-keys— Validate label key format
Options:
-r, --rule RULE Enable/disable specific rules (e.g., --rule=-latest-tag)
--color Colored output
--no-color Disable colors
--quiet Only show errors
--format FORMAT Output format: text, json, sarif
--check Exit with error code if issues found
Pretty-print YAML files.
Options:
-i, --in-place Modify files in place
-o, --output FILE Write to file
--indent INT Indentation (default: 2)
--width INT Line width (default: 80)
Extract a value from a YAML file.
Examples:
# Get replicas
kyq get deployment.yaml '.spec.replicas'
# Get all container images
kyq get deployment.yaml '.spec.template.spec.containers[].image'
# Get from multiple files
kyq get '*.yaml' '.metadata.name'Set a value at a path.
Examples:
# Set replicas
kyq set deployment.yaml '.spec.replicas' 5 -i
# Set image
kyq set deployment.yaml '.spec.template.spec.containers[0].image' 'nginx:1.25' -i
# Add namespace
kyq set deployment.yaml '.metadata.namespace' 'production' -iDelete a field at a path.
Examples:
# Remove a label
kyq del deployment.yaml '.metadata.labels.old-label' -i
# Remove a container
kyq del deployment.yaml '.spec.template.spec.containers[1]' -iValidate against Kubernetes OpenAPI schemas.
Options:
--schema PATH Custom schema file
--strict Strict validation (fail on warnings)
Split multi-document YAML into separate files.
Examples:
kyq split multi.yaml -o manifests/
# Creates: manifests/00-deployment.yaml, manifests/01-service.yaml, etc.Merge multiple YAML files into one.
Show differences between two resources.
Convert YAML to JSON.
Convert JSON to YAML.
Replace ${VAR} with environment variables.
Examples:
# In YAML: image: ${IMAGE}:${TAG}
IMAGE=nginx TAG=1.25 kyq envsubst deployment.yaml
# Output: image: nginx:1.25Inject namespace, labels, or annotations.
Examples:
# Inject namespace
kyq inject deployment.yaml --namespace production -i
# Inject labels
kyq inject deployment.yaml --label app=myapp --label env=prod -i
# Inject annotations
kyq inject deployment.yaml --annotation 'k8s.io/description=My App' -ikyq supports a jq-like query language optimized for Kubernetes.
| Query | Description |
|---|---|
.spec.replicas |
Get replicas |
.spec.containers[0].image |
Get first container image |
.spec.containers[].image |
Get all container images |
.metadata.labels."app.kubernetes.io/name" |
Get label with special chars |
.spec.ports[?(.port == 80)] |
Filter ports (future) |
| Filter | Description |
|---|---|
select(.kind == "Deployment") |
Filter documents |
map(.metadata.name) |
Transform array |
.items[] |
Iterate over array |
| Function | Description |
|---|---|
length |
Array length |
keys |
Object keys |
has("field") |
Check if field exists |
env("VAR") |
Get environment variable |
┌─────────────────────────────────────────────────────────────┐
│ kyq CLI │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Parser │ │ Linter │ │ Query │ │
│ │ (AffineScript)│───▶│ (Rules) │───▶│ Engine │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ KYAML AST │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────┐
│ Output Formatter │
│ (YAML, JSON, Text, SARIF) │
└─────────────────────────────┘
-
Parser (
src/Kyaml/Parser.affine)- Lexer for KYAML (K8s-specific YAML subset)
- Parser to build Abstract Syntax Tree
- Multi-document support
-
Linter (
src/Kyaml/Lint/)- Pluggable rule system
- K8s-specific validation
- Configurable severity levels
-
Query Engine (
src/Kyaml/Query.affine)- Path-based queries
- jq-like filter language
- In-place mutations
-
K8s Schema (
src/Kyaml/Schema/)- Embedded K8s API schemas
- Type definitions for common resources
- Validation against official schemas
| Kind | API Version | Support |
|---|---|---|
| Deployment | apps/v1 | ✅ Full |
| StatefulSet | apps/v1 | ✅ Full |
| DaemonSet | apps/v1 | ✅ Full |
| Service | v1 | ✅ Full |
| ConfigMap | v1 | ✅ Full |
| Secret | v1 | ✅ Full |
| Ingress | networking.k8s.io/v1 | ✅ Full |
| PersistentVolume | v1 | ✅ Full |
| PersistentVolumeClaim | v1 | ✅ Full |
| Namespace | v1 | ✅ Full |
| Job | batch/v1 | ✅ Full |
| CronJob | batch/v1 | ✅ Full |
| HorizontalPodAutoscaler | autoscaling/v2 | ✅ Full |
| PodDisruptionBudget | policy/v1 | ✅ Full |
| NetworkPolicy | networking.k8s.io/v1 | ✅ Full |
| CustomResourceDefinition | apiextensions.k8s.io/v1 | ✅ Full |
All standard K8s resource types are supported.
| Rule ID | Description | Default |
|---|---|---|
required-fields |
Missing required K8s fields | ✅ |
type-mismatch |
Field has wrong type | ✅ |
invalid-name |
Invalid resource name (DNS-1123) | ✅ |
| Rule ID | Description | Default |
|---|---|---|
deprecated-api |
Using deprecated API version | ✅ |
latest-tag |
Image uses :latest tag |
✅ |
selector-mismatch |
Selector doesn't match pod template | ✅ |
missing-labels |
Missing recommended labels | ❌ |
root-user |
Container runs as root | ✅ |
empty-selector |
Deployment has empty selector | ✅ |
| Rule ID | Description | Default |
|---|---|---|
non-standard-label |
Label key doesn't follow conventions | ❌ |
missing-description |
Missing description annotation | ❌ |
| Metric | yq (Go) | kyq (AffineScript/WASM) | Winner |
|---|---|---|---|
| Binary size | ~30-50MB | ~1-5MB | ✅ kyq |
| Memory usage | ~50-100MB | ~20-40MB | ✅ kyq |
| Startup time | ~50ms | ~10-20ms | ✅ kyq |
| Parse speed | ~50MB/s | ~30-40MB/s (early) |
| Feature | yq | kyq | Winner |
|---|---|---|---|
| Generic YAML | ✅ | ✅ | Tie |
| JSON | ✅ | ✅ | Tie |
| XML | ✅ | ❌ | yq |
| CSV | ✅ | ❌ | yq |
| TOML | ✅ | ❌ | yq |
| HCL | ✅ | ❌ | yq |
| Properties | ✅ | ❌ | yq |
| K8s schema validation | ❌ | ✅ | ✅ kyq |
| Deprecated API warnings | ❌ | ✅ | ✅ kyq |
| Selector validation | ❌ | ✅ | ✅ kyq |
| Image tag warnings | ❌ | ✅ | ✅ kyq |
| Resource naming rules | ❌ | ✅ | ✅ kyq |
| Feature | yq | kyq |
|---|---|---|
| Understands K8s schemas | ❌ | ✅ |
| Knows resource kinds | ❌ | ✅ |
| Validates field types | ❌ | ✅ |
| Warns on deprecated APIs | ❌ | ✅ |
| Checks selector consistency | ❌ | ✅ |
| Detects common mistakes | ❌ | ✅ |
- Repository creation
- KYAML lexer (basic)
- KYAML parser (basic)
- AST definition
- Required fields linter
- Type checking linter
-
lintcommand with 5-10 rules -
fmtcommand (pretty-print) -
getcommand (basic path queries) -
validateagainst embedded schemas
-
setcommand (update values) -
delcommand (delete fields) -
injectcommand (namespace/labels) -
envsubstcommand
- Full query language (jq-like)
- Multi-document operations
-
splitandmergecommands -
diffcommand
- GitHub Action
- Pre-commit hooks
- VS Code extension
- Language server (LSP)
- Optimize parser performance
- Reduce binary size further
- Add more lint rules
- Improve error messages
See CONTRIBUTING.md for development setup and contribution guidelines.
- Code: Mozilla Public License 2.0, see LICENSE.
- Documentation: CC-BY-SA-4.0, see LICENSES/CC-BY-SA-4.0.txt.
Each file's SPDX-License-Identifier header is authoritative.
- yq — The inspiration for generic YAML processing
- AffineScript — The language kyq is built with
- Kustomize — K8s configuration management
- Helm — K8s package manager
- kubectl — K8s CLI
- Inspired by yq and its ecosystem
- Built with AffineScript
- Kubernetes API schemas from kubernetes/kubernetes