kubespy: watching Kubernetes resources change in real time
Tools for observing Kubernetes resources in real time, powered by Pulumi.
At a glance
- What is it?
- kubespy is a small Go CLI from Pulumi that streams the changes a Kubernetes object makes as it is created and reconciled. It is useful for debugging rollouts, and it is not a replacement for kubectl or a monitoring stack.
- Who is it for?
- kubespy fits engineers who are debugging a single resource and want to see its .status field change second by second, and it is the wrong tool for anything that needs to run unattended or cover a whole cluster.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The gap kubespy fills between kubectl apply and a settled cluster
A Deployment is applied and the terminal returns. What happens next is a sequence of intermediate states: a ReplicaSet is created, Pods are scheduled, containers pull images, readiness probes fail and then pass, and the Deployment's status fields move through several values. kubectl describe gives a snapshot of that sequence, and kubectl get --watch gives a stream of whole objects. Neither aggregates the sequence into something you can read at a glance, and neither is designed to answer questions like how often a Deployment's status is changing.
kubespy is aimed at that window. The README frames it as a tool that makes it easy to observe how Kubernetes resources change in real time, derived from work Pulumi did to make Kubernetes deployments predictable in its own CLI. The audience is narrow and practical: someone who is writing or debugging a controller, a manifest, or a rollout and wants to watch the object rather than infer its state from logs. It assumes you already have a kubeconfig and cluster access, and it assumes you are at a terminal.
How kubespy reads the cluster: discovery, watches and diffs
The repository layout shows the mechanism split across packages: k8sconfig/, k8sobject/, pods/, print/, version/ and watch/, with the command definitions under cmd/. The README states that kubespy uses the discovery client to discover the available API resources and allows users to query any of them, including custom resources. That is why the commands take an apiVersion and a kind rather than a fixed list of built-in types.
From there the tool opens a watch on the named object and renders what arrives. The four commands differ in what they select and how they present it. status emits changes to the .status field as a JSON diff. changes emits changes to any field, also as a JSON diff. record emits changes to any field as a JSON array, which is the form you would keep rather than read. trace takes only a kind and a name, with no apiVersion, and the README describes it as tracing the changes a complex resource makes throughout a cluster and aggregating them into a high-level summary that is updated in real time. That aggregation is the interesting part: a Deployment touches Pods, ReplicaSets and other objects, and trace is the command that follows those relationships instead of reporting one object's fields.
The diffing itself is delegated to a JSON diff library, and the terminal rendering uses a live-updating writer plus color output, both visible in go.mod. The README notes that status output is syntax-highlighted JSON diffs. Nothing in the repository describes a server-side component, a daemon, or persistent storage: kubespy is a client that watches and prints.
Installing kubespy and tracing a Deployment rollout
The README lists four installation paths. Homebrew is the shortest on macOS. The formula installs the binary under the name kubespy.
brew install kubespyIf you prefer to build it yourself, the README gives a Go prerequisite of version 1.19 or later and this command, which installs from the module path recorded in go.mod.
go install github.com/pulumi/kubespy@latestThere is also a release binary you rename to kubespy, mark executable with chmod +x, and move onto your path, with /usr/local/bin offered as an example location. The fourth path turns kubespy into a kubectl plugin: with kubectl v1.12.0 or later, renaming the binary to kubectl-spy and putting it on your path makes it invocable as kubectl spy. The README does not describe any configuration file or environment variable, so the cluster it talks to is whatever your kubeconfig currently selects.
For a first real use, pick a Deployment in a namespace you can disturb and run trace against it. The README's own example is a Deployment called nginx.
kubespy trace deployment nginxThe command runs until you kill it. What you should see is a summary that updates in place as the rollout proceeds, rather than a scrolling log. If you would rather watch one field, status takes an apiVersion, a kind and a name, and the README's example is a Pod called nginx.
kubespy status v1 Pod nginxThat form waits for the Pod to be created and then emits changes to its .status field as syntax-highlighted JSON diffs. The namespace is optional in the name argument: the README writes it as [<namespace>/]<name>, so you can pass default/nginx when the object is not in your current namespace. If you want the raw stream instead of a rendered diff, record emits the same changes as a JSON array.
Where kubespy stops being the right tool
The commands are foreground processes. The README says to run kubespy at any point in time and that it will watch and report until you kill it. There is no documented flag for writing output to a file, no daemon mode, and no retention beyond what your terminal scrollback holds. For an incident that happened an hour ago, kubespy has nothing to show you, because it was not running.
Coverage is per-object. The README's feature list has two unchecked items: case-insensitive aliases, so you must write v1 Pod rather than v1 pod, and status updates from regex or fuzzy matching, which would make it easy to watch Pods generated by a Deployment or ReplicaSet. Until that second item lands, trace is the only command that follows a resource's children, and there is no way to say watch every Pod whose name starts with this prefix. If your question is about a set of objects rather than one object or one rollout, kubespy does not answer it.
The tool also inherits whatever your kubeconfig grants. Watching a resource requires list and watch permission on that resource in that namespace, and a cluster with an aggregated API server or a broken discovery endpoint will affect the discovery step the README describes. None of this is unusual for a client-side tool, but it means kubespy is a debugging instrument, not an observability system. It has no alerting, no aggregation across clusters, and no history.
kubespy compared with kubectl get --watch and kubectl describe
The closest alternative is already in your shell. kubectl get <resource> --watch streams whole objects, and kubectl describe renders a human-readable view of one object at a moment in time. The difference is what each one does with the stream. kubectl get --watch reprints the object on every change, so a busy resource produces a wall of near-identical text and you do the comparison in your head. kubespy computes a diff and shows only what moved, and trace goes further by collapsing a rollout's related objects into a single summary. That is the whole reason to install it.
The trade-off runs the other way too. kubectl is already present, already authenticated, and its output formats (jsonpath, custom-columns, go-template) compose with the rest of your shell. kubespy's output is designed for a human reading a terminal, which is why record exists as the escape hatch: it emits a JSON array, the one form in the command set that is meant to be consumed rather than watched. If you need to post-process the stream, start from record rather than parsing a rendered diff.
A second alternative is the Kubernetes event stream, which records why the control plane made a decision. kubespy shows you what the object looks like now, not why it got there. When a Pod is stuck, events usually explain it and kubespy usually does not. The two are complementary: watch the object with kubespy, read the events when the object stops changing and you still do not know why.
Maintenance, build requirements and the Apache-2.0 licence
The repository is not archived, and the last push was on 2026-09-23. That is recent, but release cadence tells a different story: v0.6.3 was published on 2024-04-09, v0.6.2 on 2023-04-25, and v0.6.1 on 2022-09-07. Roughly one release a year, and the most recent is well behind the last commit. If you install from a release binary rather than from source, you are getting the v0.6.3 build, not whatever landed on master since. That gap is worth knowing before you file a bug against a released binary.
The build is plain Go. The Makefile defines ensure (go mod tidy), build (go build), lint (golangci-lint run), install (go install) and test_all (go test with a one-hour timeout and parallelism of 10). The module declares go 1.26.6, which is newer than the Go 1.19 the README lists as the prerequisite for go install. Building from source therefore requires a toolchain matching the module directive, not the README's minimum. The dependency list is substantial and includes the Pulumi Kubernetes provider, client-go and apimachinery, plus a Bubble Tea stack pulled in indirectly. That is a large dependency surface for a CLI whose job is to watch and print, and it is the main cost of building from source rather than using a release binary.
The licence is Apache-2.0, the same permissive licence Kubernetes itself uses. For most users that means you can run it, modify it and redistribute it, provided you keep the licence and attribution notices intact. Apache-2.0 also includes an explicit patent grant, which matters if you vendor the code into a product. This is a description of the licence text, not legal advice; if you plan to redistribute a modified kubespy, read LICENSE and your own legal guidance.
Editorial conclusion
kubespy fits engineers who are debugging a single resource and want to see its .status field change second by second, and it is the wrong tool for anything that needs to run unattended or cover a whole cluster. Verify two things before adopting it: that your kubectl config points at the context you intend to watch, since the tool reads the cluster through the same client configuration, and that the resource you care about actually exposes the fields you want to watch, because status and changes only report what the API server stores. Start with kubespy trace deployment <name> against a resource you can safely restart.
Frequently asked questions
What is kubespy used for?
It observes how Kubernetes resources change in real time. Its four commands emit status changes, any-field changes, or an aggregated trace of a complex resource such as a Deployment, and it runs until you kill it.
How do I install kubespy?
The README lists Homebrew (brew install kubespy), a release binary you rename to kubespy and chmod +x, go install github.com/pulumi/kubespy@latest with Go 1.19 or later, and renaming the binary to kubectl-spy to invoke it as kubectl spy with kubectl v1.12.0 or later.
Does kubespy work with custom resources?
Yes. The README states that it uses the discovery client to discover available API resources and allows users to query any of them, including CRDs. That is why status, changes and record take an apiVersion and a kind.
What is the difference between kubespy status and kubespy trace?
status takes an apiVersion, kind and name and emits changes to the .status field as a JSON diff. trace takes only a kind and a name and aggregates the changes a complex resource makes throughout a cluster into a high-level summary updated in real time.
Can kubespy save its output to a file?
The README does not document a flag for writing to a file. It describes kubespy as watching and reporting until you kill it, and record is the command that emits changes as a JSON array rather than a rendered diff.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/pulumi-kubespy)