kat automatically invokes manifest generators like helm or kustomize, and provides a persistent, navigable view of rendered resources, with support for live reloading, integrated validation, and more.
It is made of two main components, which can be used together or independently:
Together, these deliver a seamless development experience that maintains context and focus while iterating on Helm charts, Kustomize overlays, and other manifest generators.

❤️ Made with bubble tea, chroma, and other amazing libraries.
🔍️ Manifest browsing
⚡️ Live reload
--watch for automatic re-rendering🐛 Error handling
🧪 Tool integration
kubeconform or kyverno automatically on rendered manifests🎯 Project detection
.katrc.yaml files🔌 Plugin system
🤖 MCP server (Experimental)
🎨 Fully customizable
Homebrew
You can install kat using my tap.
With brew:
brew install macropower/tap/kat --cask
With your Brewfile:
tap "macropower/tap"
cask "kat"
Go
go install github.com/macropower/kat/cmd/kat@latest
Docker
Docker images are published to ghcr.io/macropower.
All images are configured with WORKDIR=/data, so you can mount your current directory there to run kat against your local files.
Run the latest alpine image:
docker run -it -v .:/data -e TERM=$TERM ghcr.io/macropower/kat:latest-alpine
The default config is located at /config/kat/config.yaml, and you can override it by mounting your own configuration file at that path.
There is also a scratch image that contains only the kat binary, which is useful when you want to build your own image (which I generally recommend doing):
FROM alpine:latest
COPY --from=ghcr.io/macropower/kat:latest /kat /usr/local/bin/kat
# Add whatever customization you need here.
ENTRYPOINT ["/usr/local/bin/kat"]
Nix (NUR)
You can install kat using my NUR.
With nix-env:
nix-env -iA kat -f https://github.com/macropower/nur-packages/archive/main.tar.gz
With nix-shell:
nix-shell -A kat https://github.com/macropower/nur-packages/archive/main.tar.gz
With your flake.nix:
{
inputs = {
macropower.url = "github:macropower/nur-packages";
};
# Reference the package as `inputs.macropower.packages.<system>.kat`
}
With devbox:
devbox add github:macropower/nur-packages#kat
GitHub CLI
gh release download -R macropower/kat -p "kat_$(uname -s)_$(uname -m).tar.gz" -O - | tar -xz
And then move kat to a directory in your PATH.
Curl
curl -s https://api.github.com/repos/macropower/kat/releases/latest | \
jq -r ".assets[] |
select(.name | test(\"kat_$(uname -s)_$(uname -m).tar.gz\")) |
.browser_download_url" | \
xargs curl -L | tar -xz
And then move kat to a directory in your PATH.
Or, download a binary from releases.
Note: The default
katconfiguration contains references tohelm,kustomize, andyq. If you want to usekatwith these tools, you will need to install them separately.
You can verify the authenticity and integrity of kat releases.
See verification for more details.
Show help:
kat --help
Render a project in the current directory:
kat
Render a project and enable watch (live reloading):
kat -w
Render a project in a specific directory:
kat ./example/helm
Render a project in a specific directory using the ks profile:
kat ./example/kustomize ks
Render a project with custom profile arguments:
kat ./example/helm -- -g -f prod-values.yaml
kat ./example/kustomize ks -- --enable-helm
Render a project with command passthrough:
kat ./example/helm task -- helm:render
Read from stdin (disables rendering engine):
cat ./example/kustomize/resources.yaml | kat -
Send output to a file (disables TUI):
kat ./example/helm > manifest.yaml
You can optionally start kat with an MCP server by using the --serve-mcp flag:
kat --serve-mcp :50165
See MCP Server for more details.
When you first run kat, it will attempt to add default configuration files to $XDG_CONFIG_HOME/kat/ (or ~/.config/kat/). This configuration allows you to customize the behavior of kat, such as the UI style, keybindings, rules for project detection, and profiles for rendering different types of projects.
Note that JSON schemas are also included in the configuration directory, which can be used by your editor's YAML language server.
Some of the default behavior around loading configuration can be overridden with command line flags or environment variables. See
kat --helpfor details.
Over time, the default configuration may change, and the schema is currently still evolving. If you want to reset your configuration to the latest defaults, you can use kat --write-config, which will move your existing configuration to a backup file and generate a new default configuration.
You can find the default configuration file as well as JSON schemas in api.
You can customize how kat detects and renders different types of projects using rules and profiles in the configuration file. This system uses CEL (Common Expression Language) expressions to provide flexible file matching and processing.
Rules determine which profile should be used. Each rule contains:
match (required): A CEL expression that returns true if the rule should be appliedprofile (required): The name of the profile to use when this rule matchesRules use boolean CEL expressions with access to:
files (list): All file paths in the directorydir (string): The directory path being processedrules:
- # Select the Helm profile if any Helm chart files exist
match: >-
files.exists(f, pathBase(f) in ["Chart.yaml", "Chart.yml"])
profile: helm
- # Select the Kustomize profile if any Kustomization files exist
match: >-
files.exists(f, pathBase(f) in ["kustomization.yaml", "kustomization.yml"])
profile: ks
- # Fallback: select the YAML profile if any YAML files exist
match: >-
files.exists(f, pathExt(f) in [".yaml", ".yml"])
profile: yaml
Profiles define how to render projects. They can be automatically selected by rules, or manually specified when kat is invoked. Each profile contains:
command (required): The command to executeargs: Arguments to pass to the commandextraArgs: Arguments that can be overridden from the CLIenv: List of environment variables for the commandenvFrom: List of sources for environment variablessource: Define which files to watch for changes (when watch is enabled)reload: Define conditions for when events should trigger a reloadui: UI configuration overrideshooks: Initialization and rendering hooksinit hooks are executed once when kat is initializedpreRender hooks are executed before the profile's command is runpostRender hooks are executed after the profile's command has run, and are provided the rendered output via stdinplugins: Custom commands that can be executed on-demand with keybindsdescription (required): Human-readable description of what the plugin doeskeys (required): Array of key bindings that trigger the plugincommand (required): The command to executeargs: Arguments to pass to the commandprofiles:
helm:
command: helm
args: [template, .]
extraArgs: [-g]
source: >-
files.filter(f, pathExt(f) in [".yaml", ".yml", ".tpl"])
reload: >-
fs.event.has(fs.WRITE, fs.CREATE, fs.REMOVE)
envFrom:
- callerRef:
pattern: "^HELM_.+"
ui:
theme: dracula
hooks:
init:
- command: helm
args: [version, --short]
preRender:
- command: helm
args: [dependency, build]
envFrom:
- callerRef:
pattern: "^HELM_.+"
postRender:
# Pass the rendered manifest via stdin to `kubeconform`.
- command: kubeconform
args: [-strict, -summary]
plugins:
dry-run:
command: helm
args: [install, ., -g, --dry-run]
envFrom:
- callerRef:
pattern: "^HELM_.+"
description: invoke helm dry-run
keys:
- code: ctrl+r
alias: ⌃r
ks:
command: kustomize
args: [build, .]
source: >-
files.filter(f, pathExt(f) in [".yaml", ".yml"])
reload: >-
fs.event.has(fs.WRITE, fs.CREATE, fs.REMOVE)
env:
- name: KUSTOMIZE_ENABLE_ALPHA_COMMANDS
value: "true"
ui:
compact: true
theme: tokyonight-storm
hooks:
init:
- command: kustomize
args: [version]
kat provides custom CEL functions for use in rules and profiles:
Path Functions:
pathBase(string): Returns the filename (e.g., "Chart.yaml")pathExt(string): Returns the file extension (e.g., ".yaml")pathDir(string): Returns the directory pathYAML Functions:
yamlPath(file, path): Reads a YAML file and extracts a value using a JSONPath expressionEvent Functions:
has(event, flag...): Checks if a file system event contains specific flagsFile System Constants:
fs.CREATE, fs.WRITE, fs.REMOVE, fs.RENAME, fs.CHMOD: File system event typesRender Status Constants:
render.STAGE_NONE, render.STAGE_PRE_RENDER, render.STAGE_RENDER, render.STAGE_POST_RENDER: Render stagesrender.RESULT_NONE, render.RESULT_OK, render.RESULT_ERROR, render.RESULT_CANCEL: Render resultsYou can combine these with CEL's built-in functions like exists(), filter(), in, contains(), matches(), and logical operators.
Example:
rules:
- match: >-
files.exists(f,
pathBase(f) == "Chart.yaml" &&
yamlPath(f, "$.apiVersion") == "v2")
profile: helm
profiles:
helm:
command: helm
args: [template, .]
extraArgs: [-g]
source: >-
files.filter(f,
pathExt(f) in [".yaml", ".yml", ".tpl"])
reload: >-
fs.event.has(fs.WRITE, fs.RENAME) &&
render.result != render.RESULT_CANCEL
For more details on CEL expressions and examples, see the CEL documentation.
Projects can include their own .katrc.yaml file to define project-specific rules and profiles. For example, you can