A top-like tool for containers that displays resource usage based on cgroup limits, not the host's resources.
Traditional monitoring tools like top or htop, when run inside a container, report resource usage as a percentage of the host machine's total resources. When working in containerized environments like Kubernetes Pods, it is hard to monitor the resource usage from inside the container.
For example, a container with a 2GB memory limit on a 128GB host may be using 1.8GB of RAM. While htop would show a negligible system-wide usage, the container is actually at 90% of its capacity and is dangerously close to being OOMKilled with no warning.
topic (top inside a container) is a simple terminal-based monitoring tool that solves this problem. It reads the container's resource limits directly from the cgroup filesystem and calculates all usage percentages based on those limits.
This provides an accurate view of how close a container is to its resource boundaries, without the need to access the host or external monitoring tools.
The screenshot is captured inside a demo container limited to 2 CPUs, 2 GiB of memory, and 256 PIDs, with a synthetic CUDA workload using an attached GPU.
The system panel adapts to the terminal width. Wide terminals use two aligned resource columns; narrower terminals switch to one column and truncate secondary details before hiding primary measurements.
- CPU, memory, storage, and GPU rows share the same label, percentage, bar, and detail alignment.
- Network and disk throughput, PID usage, cgroup pressure, and metric history use a shared label gutter for quick scanning.
- Utilization is green below 70%, gold from 70% to 89.9%, and red at 90% or above.
- Docker, Kubernetes, and NVIDIA/NVML availability is shown in the compact status panel. Missing integrations remain non-fatal.
You can install the latest version of topic with a single command. The script will automatically detect your system's architecture (amd64/arm64) and install the binary to a directory in your PATH.
curl -s https://raw.githubusercontent.com/yurirocha15/topic/master/install.sh | bashor for containers based on alpine:
wget -qO- https://raw.githubusercontent.com/yurirocha15/topic/master/install.sh | shThe script will attempt to install to /usr/local/bin (prompting for sudo if needed). If that fails, it will fall back to $HOME/.local/bin and notify you if you need to add this directory to your PATH.
After installation, simply run the command:
topicCommon options:
topic --refresh=2s # change refresh interval
topic --no-gpu # disable GPU collection
topic --no-docker # disable Docker metadata lookup
topic --no-kubernetes # disable Kubernetes metadata lookup
topic --no-nvml # disable NVML/NVIDIA integration status
topic --ascii # start with the large ASCII logo visible
topic --once # print one text snapshot and exit
topic --once --json # print one JSON snapshot for scripts
topic --sort=mem # initial sort: cpu, mem, gpu, gpumem, pid, user, command- Quit:
qorCtrl+C - Navigate: Use the arrow keys (
←,↑,→,↓) or mouse to scroll through the process list. - Filter mode:
/to enter, type to filter,Ctrl+Uto clear,Escto leave. - Sort mode:
sto enter,←/→to choose a column,↑/↓to choose direction,Escto leave. - Process details:
Enter - Signal process:
k - Pause refresh:
p - Tree view:
t - Toggle logo:
a - Help:
?
If you prefer to build the project yourself, you will need:
- Go (version 1.23 or later)
make
Clone the repository and run the build command:
git clone https://github.com/yurirocha15/topic.git
cd topic
make buildThe compiled binary will be available at ./dist/topic.
Run the standard validation gates from the repository root:
make test
make lint
make buildRace detection and benchmarks run directly from the Go module:
cd pkg
go test -race ./...
go test -bench=. -benchmem -count=5 ./...The test suite includes simulated TUI renders at compact, medium, and wide terminal sizes, plus input-flow coverage for filtering, sorting, process details, and clean shutdown.
The normal test suite uses fake Docker, Kubernetes, and NVML providers so it does not require host services:
make test-integrationsThis target also runs scripts/smoke-integration.sh, which executes topic --once --json and validates that Docker, Kubernetes, and NVML integration statuses are present in the JSON snapshot.
To validate that integrations work inside real environments, use the opt-in E2E targets:
make e2e-docker
make e2e-kubernetes
make e2e-integrations # runs bothmake e2e-docker requires Docker and /var/run/docker.sock. It builds a local image, runs topic --once --json inside Docker with the Docker socket mounted, and asserts Docker metadata is actually available.
make e2e-kubernetes requires kubectl connected to a cluster. By default it builds a local Docker image named topic:e2e-kubernetes; if your cluster cannot see local Docker images, publish an image yourself and run:
TOPIC_KUBE_E2E_BUILD_IMAGE=0 TOPIC_KUBE_E2E_IMAGE=registry.example.com/topic:e2e make e2e-kubernetesFor kind clusters, the script automatically loads the local image when the current context starts with kind-.
For k3s clusters, the script can import the local image only when it is run as root or passwordless sudo is available. Otherwise, publish the image to a registry or manually import it into k3s/containerd before running the target.
For single-node local clusters where the Kubernetes node can access this checkout path, you can avoid image publishing by mounting the built binary into a stock Alpine pod:
TOPIC_KUBE_E2E_USE_HOSTPATH=1 make e2e-kubernetesLive integration discovery is opt-in:
TOPIC_LIVE_INTEGRATION_TESTS=1 make test-integrationsLive tests assert that discovery returns well-formed statuses without hanging or crashing. They do not require every integration to be available; unavailable Docker, Kubernetes, or NVIDIA/NVML environments are valid results. Use the E2E targets above when you need to prove an integration is available and returning correct metadata in its native environment.
Contributions are welcome! If you find a bug or have a feature request, please open an issue on the GitHub Issues page.
This project is licensed under the MIT License.

