- Go 56.8%
- Nix 43.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| blocks | ||
| schemas | ||
| .gitignore | ||
| flake.lock | ||
| flake.nix | ||
| go.mod | ||
| go.sum | ||
| main.go | ||
| README.md | ||
sis
system information snapshot — a tiny Go CLI that samples the machine
once, prints one JSON object, and exits. Meant to be polled by a status bar
(Waybar, i3status-rust, eww, tmux, …) or piped into jq.
$ sis
{
"cpu": {
"model": "AMD Ryzen 7 9700X 8-Core Processor",
"cores": 8,
"threads": 8,
"frequency": "5787 Mhz",
"temperature": "",
"usage": "3%"
},
"ram": {
"total": "30.5 GB",
"used": "11.5 GB"
},
"disk": {
"devices": [
{ "name": "/", "mountpoint": "/", "size": "899.6 GB", "used": "664.5 GB", "free": "189.3 GB", "fs": "ext2/ext3" }
]
},
"net": {
"devices": [
{ "name": "eth0", "mac_address": "aa:bb:cc:dd:ee:ff", "ip_address": "192.168.1.20/24" }
]
},
"clock": { "time": "2026-08-25 17:10:19", "timezone": "" },
"volume": { "level": "100%", "mute": false }
}
There is no loop, no daemon, no config file, and no flags. One invocation is one sample.
Blocks
Each field of the output comes from one "block" in blocks/; the
shapes are declared in schemas/types.go.
| Block | Source | Notes |
|---|---|---|
cpu |
gopsutil cpu |
model, core/thread counts, MHz, instantaneous usage |
ram |
gopsutil mem |
total and used, human-formatted |
disk |
gopsutil disk |
every physical partition, size/used/free/fstype |
net |
gopsutil net |
interface name, MAC, first address (N/A when unset) |
clock |
stdlib time |
local wall clock |
volume |
wpctl get-volume (WirePlumber) |
percentage and mute state; "unknown" if wpctl is missing |
Known gaps in the current implementation, so the empty strings aren't a
surprise: cpu.temperature and clock.timezone are declared in the schema but
never populated. disk reports whatever gopsutil considers a physical
partition, which on NixOS includes bind mounts like /nix/store — filter with
jq if you only want real mounts.
Requirements
- Linux for the
volumeblock (wpctl, from WirePlumber). Everything else is cross-platform via gopsutil; on non-Linux the volume block degrades to{"level": "unknown", "mute": false}rather than failing. - Go 1.24+ if you build outside Nix.
Nix
The flake exposes a package, a runnable app, a dev shell, an overlay, checks and
a formatter for x86_64-linux, aarch64-linux, x86_64-darwin and
aarch64-darwin.
Run without installing
nix run git+https://git.cumsek.com/Marti/sis # or: nix run . inside a checkout
Build
nix build # -> ./result/bin/sis
nix build .#sis # same thing, explicit attribute
The Linux build is wrapped with makeWrapper so wpctl is on PATH at
runtime; the binary works even where WirePlumber isn't in the ambient
environment. src is narrowed with lib.fileset to go.mod, go.sum,
main.go, blocks/ and schemas/, so touching this README or the flake does
not trigger a rebuild.
Dev shell
nix develop
Gives you Go, gopls, gotools (goimports), go-tools (staticcheck),
golangci-lint, delve, jq, and wireplumber for wpctl. CGO_ENABLED=0
is set, matching how the package is built. Then the usual loop:
go run .
go run . | jq .cpu
go build -o sis .
With direnv, echo 'use flake' > .envrc && direnv allow
enters the shell automatically.
Checks
nix flake check
Runs two checks: package builds the binary, and vet runs go vet ./... plus
a gofmt cleanliness test over main.go, blocks/ and schemas/.
Use it from another flake
As an input plus overlay:
{
inputs.sis.url = "git+https://git.cumsek.com/Marti/sis";
# NixOS / home-manager module
outputs = { nixpkgs, sis, ... }: {
# …
nixpkgs.overlays = [ sis.overlays.default ];
environment.systemPackages = [ pkgs.sis ]; # or home.packages
};
}
Or reference the package directly, without the overlay:
environment.systemPackages = [ sis.packages.${pkgs.system}.default ];
To bump the pinned nixpkgs: nix flake update. If you change go.mod or
go.sum, vendorHash in flake.nix has to be refreshed —
build once, and Nix prints the hash it expected versus the one it got.
Example: Waybar
"custom/sis": {
"exec": "sis",
"return-type": "json",
"interval": 5,
"format": "{}"
}
Waybar wants its own text/tooltip keys, so in practice pipe through jq to
reshape:
"exec": "sis | jq -c '{text: (.cpu.usage + \" \" + .ram.used), tooltip: .cpu.model}'"
Layout
main.go assembles one schemas.Output and prints it
blocks/ one file per block, plus utils.go (byte formatting)
schemas/types.go output structs and their JSON tags
flake.nix the buildGoModule derivation plus devshell, app, overlay,
checks and formatter
License
MIT.