kat

module
v0.13.0-rc.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 29, 2025 License: Apache-2.0

README ΒΆ

kat

kat provides a terminal UI for rendering, validating, and displaying local Kubernetes manifests. It eliminates the frustrating cycle of manually running commands, scrolling through endless output, and constantly losing context when working with Helm charts, Kustomize overlays, and other manifest generators.


❀️ Made with bubble tea, glow, and chroma.

✨ Features

  • πŸ”οΈ Manifest browsing - Navigate hundreds of rendered manifests with fuzzy search and filtering, no more endless scrolling through terminal output
  • ⚑️ Live reload - Use --watch to automatically re-render when you modify source files, without losing your current context
  • πŸ› Error handling - Rendering and validation errors are displayed as overlays and disappear if reloading resolves the error
  • 🎯 Project detection - Automatically detect Helm charts, Kustomize projects, and custom manifest generators using powerful CEL expressions
  • πŸ§ͺ Tool integration - Define profiles for any manifest generator (Helm, Kustomize, CUE, KCL, Jsonnet, etc.) with pre/post-render hooks
  • πŸ”Œ Plugin system - Create custom keybind-triggered commands for common tasks that can't run on hooks, like dry-runs or diffs
  • βœ… Custom validation - Run tools like kubeconform, kyverno, or custom validators automatically on rendered output
  • 🎨 Beautiful UI - Syntax-highlighted YAML with customizable themes and keybindings that match your preferences

πŸ“¦ Installation

Homebrew

brew install macropower/tap/kat --cask

Go

go install github.com/macropower/kat/cmd/kat@latest

Releases

Binaries are posted in releases.

πŸš€ Usage

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 and override the profile arguments:

kat ./example/kustomize ks -- build . --enable-helm

Render a project with command passthrough:

kat ./example/helm task -- helm:render

Render using data from stdin:

cat ./example/kustomize/resources.yaml | kat -f -

βš™οΈ Configuration

You can use kat --write-config to generate a default configuration file at ~/.config/kat/config.yaml. This file 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.

Alternatively, you can find the default configuration file in pkg/config/config.yaml.

πŸ› οΈ Rules and Profiles

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

Rules determine which profile should be used. Each rule contains:

  • match (required): A CEL expression that returns true if the rule should be applied
  • profile (required): The name of the profile to use when this rule matches

Rules use boolean CEL expressions with access to:

  • files (list): All file paths in the directory
  • dir (string): The directory path being processed
rules:
  - # 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

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 execute
  • args: Arguments to pass to the command
  • source: Define which files to watch for changes (when watch is enabled)
  • ui: UI configuration overrides
  • hooks: Initialization and rendering hooks
    • init hooks are executed once when kat is initialized
    • preRender hooks are executed before the profile's command is run
    • postRender hooks are executed after the profile's command has run, and are provided the rendered output via stdin
  • plugins: Custom commands that can be executed on-demand with keybinds
    • description (required): Human-readable description of what the plugin does
    • keys (required): Array of key bindings that trigger the plugin
    • command (required): The command to execute
    • args: Arguments to pass to the command

Profile source expressions use list-returning CEL expressions with the same variables as rules.

profiles:
  helm:
    command: helm
    args: [template, ., --generate-name]
    source: >-
      files.filter(f, pathExt(f) in [".yaml", ".yml", ".tpl"])
    ui:
      theme: dracula
    hooks:
      init:
        - command: helm
          args: [version, --short]
      preRender:
        - command: helm
          args: [dependency, build]
      postRender:
        # Pass the rendered manifests via stdin to `kubeconform`.
        - command: kubeconform
          args: [-strict, -summary]
    plugins:
      dry-run:
        command: helm
        args: [install, ., -g, --dry-run]
        description: invoke helm dry-run
        keys:
          - code: shift+h
            alias: ⇧+h

  ks:
    command: kustomize
    args: [build, .]
    source: >-
      files.filter(f, pathExt(f) in [".yaml", ".yml"])
    ui:
      compact: true
      theme: tokyonight-storm
    hooks:
      init:
        - command: kustomize
          args: [version]

🧩 CEL Functions

kat provides custom CEL functions for file path operations:

  • pathBase(string): Returns the filename (e.g., "Chart.yaml")
  • pathExt(string): Returns the file extension (e.g., ".yaml")
  • pathDir(string): Returns the directory path
  • yamlPath(file, path): Reads a YAML file and extracts a value using a YAML path expression

You 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, ., --generate-name]
    source: >-
      files.filter(f,
        pathExt(f) in [".yaml", ".yml", ".tpl"])

For more details on CEL expressions and examples, see the CEL documentation.

πŸ”₯ DRY Configuration

The kat configuration supports YAML anchor nodes, alias nodes, and merge keys. You can define common settings once and reuse them across the configuration.

profiles:
  ks: &ks
    command: kustomize
    args: [build, .]
    source: >-
      files.filter(f, pathExt(f) in [".yaml", ".yml"])
    hooks:
      postRender:
        - &kubeconform
          command: kubeconform
          args: [-strict, -summary]

  ks-helm:
    <<: *ks
    args: [build, ., --enable-helm]

  helm:
    command: helm
    args: [template, ., --generate-name]
    source: >-
      files.filter(f, pathExt(f) in [".yaml", ".yml", ".tpl"])
    hooks:
      postRender:
        - *kubeconform

❀️ Thanks to goccy/go-yaml.

πŸ“– Examples

Default config - By default, kat includes a configuration that supports helm, kustomize, and generic YAML files. This is a great starting point for writing your own custom config:

Support for custom tools - You can add support for other languages/tools like kcl, jsonnet, flux-local, cue, and so on:

rules:
  - match: >-
      files.exists(f, pathExt(f) == ".k")
    profile: kcl
profiles:
  kcl:
    command: kcl
    args: [run, .]
    source: >-
      files.filter(f, pathExt(f) == ".k")

Content-based detection - Match based on file content, not just names:

rules:
  - # Match Helm v3 specifically
    match: >-
      files.exists(f,
        pathBase(f) == "Chart.yaml" &&
        yamlPath(f, "$.apiVersion") == "v2")
    profile: helm-v3
  - # Match Kubernetes native manifests with specific API versions
    match: >-
      files.exists(f,
        pathExt(f) in [".yaml", ".yml"] &&
        yamlPath(f, "$.apiVersion") in ["apps/v1", "v1"])
    profile: yaml

Using Task - If you use task, you can use your tasks in the kat config:

rules:
  - match: >-
      files.exists(f, pathBase(f) in ["Taskfile.yml", "Taskfile.yaml"])
    profile: task
profiles:
  task:
    command: task
    args: [render]
    source: >-
      files.filter(f, pathExt(f) in [".yaml", ".yml"])
    hooks:
      postRender:
        - command: task
          args: [validate]

Note that you should write your task to:

  • Output the rendered manifests to stdout, and anything else to stderr.
  • Tolerate being called from any directory in the project.
    • E.g., instead of ./folder, use {{joinPath .ROOT_DIR "folder"}}.
  • Not require any additional arguments to run.
    • You can reference {{.USER_WORKING_DIR}} to obtain the path that the user invoked kat from/with.
    • E.g., vars: { PATH: "{{.PATH | default .USER_WORKING_DIR}}" }

If you are concerned about safety (i.e. accidentally calling a task defined by someone else), you can consider not including a rule for task and only allowing it to be invoked manually via the CLI args, or you could write a more narrow match expression (e.g. f.contains("/my-org/")).

🌈 Themes

Themes

Configure a theme with --ui-theme, KAT_UI_THEME, or via config:

ui:
  theme: "dracula"

You can optionally set different themes for different profiles:

profiles:
  helm:
    ui:
      theme: "dracula"
      # ...
  ks:
    ui:
      theme: "tokyonight-storm"
      # ...

We use Chroma for theming, so you can use any styles from the Chroma Style Gallery.

You can also add your own themes in the config:

ui:
  theme: "my-custom-theme"
  themes:
    my-custom-theme:
      styles:
        background: "#abb2bf bg:#282c34"
        punctuation: "#abb2bf"
        keyword: "#c678dd"
        name: "bold #e06c75"
        comment: "italic #8b949e"
        commentSpecial: "bold italic #8b949e"
        # ...

Chroma uses the same syntax as Pygments. Define ui.themes.[name].styles as a map of Pygments Tokens to Styles. You can then reference any theme in ui.theme (or by using the corresponding flag / env var).

πŸ”οΈ Similar Tools

Directories ΒΆ

Path Synopsis
cmd
kat command
pkg
expr
Package expr provides CEL (Common Expression Language) functionality for evaluating expressions against file paths and YAML content.
Package expr provides CEL (Common Expression Language) functionality for evaluating expressions against file paths and YAML content.
log
Package log provides logging utilities.
Package log provides logging utilities.
profile
Package profile provides command profile functionality for executing commands with optional source filtering using CEL expressions.
Package profile provides command profile functionality for executing commands with optional source filtering using CEL expressions.
rule
Package rules provides functionality for matching files and directories using CEL (Common Expression Language) expressions.
Package rules provides functionality for matching files and directories using CEL (Common Expression Language) expressions.
ui
Package ui provides the main UI for the kat application.
Package ui provides the main UI for the kat application.
ui/overlay
Package overlay provides terminal UI overlay functionality for placing foreground content on top of background content, similar to modal dialogs or popup windows in terminal applications.
Package overlay provides terminal UI overlay functionality for placing foreground content on top of background content, similar to modal dialogs or popup windows in terminal applications.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL