README
ΒΆ
kyt
kyt stands for Kubernetes Yaml Toolkit (or Know Your Things).
A powerful CLI tool for formatting and comparing Kubernetes manifests with intelligent ignore rules.
Overview
kyt is a Go-based toolkit designed to solve a common problem in Kubernetes workflows: comparing and managing YAML manifests while ignoring irrelevant differences.
When working with tools like Helm, Kustomize, or ArgoCD, you often need to compare manifests to detect drift, validate changes, or ensure consistency. However, raw YAML diffs are noisy - filled with differences in field ordering, timestamps, managed fields, and other metadata that doesn't matter for your use case.
kyt solves this by:
- Formatting manifests - Sorts keys alphabetically for consistent YAML structure
- Smart comparison - Normalizes and compares manifests using ArgoCD-compatible ignore rules (removes fields, applies custom rules, sorts keys)
- Beautiful diffs - Generates unified diff output (git-style) that's easy to read and integrate with tools (delta, difftohtml ...)
- Terminal UI - Terminal UI inspired by k9s for exploring large diffs
Key Features:
- π― ArgoCD-Compatible Rules: Uses the same ignore syntax as ArgoCD's
ignoreDifferences - π JSON Pointer Support: RFC 6901 compliant JSON Pointers for precise field targeting
- π¨ JQ Path Expressions: Powerful filtering with wildcards and conditionals
- π Multiple Output Formats: Unified diff with optional pager support (less, delta, bat)
- π₯οΈ Interactive TUI Mode: k9s-inspired terminal UI for exploring large diffs (
--tui) - π― Smart Normalization: Removes managed fields, applies ignore rules, sorts keys (used by
diff) - βΈοΈ Live Cluster Comparison: Compare local manifests against live Kubernetes resources
- π Secret Masking: Automatically masks Kubernetes Secret values to prevent credential leaks in CI/CD logs
- π§ Format: Sort keys consistently with
kyt fmt - π Pipe-friendly: Works seamlessly with kubectl, kustomize, helm
- π€ Intelligent Similarity Matching: Automatically detects renamed resources across namespaces
- ποΈ Configurable Matching: Adjust similarity thresholds and data field importance
- ποΈ Resource Filtering: Filter by resource kinds and namespaces with unified syntax (supports short names like
cm,svc,deploy) - β‘ Fast & Reliable: Written in Go with comprehensive test coverage
Use Cases
- Compare local manifests vs live cluster: Detect configuration drift between Git (desired state) and actual cluster state
- Compare across namespaces: Compare production vs staging environments directly in the cluster
- Compare Helm vs Kustomize outputs: Validate migrations by comparing rendered manifests while ignoring expected differences (field order, formatting, etc.)
- Detect configuration drift: Compare desired state (Git) with actual cluster state (
kubectl get), ignoring dynamic fields like timestamps and resource versions - CI/CD validation: Ensure manifest changes are intentional by comparing PR changes against production, with rules to ignore acceptable differences
- Pre-deployment validation: Compare what's currently deployed vs what will be deployed, filtering out noise
- Format and standardize: Clean up YAML files by sorting keys alphabetically for consistent formatting
Quick Start
# Build from source
git clone https://github.com/nhuray/kyt.git
cd kyt
make build
# Compare two manifest files
./bin/kyt diff source.yaml target.yaml
# Compare directories
./bin/kyt diff ./kustomize-output ./helm-output
# Compare local manifests against live cluster
./bin/kyt diff ./manifests ns:production
# Compare two namespaces in the cluster
./bin/kyt diff ns:production ns:staging
# Interactive TUI mode for exploring diffs
./bin/kyt diff ./manifests ns:production --tui
# Normalize a manifest file
./bin/kyt fmt deployment.yaml
# Pipe manifests through kyt
kustomize build . | kyt fmt | kubectl apply -f -
# Use custom config
./bin/kyt diff -c .kyt.yaml source.yaml target.yaml
# Secret masking (enabled by default)
./bin/kyt diff source.yaml target.yaml # Secrets are masked
./bin/kyt diff --mask-secrets=false source.yaml target.yaml # Disable masking
# Output JSON for CI/CD
./bin/kyt diff -o json source.yaml target.yaml
Commands
kyt diff - Compare manifests
Compare two Kubernetes manifest files, directories, or live cluster namespaces with smart ignore rules and intelligent similarity matching.
Interactive TUI Mode:
Launch an interactive k9s-inspired terminal UI for exploring diffs with --tui. Perfect for navigating large diffs with hundreds of resources.
# Launch TUI for interactive exploration
kyt diff source.yaml target.yaml --tui
# Compare namespaces in TUI
kyt diff ns:production ns:staging --tui
# All filtering options work with TUI
kyt diff --kind deploy,svc ns:prod ns:staging --tui
TUI Features:
- Tabbed Views: All / Added / Modified / Removed resources
- Navigation: vim-style keybindings (h/j/k/l, g/G)
- Search: Filter by Kind, Name, or Namespace (
/) - Sorting: Sort by name (
N) or status (S) with reverse toggle - Diff Modes: Side-by-side and unified views (
s,u) - Quit:
:qto quit,qto go back
Live Cluster Comparison:
Use the ns:namespace syntax to fetch and compare resources directly from Kubernetes clusters. kyt automatically uses your current kubectl context, or you can specify a different context with --context.
# Compare local manifests against live cluster (uses current context)
kyt diff ./manifests ns:production
# Compare two namespaces in the same cluster
kyt diff ns:production ns:staging
# Compare using a specific cluster context
kyt diff --context prod ns:production ns:staging
# Compare specific resource types from cluster
kyt diff --kind deploy,svc,cm ns:production ns:staging
# Verbose output shows connection and resource fetching details
kyt diff -v ns:production ns:staging
Similarity Matching:
kyt can automatically detect renamed or relocated resources across namespaces using structural similarity. This is particularly useful when comparing production vs staging environments where resource names and namespaces may differ.
# Basic comparison
kyt diff source.yaml target.yaml
# Compare directories
kyt diff ./helm-output ./kustomize-output
# Compare across namespaces (prod vs staging)
kyt diff ./prod-manifests ./staging-manifests
# Disable similarity matching (exact name match only)
kyt diff --exact-match source.yaml target.yaml
# Adjust similarity threshold (0.0-1.0, default: 0.7)
kyt diff --similarity-threshold 0.8 source.yaml target.yaml
# Boost ConfigMap/Secret data field importance (1-10, default: 2)
# Higher values prioritize data content over metadata differences
kyt diff --data-similarity-boost 4 source.yaml target.yaml
# Filter by resource kind (include only specific types)
kyt diff --kind cm,svc,deploy source.yaml target.yaml
# Filter by resource kind (exclude specific types)
kyt diff --kind -secrets,-configmaps source.yaml target.yaml
# Filter by namespace
kyt diff --namespace production,staging source.yaml target.yaml
# Exclude specific namespaces
kyt diff --namespace -kube-system source.yaml target.yaml
# Combine kind and namespace filters
kyt diff --kind deploy,sts --namespace production source.yaml target.yaml
# Show summary of changes
kyt diff --summary source.yaml target.yaml
# Control output colorization
kyt diff --color always source.yaml target.yaml # Always colorize
kyt diff --color never source.yaml target.yaml # Never colorize
kyt diff --color auto source.yaml target.yaml # Auto (default)
# Write output to file
kyt diff -o diff.txt source.yaml target.yaml
Exit Codes:
0- No differences found1- Differences detected2- Error (invalid YAML, missing files, etc.)
kyt fmt - Format manifests
Format Kubernetes manifests by sorting keys alphabetically for consistent YAML structure.
# Format a file to stdout
kyt fmt deployment.yaml
# Format a directory to stdout
kyt fmt ./manifests
# Format and write back to source files
kyt fmt -w ./manifests
# Format from stdin
cat deployment.yaml | kyt fmt
# Chain with other tools
kustomize build . | kyt fmt | kubectl apply -f -
helm template . | kyt fmt > formatted.yaml
kyt version - Version information
kyt version
Configuration
The diff command uses .kyt.yaml for normalization rules, similarity matching options, and ignore rules. The tool searches for this file in the current directory and parent directories.
The fmt command does not use configuration - it only sorts keys.
# .kyt.yaml
diff:
# Ignore differences for specific resources
ignoreDifferences:
# Ignore all labels and annotations
- group: ""
kind: "*"
jsonPointers:
- /metadata/labels
- /metadata/annotations
# Ignore Istio sidecar containers
- group: "apps"
kind: "Deployment"
jqPathExpressions:
- .spec.template.spec.containers[] | select(.name == "istio-proxy")
# Ignore specific fields in Services
- group: ""
kind: "Service"
jsonPointers:
- /spec/clusterIP
- /spec/clusterIPs
# Diff options
options:
contextLines: 3 # Lines of context in unified diff (default: 3)
similarityThreshold: 0.7 # Min similarity score for matching (0.0-1.0, default: 0.7)
dataSimilarityBoost: 2 # Boost for ConfigMap/Secret data fields (1-10, default: 2)
# Default resource filters (can be overridden by CLI flags)
# CLI flags take precedence over these settings
filters:
# Resource kinds to include/exclude
# Use "-" prefix for exclusions
# Examples:
# kinds: ["Deployment", "StatefulSet"] # include only these
# kinds: ["-Secret", "-ConfigMap"] # exclude these
kinds: []
# Namespaces to include/exclude
# Use "-" prefix for exclusions
# Note: Cluster-scoped resources (ClusterRole, Node, etc.) are excluded when namespace filters are active
# Examples:
# namespaces: ["production", "staging"] # include only these
# namespaces: ["-kube-system", "-kube-public"] # exclude system namespaces
namespaces: []
# Secret masking configuration (pattern-based rules)
# Masks Kubernetes Secret data/stringData values to prevent credential leaks in CI/CD logs
secretMasking:
enabled: true # Enable/disable masking (default: true)
maskChar: "*" # Masking character (default: "*")
fields: ["data", "stringData"] # Secret fields to mask (default: ["data", "stringData"])
# Pattern-based masking rules (evaluated in order, first match wins)
# Each rule uses regex with named capture groups
# Strategies: "mask-F-E" (keep first F, last E chars) or "mask-F-E-S-M" (sequenced)
rules:
# PostgreSQL/MySQL connection strings
- name: "postgres"
pattern: '^postgres(?:ql)?://(?<user>[^:]+):(?<password>[^@]+)@(?<host>.+)$'
masks:
user: "mask-2-0" # Keep first 2 chars
password: "mask-2-2" # Keep first/last 2 chars
host: "mask-0-10" # Keep last 10 chars
# Default fallback for any other format
- name: "default"
pattern: '^(?<value>.+)$'
masks:
value: "mask-2-2" # Keep first/last 2 chars
# Fuzzy string matching configuration
fuzzyMatching:
enabled: true # Enable Levenshtein distance for strings (default: true)
minStringLength: 100 # Min string length for fuzzy matching (default: 100)
# Normalization options
normalization:
sortKeys: true # Sort object keys alphabetically
removeDefaultFields: # Fields to remove before comparison
- "/status"
- "/metadata/managedFields"
- "/metadata/creationTimestamp"
# Optional: pipe output through external diff viewer
pager: "" # Examples: "delta --side-by-side", "bat --language=diff", "less -R"
See examples/.kyt.yaml for a complete configuration example.
Installation
Binary Releases (Recommended)
Download pre-built binaries from GitHub Releases:
Linux (x86_64):
curl -L https://github.com/nhuray/kyt/releases/latest/download/kyt_Linux_x86_64.tar.gz | tar xz
sudo mv kyt /usr/local/bin/
macOS (Apple Silicon):
curl -L https://github.com/nhuray/kyt/releases/latest/download/kyt_Darwin_arm64.tar.gz | tar xz
sudo mv kyt /usr/local/bin/
macOS (Intel):
curl -L https://github.com/nhuray/kyt/releases/latest/download/kyt_Darwin_x86_64.tar.gz | tar xz
sudo mv kyt /usr/local/bin/
Windows (PowerShell):
Invoke-WebRequest -Uri "https://github.com/nhuray/kyt/releases/latest/download/kyt_Windows_x86_64.zip" -OutFile "kyt.zip"
Expand-Archive -Path "kyt.zip" -DestinationPath .
# Add kyt.exe to your PATH
Using Flox
Flox provides reproducible environments and package management. Install kyt from the private catalog:
# Install directly
flox install nhuray/kyt
# Or add to your Flox environment
flox init
flox edit # Add: "nhuray/kyt".pkg-path = "nhuray/kyt"
flox activate
kyt version
Using Go Install
go install github.com/nhuray/kyt/cmd/kyt@latest
From Source
git clone https://github.com/nhuray/kyt.git
cd kyt
# Using Make (recommended)
make build
# Or directly with Go
go build -o bin/kyt ./cmd/kyt
# Optional: Install to your PATH
make install
# Or manually: cp bin/kyt /usr/local/bin/
Verify Installation
kyt version
Security
Secret Masking
To prevent accidental credential leaks in CI/CD logs and console output, kyt automatically masks Kubernetes Secret values using pattern-based rules.
How it works:
When comparing Secrets, kyt applies regex-based masking rules with named capture groups:
- Rules are evaluated in order (first match wins)
- Each rule defines patterns for specific credential types (database URLs, API keys, etc.)
- Masking strategies preserve structural patterns while hiding sensitive data
- Works across all output formats: unified diff, summary, markdown, and TUI
Examples:
PostgreSQL: postgres://admin:MySecretPass@db.com:5432/prod
Masked: postgres://ad***:My**********ss@*****:5432/prod
MongoDB: mongodb://user:P@ssw0rd@cluster.net/db
Masked: mongodb://us**:*****0rd@*******ter.net/db
API Key: apikey_live_ExAmPlE1234567890aBcDeF
Masked: ************ExAm***************cDeF
JWT: eyJhbGc.eyJzdWI.SflKxwRJ
Masked: ***JhbGc.eyJs********RJ.********
Configuration:
Customize masking rules in .kyt.yaml:
diff:
secretMasking:
enabled: true # Enable/disable (default: true)
maskChar: "*" # Masking character (default: "*")
fields: ["data", "stringData"] # Fields to mask
# Pattern-based rules (first match wins)
rules:
# PostgreSQL connection strings
- name: "postgres"
pattern: '^postgres://(?<user>[^:]+):(?<password>[^@]+)@(?<host>.+)$'
masks:
user: "mask-2-0" # Keep first 2 chars
password: "mask-2-2" # Keep first/last 2 chars
host: "mask-0-10" # Keep last 10 chars
# API keys with prefixes
- name: "api-key"
pattern: '^(?<prefix>sk_[a-z]+_)(?<secret>[A-Za-z0-9]+)$'
masks:
prefix: "mask-0-0" # Fully mask prefix
secret: "mask-4-4" # Keep first/last 4 chars
# Default fallback
- name: "default"
pattern: '^(?<value>.+)$'
masks:
value: "mask-2-2" # Keep first/last 2 chars
Masking Strategies:
mask-F-E: Keep first F and last E characters, mask middle- Example:
mask-2-2on "password123" β "pa********23"
- Example:
mask-F-E-S-M: Sequenced masking (keep F, keep E, then mask S/keep M/repeat)- Example:
mask-2-2-5-1on "1234567890abcdefgh" β "128d**gh" - Useful for complex credentials where simple masking hides too much structure
- Example:
CLI Control:
# Default behavior (masking enabled)
kyt diff ./left ./right
# Disable masking temporarily
kyt diff --mask-secrets=false ./left ./right
# Alternative: exclude Secrets entirely
kyt diff --kind -secrets ./left ./right
Example output:
--- a/Secret.core/my-secret
+++ b/Secret.core/my-secret
@@ -1,7 +1,7 @@
apiVersion: v1
data:
- password: cG************M= # Masked value
+ password: bm************Q= # Masked value
token: dG****************kw
kind: Secret
Documentation
- Cluster Comparison Guide - Complete guide to comparing live Kubernetes resources
- fmt Command Guide - Complete guide to formatting manifests with configuration options
- diff Command Guide - Advanced comparison techniques with JQ expressions and examples
- Example Configs - Sample configurations and manifests
Testing
The project has comprehensive test coverage:
- 240+ tests total covering all major functionality
- All tests passing
- Covers: config loading, manifest parsing, normalization, diffing, output formatting, CLI commands, cluster operations
Run tests:
# Run all tests
make test
# Run with verbose output
make test-verbose
# Run with coverage report
make test-coverage
# Or use go directly
go test ./...
go test -v ./...
go test -coverprofile=coverage.out ./...
Development
# Show all available make targets
make help
# Build the binary
make build
# Run tests
make test
# Clean build artifacts
make clean
# Run with example manifests
make run
make run-json
Dependencies
Go Libraries:
- client-go - Kubernetes client library for live cluster access
- go-udiff - Unified diff generation
- ArgoCD - Ignore rules engine
- gojq - JQ implementation in Go
- cobra - CLI framework
- bubbletea - TUI framework (for
--tuimode) - bubbles - TUI components (table, viewport)
- lipgloss - Terminal styling
Inspiration
This project is inspired by:
- ArgoCD's diff customization
- k9s - Kubernetes CLI with TUI (inspired the
--tuimode) - kubectl diff
- dyff - YAML diff tool
- helm-drift - Helm drift detection
Contributing
Contributions are welcome! Please see CONTRIBUTING.md (coming soon) for guidelines.
License
MIT License - See LICENSE for details.
Author
Created by Nicolas Huray (@nhuray)