Skip to main content

pinghue - colored concurrent ICMP/TCP ping monitor for maintenance windows

PyPI Python versions CI Homebrew tap License

Website · Install · Quick Start · Modes · CLI Reference · JSON Output · Security

pinghue is a colored, concurrent ICMP/TCP ping monitor for maintenance windows. It gives operators a dense terminal view for many hosts at once and can also write structured JSON for reports, cron jobs, and CI checks.

Current version: 5.0.0. The command-line interface and JSON output are stable public interfaces. JSON output uses schema_version: 1; breaking JSON changes require a new schema version.

real pinghue terminal recording: healthy hosts with green history bars, a TCP-refused host with amber markers, and unreachable hosts down in red

Why pinghue

Dense at-a-glance view

Watch many hosts in one readable terminal table — per-host latency, loss, jitter, and a live history bar.
ICMP & TCP

Default ICMP, or TCP connect checks with -p. Up to 1024 concurrent probes.
Evidence-ready JSON

--output writes a stable schema_version 1 summary for reports, cron, and CI.
Whole-run accuracy

Host states reflect everything that happened in the window, not just the most recent probes.
Scriptable

--no-tui, --count, --duration, and fail-on-down exit codes for automation.
Local & safe

No server, no daemon, no credentials. Runs on macOS and Linux, Python 3.10–3.13.

Install

Recommended isolated installs from PyPI:

uv tool install pinghue

or:

pipx install pinghue

Plain pip also works inside a virtual environment:

python -m pip install pinghue

Homebrew is available through the inxbit/tap tap:

brew install inxbit/tap/pinghue

The tap repository is inxbit/homebrew-tap; Homebrew exposes it as inxbit/tap.

For contributors, install from a local clone in editable mode:

git clone https://github.com/inxbit/pinghue.git
cd pinghue
python -m venv .venv
. .venv/bin/activate
python -m pip install -e ".[dev]"

The dev extra installs the local package plus the test, type-checking, linting, build, and schema-validation tools used by the repository.

Quick Start

pinghue 1.1.1.1 8.8.8.8 example.com
pinghue -f hosts.txt
pinghue -p 443 example.com
pinghue -p 1 127.0.0.1 -c 1 --no-tui
pinghue --output maintenance.json 1.1.1.1 example.com
pinghue --output maintenance.json --overwrite 1.1.1.1 example.com
pinghue --host-label maintenance-window --output maintenance.json 1.1.1.1

Host files are plain text. Blank lines and # comments are ignored. Inline comments on host lines are also ignored (host.example # comment). Host files must be non-symlink regular files, at most 1 MiB, and at most 5,000 lines. A run accepts at most 5,000 unique targets in total, and each target string is capped at 253 characters.

# edge and core checks
1.1.1.1
8.8.8.8
example.com
internal-db.corp

real pinghue screenshot: a dense maintenance-window table monitoring sixteen hosts with addresses, latency columns, loss, per-host history bars, a legend, and footer keybindings

What This Is

  • A focused terminal monitor for maintenance windows, migrations, and quick reachability checks.
  • A concurrent ICMP/TCP probe runner with a readable Textual TUI.
  • A scriptable probe tool with --no-tui, --count, --duration, and --output.
  • A JSON-producing report helper for post-maintenance evidence.
  • A local operator tool designed for macOS and Linux.

What This Is Not

  • Not a Prometheus, Smokeping, Zabbix, or NMS replacement.
  • Not a long-running metrics database or alerting system.
  • Not a privileged daemon.
  • Not a packet capture or traceroute tool.
  • Not a service that accepts remote network requests.

Supported Platforms

The supported platform contract is macOS and Linux on Python 3.10 through 3.13. CI runs on both macOS and Linux for every supported Python version.

The TUI assumes an ANSI-capable terminal with Unicode glyph support. Windows and other POSIX platforms are outside the declared support scope unless explicitly added later.

Stability Policy

pinghue treats CLI flags and JSON exports as compatibility contracts. schema_version: 1 is the JSON v1 contract: additive fields are non-breaking, but removing fields, changing field types, changing enum values, or changing required-field behavior requires a new schema version.

CLI removals, flag renames, and incompatible behavior changes are deprecated for at least one minor release before removal. Deprecated flags continue to parse during that window and release notes identify the replacement. Patch releases do not intentionally break CLI or JSON consumers.

A narrowly scoped safety or security limit may be enforced without that deprecation window when preserving the old behavior would leave a material resource-exhaustion or integrity risk. The exception must be identified in the release notes and, when it changes accepted CLI behavior, ships only in a major release.

Starting with 1.0.0, release versions follow semantic versioning: patch releases are bug fixes, minor releases may add compatible behavior, and major releases are reserved for breaking CLI or JSON changes.

2.0.0 changes the default --output behavior: existing regular files are preserved unless --overwrite is passed. Scripts that intentionally reuse the same JSON path should add --overwrite.

Modes

pinghue defaults to ICMP mode:

pinghue 1.1.1.1 example.com

TCP mode is enabled by passing a port:

pinghue -p 443 example.com api.internal

Use no-TUI mode for scripts, cron, CI, and package smoke tests:

pinghue -p 443 example.com -c 3 --no-tui

Example no-TUI output:

2026-05-14T18:32:11.420000+00:00 1.1.1.1 ok latency=9.20ms
2026-05-14T18:32:11.421000+00:00 example.com ok latency=14.08ms
2026-05-14T18:32:12.420000+00:00 api.internal timeout latency=-

CLI Reference

pinghue [OPTIONS] [TARGET ...]
Option Default Description
TARGET ... none Hostnames or IP addresses to probe, up to 253 characters each. Required unless --check is used.
-f, --file PATH none Read targets from a non-symlink plain-text host file. Blank lines and full-line/inline # comments are ignored.
-p, --port PORT ICMP Enable TCP connect checks against PORT. Valid range: 1-65535.
--ipv4 off Force IPv4 resolution/probing.
--ipv6 off Force IPv6 resolution/probing.
-n, --numeric off Skip DNS and require IP literals.
-i, --interval SEC 1.0 Seconds between probes. Minimum: 0.1.
--timeout SEC interval Per-probe timeout in seconds. Must be greater than 0.
-c, --count N continuous Stop after N probes per target. Intentionally has no upper bound.
--duration SEC continuous Stop after elapsed seconds. Intentionally has no upper bound.
--no-tui off Print one line per probe instead of launching the TUI.
--output PATH none Write a JSON run summary on exit. - writes to stdout, requires --no-tui, and moves per-probe lines to stderr so stdout carries only the JSON document. Existing regular files are not replaced unless --overwrite is set.
--overwrite off Allow --output to rewrite an existing single-link regular file in place. The rewrite is type-safe but not crash-atomic.
--output-mode {private,umask} private Permissions for the --output file: private (0600, owner only) or umask (honor the process umask).
--no-samples off Emit empty per-target samples arrays in JSON output.
--concurrency N 64 Maximum concurrent probes, 1-1024; ICMP daemon workers are bounded by this limit.
--jitter-threshold MS 50.0 Mark jitter as attention-worthy above this RFC 3550 interarrival jitter, in milliseconds.
--fail-threshold COUNT 3 Classify a previously responsive host as down after this many consecutive failures; all-failure runs are down immediately.
--fail-on-any-down off Exit 3 when any target finishes down.
--fail-on-all-down off Exit 3 only when all targets finish down. --fail-on-down remains a compatibility alias.
--history-style STYLE bar One of bar, dots, sparkline, or none.
--check off Run the environment doctor and exit.
--resolve-name HOST example.com With --check, resolve this host for DNS diagnostics, up to 253 characters. Defaults to the first target when provided.
--quiet off With --check, suppress output and use only the exit code.
--host-label LABEL local Operator-controlled host label written to JSON output, up to 128 characters.
-v, --version none Print the installed version.
-h, --help none Print help.

Exit codes

Code Meaning
0 Run completed (and no --fail-on-* condition triggered). In --no-tui mode, interrupting a run with Ctrl-C still evaluates the fail conditions, matching classic ping behavior; the JSON exit_reason field records interrupted. In the TUI, use q, which records user_quit.
1 Runtime error (for example the --output file could not be written), or --check found the environment not ICMP-ready.
2 Usage error: unknown flag or invalid value.
3 --fail-on-any-down / --fail-on-all-down condition triggered.

TUI Controls

Key Action
q Quit.
a Show or hide resolved addresses.
r Reset the selected host.
R Reset all hosts.
b Probe the selected host immediately.
B Probe all hosts immediately.

History Legend

The default history style is a fixed-scale colored bar:

  • Green bar: successful probe.
  • Amber bar: successful probe above the slow-latency threshold.
  • Red . / ·: timeout, loss, or down state.
  • Amber !: TCP refused.

Successful latency uses ▁▂▃▄▅▆▇█.

The fixed mapping keeps rows comparable:

Latency Glyph
<=1ms ▁
<=3ms ▂
<=10ms ▃
<=30ms ▄
<=100ms ▅
<=300ms ▆
<=1000ms ▇
>1000ms █

Use --history-style dots, --history-style sparkline, or --history-style none when a terminal font or workflow needs a simpler display.

Host States

pinghue classifies each host from the whole run, not just the most recent probes. Once a host has replied successfully, down requires --fail-threshold consecutive failures. A run with no successful replies is down immediately, even if it ends before the threshold. Any packet loss, or any observed jitter above --jitter-threshold, latches the host as intermittent until you reset it (r or R in the TUI). The reported jitter_ms remains the current decaying RFC 3550 estimate, so it can later fall below the threshold while the whole-run status stays intermittent. This is intentional: a maintenance-window report should reflect everything that happened, not only the final moments.

Slate + Signal Palette

pinghue uses a low-glare Slate + Signal palette designed for long maintenance windows: dark structure, high-contrast text, and saturated status colors that make the affected metric stand out quickly.

Role Hex Used for
Background #101418 Terminal body and empty space.
Panel #151b22 Table surface and primary content areas.
Header #1b2630 Title bars and footer bands.
Border #2a313a Table outlines and separators.
Text #e6edf3 Normal readable values.
Muted #8ea0b8 Labels, secondary text, and inactive chrome.
Green #7ee787 Healthy state, successful probes, and normal history bars.
Amber #f2cc60 Slow latency, high jitter, intermittent state, and TCP refused markers.
Red #ff7b72 Loss, down state, timeouts, and failed history markers.
Selection Blue #58a6ff Focus accents and selected-row treatment.

Doctor

Run the doctor before relying on ICMP mode:

pinghue --check

Linux may block unprivileged ICMP sockets. TCP mode does not need special privileges:

pinghue -p 443 example.com

If pinghue --check reports that your GID is outside net.ipv4.ping_group_range, the preferred fix is to allow only your current group:

gid="$(id -g)"
sudo sysctl -w "net.ipv4.ping_group_range=${gid} ${gid}"
echo "net.ipv4.ping_group_range=${gid} ${gid}" \
  | sudo tee /etc/sysctl.d/99-pinghue.conf

The broader range 0 2147483647 also works, but enables unprivileged ICMP for every local group on the system.

setcap cap_net_raw does not work for pip or Homebrew installs: the pinghue command is a Python launcher script, and Linux ignores file capabilities on interpreter scripts. Use the ping_group_range fix above, or TCP mode. Do not set capabilities on a shared Python interpreter.

JSON Output

--output PATH writes one JSON document per run. Existing regular files are preserved by default; add --overwrite when replacing a known report path is intentional. Symlinks, sockets, multiply linked regular files, and other unsupported special nodes are never replaced. Existing character devices and FIFOs are written directly only when they can be opened safely as the same node. This is the breaking 2.0.0 CLI change for scripts that previously reused the same output file. The schema lives at schemas/output-v1.schema.json, and an example lives at examples/pinghue-output-example.json.

New report creation is no-clobber and first tries to hard-link a complete temporary report into place atomically. On filesystems without hardlink support (for example exFAT and some FUSE mounts), it falls back to an exclusive create and copy: ordinary errors and handled interrupts remove that fallback file, but an abrupt process or system failure can leave a partial new report. Explicitly overwriting an existing regular file uses a descriptor-verified in-place rewrite so a path race cannot replace a symlink, socket, FIFO, or device node; that path is also not crash-atomic. Evidence workflows should accept a report only after PingHue exits successfully and the JSON parses, then rotate it as a separate step.

pinghue -f hosts.txt --duration 180 --output maintenance.json
pinghue -f hosts.txt --duration 180 --output maintenance.json --overwrite

Use --no-samples when you only need final per-target statistics.

Every output document includes:

  • schema_version
  • pinghue_version
  • run metadata (including samples_window)
  • probe configuration
  • ordered target results
  • per-target stats
  • optional per-probe samples

Per-target stats (sent, received, loss, latency, jitter) are computed over every probe in the run, so stats.sent reflects the whole run. The per-target samples array retains only the most recent run.samples_window probes. The window is at most 1000 per target and is reduced uniformly when needed to keep the run-wide retained tail within 100,000 samples. On long runs stats.sent therefore exceeds len(samples) — that is expected windowing, not a truncated file. When reconciling evidence, treat samples as the recent tail and stats as authoritative for the full run; --no-samples emits an empty array for every target.

The run.host field defaults to local to avoid leaking workstation hostnames. Use --host-label when a report needs an operator-selected system or maintenance-window label. Operator-visible target, host-label, and error text is escaped outside printable ASCII so terminal controls and visually deceptive Unicode are represented literally.

Security Model

pinghue is a local CLI/TUI. It does not run a server, accept remote requests, store credentials, or require secrets. The security-sensitive areas are:

  • terminal rendering of operator-supplied hostnames and OS error strings
  • Linux ICMP privilege configuration
  • local output paths selected by the operator
  • release workflow integrity

See pinghue-threat-model.md, security-best-practices-report.md, and SECURITY.md.

Release Channels

Published release channels:

  1. GitHub repository: inxbit/pinghue
  2. GitHub Actions CI on Linux and macOS
  3. GitHub Release with sdist and wheel artifacts
  4. PyPI trusted publishing through a protected pypi environment
  5. Homebrew tap: inxbit/tap from inxbit/homebrew-tap

The release workflow is tag-driven, but only after the release PR has merged. Create the signed annotated tag from the merged public main commit:

git fetch --prune origin
git tag -s vX.Y.Z -m "Release vX.Y.Z" "$(git rev-parse origin/main)"
git tag -v vX.Y.Z
git push origin vX.Y.Z

Development

Contributor setup, hash-pinned dependency audits, tests, and build verification are documented in the repository's CONTRIBUTING.md. Those maintainer tools are intentionally not part of the installed package.

License

MIT. See LICENSE.

Release files for pinghue 5.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pinghue 5.0.0
File Size Uploaded
pinghue-5.0.0.tar.gz 1.3 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for pinghue 5.0.0
File Interpreter ABI Platform
pinghue-5.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 1.3 MB

Release files / pinghue-5.0.0.tar.gz

Download URL pinghue-5.0.0.tar.gz
Size 1.3 MB
Tags Source
SHA-256 checksum
How to use checksums
33c0adb9985ea5fc737f67857435719193923bab3869d4c63c9b7f46adf696bb
BLAKE2b-256 checksum
How to use checksums
a9cc326dbaaf5ce7f2421eabb64c68fe8620dc33bc65663cef1bd95da8b4772f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 11, 2026.

Transparency log

Release files / pinghue-5.0.0-py3-none-any.whl

Download URL pinghue-5.0.0-py3-none-any.whl
Size 44.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3a1339669a70ffb5c779f0be988b9fd18fb02c0297e328e8b8a6f36a138c7a4f
BLAKE2b-256 checksum
How to use checksums
f79115605863559419e62562be7175ae3789d26efb11c786561812608f55c1f6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 11, 2026.

Transparency log

Release history Release notifications | RSS feed

5.1.0

2 release files

This release

5.0.0 This release

2 release files

4.0.0

2 release files

3.0.1

2 release files

3.0.0

2 release files

2.1.0

2 release files

2.0.1

2 release files

2.0.0

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

0.3.0

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page