Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ All paths below are relative to `internal/dashboard/` unless stated otherwise.
| Logs | `logs.go`, `log_*.go` |
| Reviewed actions and commands | `authorization.go`, `operations.go`, `commands.go`, `sudo.go` |
| Settings and themes | `settings.go`, `preferences.go`, `themes.go`, `style.go`, `icons.go` |
| Prometheus and the Metrics suite | `metrics_*.go`, `prometheus*.go`, `internal/promapi/` (repository root) |
| SSH | `remote.go`, `internal/remote/` (repository root) |

Read related `*_test.go` files as needed. `helpers_test.go` contains adapters
Expand All @@ -37,7 +38,7 @@ check both implementations when changing shared contracts.

The extracted packages do not import `dashboard`, tview or tcell. Keep that
boundary: collection and parsing belong outside the UI. Their tests run with
`go test ./internal/hostnet ./internal/dockerinspect ./internal/commandcapture`;
`go test ./internal/hostnet ./internal/dockerinspect ./internal/commandcapture ./internal/promapi`;
they do not require loading dashboard fixtures or starting terminal screens.

## Documentation and assets
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ Changes are recorded here before being assigned a release tag.

## Unreleased

## v0.4.0 - 2026-10-27

A Metrics suite: Prometheus trend panels, targets, pinned metrics and exporter setup from inside the terminal.

### Added

- A sixth suite, **6 · Metrics**, visualises a Prometheus server: built-in trend panels for node_exporter, cAdvisor (standalone or kubelet), Proxmox VE (`prometheus-pve-exporter`) and Prometheus itself, drawn with the shared block/braille/ASCII renderers plus a bar variant, each with an axis naming the window's peak, pressure colours only for values that have a ceiling and gaps for missing samples, and a full-screen view per panel that flicks between panels with the arrow keys; a targets view with scrape state, errors, server version and configuration reload status; pinned metrics chosen from the server's metric names and saved in settings; a host chooser for multi-instance servers; and a setup view that detects the package manager, Docker and Proxmox and offers install steps through the usual approval card, with `sudo` steps authorised like other actions. The server is named with `--prometheus`, `SYSTEMDOC_PROMETHEUS` or `prometheus_url`, or detected from a running Prometheus service or container; **Open in Metrics** appears in the Actions menu for Prometheus and exporter workloads. A bearer token from `SYSTEMDOC_PROMETHEUS_TOKEN` is never stored. The client lives in `internal/promapi` with bounded requests, no redirects and system TLS roots only.

## v0.3.0 - 2026-10-26

Live GPU telemetry and per-process GPU readings, CPU core inspection, and independently testable backend collectors.
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ systemdoc --docker # Docker containers
systemdoc --filter state:failed # focus on failures
```

## Five feature suites
## Six feature suites

![Containers suite showing a single-node k0s stack with a crash-looping pod selected](docs/assets/containers.png)

*The Containers suite with a k0s stack: Docker containers and Kubernetes pods in one list, the Attention filter on, and a crash-looping pod's overview with its events.*

Press `0` anywhere in the live workspace to open the **Control Deck**. It explains and opens the five numbered suites, so a first-time user can understand the product without memorising commands.
Press `0` anywhere in the live workspace to open the **Control Deck**. It explains and opens the six numbered suites, so a first-time user can understand the product without memorising commands.

| Suite | What it is for | Rich workflows |
| --- | --- | --- |
Expand All @@ -72,7 +72,7 @@ The suites share one visual language, polling interval, keyboard model, theme sy

| Key | Use it for |
| --- | --- |
| `0` | Open the five-suite Control Deck |
| `0` | Open the six-suite Control Deck |
| `1` / `2` | Services / containers |
| `3` | Ports and networking |
| `4` | Process Explorer |
Expand Down
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Run Systemdoc as a regular user. Native systemd, journal, Docker, and SSH permis

Settings and exports use owner-only permissions. Project definitions contain source paths; those sources, command arguments, labels, inspect JSON, and logs can contain secrets. The Docker overview omits environment values, but it is not a general-purpose redaction layer. Review exports and AI context before sharing.

AI assistance sends the text you review to an external CLI/provider. Authentication belongs to that CLI. SSH uses native host-key and authentication handling; only public keys are installed by key setup. Temporary uploads are private and cleaned up on exit when the connection permits.
The Metrics suite sends PromQL queries to the configured Prometheus server; a bearer token lives only in `SYSTEMDOC_PROMETHEUS_TOKEN`, is sent as a header, never stored and never printed. Credentials inside the URL are rejected. AI assistance sends the text you review to an external CLI/provider. Authentication belongs to that CLI. SSH uses native host-key and authentication handling; only public keys are installed by key setup. Temporary uploads are private and cleaned up on exit when the connection permits.

## Downloads

Expand Down
5 changes: 4 additions & 1 deletion SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ A Linux and macOS terminal workspace with two modes: native services (systemd on
| Kubernetes | Detected kubectl invocation (`kubectl`, `k0s kubectl`, `k3s kubectl`, `microk8s kubectl`, kind contexts, or `--kubectl`/`SYSTEMDOC_KUBECTL`); node list names the distribution; `get pods -A -o json`, `top pods`, pod JSON/YAML, events, Services, prefixed multi-container logs; `rollout restart` and `delete pod` as reviewed actions |
| Host GPU | NVIDIA/DRM device telemetry with bounded per-device history; NVIDIA pmon and DRM fdinfo process usage/memory |
| Host network | TCP/UDP socket ownership, interfaces, and successive-counter download/upload rates from `/proc/net/dev` or `netstat -ibn` |
| Prometheus | `internal/promapi` HTTP client with bounded bodies and timeouts, no redirects, bearer header only; exporter panel catalog (node_exporter, cAdvisor, kubelet, Proxmox VE, Prometheus) with placeholder PromQL; install-step data per platform; dashboard discovery from inventory, probe back-off, `query_range` per poll |
| Compose | Installed `docker compose`; project files, profiles, environment files, workdir, endpoint |
| Settings | JSON under XDG config, owner-only atomic saves |
| Operations | Exact-target review, cancellable subprocesses, bounded output, session history |
Expand All @@ -34,7 +35,9 @@ Versions are pinned in [go.mod](go.mod). Release binaries use `CGO_ENABLED=0` fo
action review. It calls `internal/hostnet` for network collection, parsing,
filtering and rate calculation, and `internal/dockerinspect` for readable
container inspection output. `internal/hostgpu` owns GPU device and process
collection, parsing and interval calculation. These packages own their component tests and
collection, parsing and interval calculation. `internal/promapi` owns the
Prometheus HTTP client, response decoding, the exporter panel catalog and the
install-step data. These packages own their component tests and
have no dependency on dashboard state, tview or tcell. Dashboard tests cover
their integration with the UI.

Expand Down
9 changes: 8 additions & 1 deletion cmd/systemdoc/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func main() {
showVersion := flag.Bool("version", false, "Print version")
dockerContext := flag.String("docker-context", "", "Pin Docker context for this session")
kubectl := flag.String("kubectl", "", "kubectl invocation for the Containers suite (for example \"k0s kubectl\" or \"kubectl --context kind-dev\"); detected when omitted")
prometheus := flag.String("prometheus", "", "Prometheus server URL for the Metrics suite (for example http://localhost:9090); detected from local services and containers when omitted. A bearer token is read from SYSTEMDOC_PROMETHEUS_TOKEN")
host := flag.String("ssh", "", "Run the suite on an SSH host or user@host")
setupKey := flag.Bool("setup-ssh-key", false, "Install a public SSH key with ssh-copy-id before connecting")
sshUser := flag.String("ssh-user", "", "SSH login username (default: SSH configuration)")
Expand Down Expand Up @@ -61,6 +62,12 @@ func main() {
if *kubectl != "" {
args = append(args, "--kubectl", *kubectl)
}
if *prometheus == "" {
*prometheus = os.Getenv("SYSTEMDOC_PROMETHEUS")
}
if *prometheus != "" {
args = append(args, "--prometheus", *prometheus)
}
options := remote.Options{Host: *host, User: *sshUser, Port: *port, Identity: *identity, Binary: *remoteBin, Upload: *upload, UploadBinary: *uploadBinary, Args: args}
if *setupKey {
if options.Identity == "" {
Expand Down Expand Up @@ -98,7 +105,7 @@ func main() {
if *dockerContext != "" {
os.Setenv("DOCKER_CONTEXT", *dockerContext)
}
if err := dashboard.Run(dashboard.Options{User: *user, Docker: *docker, Filter: *filter, ActiveOnly: *activeOnly, Kubectl: *kubectl}); err != nil {
if err := dashboard.Run(dashboard.Options{User: *user, Docker: *docker, Filter: *filter, ActiveOnly: *activeOnly, Kubectl: *kubectl, Prometheus: *prometheus}); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
Expand Down
3 changes: 2 additions & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ Start with [installation](installation.md), then the [user guide](usage.md).
| Guide | What it covers |
| --- | --- |
| [Installation](installation.md) | Requirements, download, update, uninstall, source builds |
| [User guide](usage.md) | The five feature suites, keyboard controls, logs, management, Compose, AI |
| [User guide](usage.md) | The six feature suites, keyboard controls, logs, management, Compose, AI |
| [Configuration](configuration.md) | Settings storage, preferences, theme migration |
| [macOS services](macos.md) | Launchd support, builds and validation limits |
| [Ports and networking](networking.md) | Host sockets, port owners, connections and interfaces |
| [Process Explorer and Storage](host-panels.md) | Process trees, resource sorting, mounts, inodes and deleted open files |
| [Metrics suite](prometheus.md) | Prometheus trend panels for node_exporter, cAdvisor and Proxmox VE, scrape targets, pinned metrics and guided setup |
| [Themes](../THEMES.md) | Five gothic Observatory palettes and the shared Nerd Font vocabulary |
| [SSH and remote hosts](remote.md) | Remote runs, key setup, static binary upload |
| [Troubleshooting](troubleshooting.md) | Common failures and known limits |
Expand Down
8 changes: 7 additions & 1 deletion docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,20 @@ A minimal settings file is:
"splash": true,
"wrap_logs": false,
"nerd_icons": true,
"systemd_active_only": false
"systemd_active_only": false,
"prometheus_url": "http://localhost:9090",
"prometheus_metrics": [
{"title": "Open files", "name": "process_open_fds", "selector": "{job=\"prometheus\"}", "unit": "count"}
]
}
```

Missing settings use defaults. Unknown theme names resolve to Cathedral; legacy Deep names resolve to the nearest Observatory palette. Invalid refresh intervals resolve to five seconds. `graph_mode` accepts `blocks`, `braille`, or `ascii`; invalid values fall back to blocks. Press `G` to cycle it without opening Preferences. Five [Observatory themes](../THEMES.md) are supplied. `accent` and `background` accept `#RRGGBB` strings; blank values restore preset colours. Existing overrides survive theme migration. `nerd_icons` defaults to `true`; the first Observatory-era read promotes the former off-by-default value once, after which setting it to `false` under Preferences is retained as the labeled Unicode/ASCII fallback.

`SYSTEMDOC_KUBECTL` (or `--kubectl`) pins the kubectl invocation used for Kubernetes pods in the Containers suite, for example `k0s kubectl` or `kubectl --context kind-dev`; leave it unset to detect the stack automatically.

`--prometheus URL` (or `SYSTEMDOC_PROMETHEUS`) names the Prometheus server for the Metrics suite and overrides `prometheus_url` in settings; with neither, a running Prometheus service or container is detected, and failing that `http://localhost:9090` is tried. An optional bearer token is read from `SYSTEMDOC_PROMETHEUS_TOKEN`; it is never written to settings and is not forwarded over SSH. The flag and environment value are forwarded to a remote host, where they name that host's own loopback; the settings value is not, because the remote user has their own settings. `prometheus_metrics` holds pinned panels (`title`, `name`, optional `selector`, `unit`, `rate`, `ceiling`) and `prometheus_instances` remembers which scraped host each exporter family shows. See [the Metrics suite](prometheus.md).

`i` toggles active-only filtering and saves the systemd choice. Docker's filter is session-local. `--active-only` enables it at startup. Favourites and registered Compose project definitions are also saved. Configure projects through the project menu so file ordering, working directory, profiles, environment files, and Docker endpoint are explicit.

Saved views (`saved_views`) are managed with **V** or the visible **Views** button. Each named entry stores mode, service manager, system/user scope, filters, sort, favourites-only, layout, pane ratio, inspector tab, drawer visibility and, for Docker, the endpoint. Opening a view restores these session choices; log buffers and backend data are not persisted. Invalid view fields are rejected when opening, and Docker endpoint mismatches do not switch the target.
Expand Down
3 changes: 2 additions & 1 deletion docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ python3 scripts/render-preview.py /tmp/systemdoc-cells.json 120x30 /tmp/systemdo

For documentation images, capture the real binary instead of fixtures: `make build && scripts/capture-panels.sh` drives `bin/systemdoc` inside a detached 160×44 tmux server with 24-bit colour, walks every panel (dashboard, containers with pods, Docker overview, pod connections, processes, Process Activity, sysdig palette and stream, network speed, storage, constellation, Control Deck), converts each `tmux capture-pane -e` dump with `scripts/ansi-to-cells.py` into the same cell JSON, and renders PNGs into `docs/assets/` through `render-preview.py` and `rsvg-convert`. Run it with the k0s playground up (`playground/k0s.sh up`) so the container captures show a stack. It needs tmux, python3, rsvg-convert and JetBrainsMono Nerd Font.

Set `SYSTEMDOC_VISUAL_MODE=docker` for the container fixture or `approval` for the action card. The exporter includes 160×44, 120×30, and 80×24 frames. Python's standard library is sufficient to write the SVG. JetBrainsMono Nerd Font is required to review glyph spacing accurately. For README PNGs, convert the SVG with `rsvg-convert` from librsvg; this is a documentation-only dependency.
Set `SYSTEMDOC_VISUAL_MODE=docker` for the container fixture, `approval` for the action card, or `metrics` and `metrics-setup` for the Metrics suite. The exporter includes 160×44, 120×30, and 80×24 frames. Python's standard library is sufficient to write the SVG. JetBrainsMono Nerd Font is required to review glyph spacing accurately. For README PNGs, convert the SVG with `rsvg-convert` from librsvg; this is a documentation-only dependency.

Review all themes and both modes. Screenshots published in documentation must say that workloads and measurements are fixtures. Never include credentials or real sensitive host configuration.

Expand All @@ -40,6 +40,7 @@ Review all themes and both modes. Screenshots published in documentation must sa
- `cmd/systemdoc`: flags, version, local/remote dispatch.
- `internal/dashboard`: UI, systemd/launchd/Docker backends, workflows, state, themes.
- `internal/hostnet`: socket collection/parsing, interface counters, rates and filters; no UI dependencies.
- `internal/promapi`: Prometheus HTTP client, exporter panel catalog, install steps; no UI dependencies.
- `internal/dockerinspect`: readable Docker inspection output and its JSON fixture; no UI dependencies.
- `internal/commandcapture`: bounded structured command output, separate diagnostics and cancellation.
- `internal/textutil`: shared plain-text sanitization and formatting.
Expand Down
Loading
Loading