This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
go run .— run the TUI from the repository root.go install ./cmd/nnmon— install thennmonCLI entrypoint.go build ./...— compile all packages.go build ./cmd/nnmon— compile just the installable CLI entrypoint.go test ./...— run the full test suite.go test ./internal/app ./internal/metrics— run the most frequently touched package tests while iterating on UI or sampling changes.go test ./internal/app -run TestProcessSearchInputUpdatesQuery— run a single test by name; swap in the target package and test name as needed.go fmt ./...— apply the repo’s standard formatting.go vet ./...— lightweight static analysis; there is no dedicated repo lint config checked in.go mod tidy— only when dependencies change.
main.goandcmd/nnmon/main.goboth do the same thing: createapp.New(), run it through Bubble Tea, and use the alternate screen.- Almost all product logic lives under
internal/.
- The app uses a single Bubble Tea model, defined in
internal/app/state.go. Modelowns terminal dimensions, active view, process/network/storage sub-state, the latestmetrics.Snapshot, the shared history store, and thecontrol.Executor.internal/app/update.gois the main event loop. It handles:- terminal resize
- periodic polling
- manual refresh
- keyboard routing
- metric collection results
- action execution results
internal/app/layout.gois the top-level renderer. It decides between the normal screen, the help modal, the action modal, and the “terminal too small” fallback.
internal/metrics/snapshot.godefines the shared data contract between collectors and UI.- UI code should treat
metrics.Snapshotas the canonical read model for the current screen. internal/metrics/service.godoes not collect everything on every UI tick. It uses scheduled lanes:- fast lane every
750ms: CPU, memory, network - medium lane every
3s: processes - slow lane every
15s: host and disk
- fast lane every
CollectModeFullbypasses those intervals for manual refreshes.SampleCachestores lane timestamps and previous network totals so incremental refreshes can compute rates without reinitializing state.
internal/app/history.gokeeps fixed-length series (default32points).- After each successful collection,
internal/app/update.goonly pushes series for the metric groups that were actually refreshed. - Reuse this history store for sparklines or short trend views instead of introducing separate history caches.
internal/metrics/collectors_process.gogathers process data with gopsutil, filters out unusable entries, sorts by RSS, and caps the sample size.- Network rate calculation depends on cached previous totals, so changes to network collection should preserve cache semantics.
- Disk and process collectors already perform ranking/trimming; the UI mostly renders curated snapshot data instead of re-collecting or re-normalizing it.
- Process-management actions are defined via the action catalog in
internal/control/catalog.go. - The UI never sends OS signals directly; it opens an action palette and executes through the
control.Executorinterface. control.DefaultExecutor()currently returnsLocalProcessExecutor.- On
darwinandlinux,internal/control/local_process_unix.gomaps actions to real Unix signals. - On unsupported platforms,
local_process_unsupported.gokeeps the feature present but non-functional with clear status messages. - New management actions should follow the same pattern: catalog entry, capability gating, confirm behavior for dangerous actions, then executor support.
- Keep package boundaries strict:
internal/appfor Bubble Tea state, layout, input handling, and renderinginternal/metricsfor sampling, snapshot shaping, and metric formattinginternal/controlfor OS-facing management actions and executor logic
- This is a single-model Bubble Tea app. Prefer extending
app.Modeland its sub-state over introducing global state or parallel controller layers. - If a new metric is expensive to collect, assign it to the appropriate sampling lane instead of attaching it to every
750mstick. - Tests live next to the code they cover. The main coverage areas today are:
internal/app: layout, keyboard behavior, action palette behavior, filtering/search flowsinternal/metrics: scheduled collection behaviorinternal/control: capability and executor behavior
viewStorageand storage rendering/tests exist, but the storage page is not currently wired into the main navigation.- The active navigation path only exposes overview, processes, and network.
- If you re-enable or add a view, update all of these together:
orderedViewsininternal/app/state.go- keyboard shortcuts in
internal/app/input.go renderActiveViewand help/footer copy ininternal/app/layout.go- any affected tests in
internal/app/model_test.go
- Use standard Go naming and formatting conventions.
- Prefer feature-oriented filenames like
view_processes.goandcollectors_network.go. - Recent commit messages use short imperative subjects such as
Refine process view layout and samplingandAdd installable nnmon CLI entrypoint.