No description
  • Go 56.8%
  • Nix 43.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-08-25 17:18:02 +02:00
blocks create 2025-08-07 20:31:03 +02:00
schemas create 2025-08-07 20:31:03 +02:00
.gitignore Add nix flake with devshell, package and README 2026-08-25 17:16:29 +02:00
flake.lock Add nix flake with devshell, package and README 2026-08-25 17:16:29 +02:00
flake.nix Add nix flake with devshell, package and README 2026-08-25 17:16:29 +02:00
go.mod create 2025-08-07 20:31:03 +02:00
go.sum create 2025-08-07 20:31:03 +02:00
main.go create 2025-08-07 20:31:03 +02:00
README.md wrong url 2026-08-25 17:18:02 +02:00

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 volume block (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.