A Rust terminal system monitor for CPU, memory, disks, network activity, processes, and host metadata.
grainx is a pre-1.0 project. The repository documents the implemented behavior and the checks that run in CI; it does not publish unsupported runtime or benchmark numbers.
- Interactive terminal dashboard with Unicode/Braille charts.
- Local system collection through sysinfo: CPU, memory, disks, network counters, processes, OS, kernel, and uptime.
- Optional analytics: z-score anomaly detection, Pearson correlation, moving-average estimates, and a deliberately simple arithmetic formula evaluator.
- Adaptive refresh and frame skipping when CPU load is high.
- Optional HTTP metrics service with GET /health and GET /metrics.
- JSON and CSV snapshots from local or remote metrics.
- JSON configuration with environment-variable and CLI overrides.
- Shell completion generation for Bash, Elvish, Fish, PowerShell, and Zsh.
The term agent in this repository means the HTTP metrics process. It is not an AI or LLM agent.
Prerequisites:
- Stable Rust 1.88 or newer. The crate uses Rust edition 2024. This minimum is checked against the committed dependency lockfile.
- An interactive terminal for the monitor command.
git clone https://github.com/rustfuture/grainx.git
cd grainx
# Run the local dashboard
cargo run --locked
# Build an optimized binary
cargo build --locked --releaseThe default command is monitor. In a headless environment, use the agent or export command instead.
# Interactive dashboard
cargo run --locked -- monitor
# Local HTTP metrics service; the bind address must be loopback
cargo run --locked -- agent --bind 127.0.0.1 --port 9090
# Export one snapshot without starting the TUI
cargo run --locked -- export
# Export from a running remote agent
cargo run --locked -- export --remote http://127.0.0.1:9090
# Read metrics in the terminal
curl http://127.0.0.1:9090/health
curl http://127.0.0.1:9090/metrics
# Connect the TUI to a remote agent
cargo run --locked -- monitor --remote http://127.0.0.1:9090
# Generate shell completions
cargo run --locked -- completions bashThe agent exposes host metrics without authentication, TLS, or rate limiting, so it refuses to start on any address that is not loopback: --bind 0.0.0.0 and a LAN address exit with an error instead of listening. That boundary is enforced in the program, not only in this document. Loopback is still not a complete protection — it does not separate users or processes on the same machine, and anything that can reach localhost can read the metrics. Remote metrics access is out of scope for this version; if you need it, put an authenticated transport in front of the agent.
The monitor reads dashboard_config.json. If the file is missing, grainx creates a default configuration. The precedence order is:
- dashboard_config.json
- Environment variables
- Monitor CLI flags
Supported environment overrides include GRAINX_REFRESH_INTERVAL_MS, GRAINX_CPU_WARNING_THRESHOLD, GRAINX_MEMORY_WARNING_THRESHOLD, and GRAINX_COLOR_THEME. See dashboard_config.json and src/config.rs for the current schema.
| Key | Action |
|---|---|
| q or Esc | Quit |
| Up / Down | Select a process |
| p | Pause or resume |
| k | Request process termination |
| r | Refresh the view |
| a | Toggle adaptive refresh |
| s | Save a snapshot |
Process termination is subject to the operating system permissions of the user running grainx.
- CPU Usage: System-wide CPU utilization is calculated as the average utilization across all logical cores since the last refresh. The default refresh interval is 1 second (1000ms), which provides a balanced sampling window.
- Memory Usage: Physical memory utilization reported by the operating system, excluding swap.
- Network I/O:
network_rx_bytesandnetwork_tx_bytesare the bytes received and transmitted during the most recent sampling interval (a per-interval delta reported bysysinfo). They are not cumulative counters and are not rates. The TUI labels the same values as kilobytes for the last interval. - Sampling Interval: By default, the system monitor samples state every 1000ms. This is configurable via
GRAINX_REFRESH_INTERVAL_MS. Adaptive refresh can increase this interval (slowing down the sampling rate) up to 2000ms when system CPU usage exceeds the configured warning threshold (default 80%).
See demos/ for verified captures with build identity, artifact hashes, a privacy review, and reproduction commands:
tui_capture_2026-09-12-contract-80x24.*and-110x50.*— the enforced bounded-capture contract at two terminal sizes, showing the currentNetwork I/O: ... (last interval)label.http_capture_2026-09-11.txt— realGET /healthandGET /metricsoutput plus a localexportrun from the built binary.verification_2026-09-11-remote-export.md— CLI-boundary verification of the remote-export fix: exit 0 against a livegrainx agent, and controlled non-zero errors for unreachable, malformed, andhttp://127.0.0.1:0endpoints with no panic text.verification_2026-09-12-braille-termination.md— PTY proof that braille rendering and frame completion are bounded.
The older 2026-09-06 captures are kept and marked historical.
cargo build --locked
python3 -m venv /tmp/grainx-render-venv && /tmp/grainx-render-venv/bin/pip install pyte==0.8.2
/tmp/grainx-render-venv/bin/python demos/capture_tui.py target/debug/grainx /tmp/tui.raw /tmp/tui.txt 5 110 50See demos/README.md and demos/verification_2026-09-11.md for the full commands, hashes, privacy review, and limitations.
Microbenchmarks run via cargo bench (Criterion) measure isolated components on the test host; they are not a universal performance claim. A recorded run with its machine, OS, toolchain, command, and base commit is kept in benches/results/2026-09-10-macos-arm64.txt. To reproduce:
cargo bench --lockedScope notes:
system_monitor_refreshconstructs a freshSystemMonitorand performs a singlerefresh()per iteration. It measures cold construction plus one refresh, and does not measure the CPU or memory cost of a long-running monitor loop.- The formula, prediction, and correlation benchmarks measure the analytical functions only. Those functions do allocate (metric substitution and token splitting build
String/Vecvalues); they are not zero-allocation.
- Monitor (
SystemMonitor): Gathers raw state usingsysinfo. - Analytics Engine (
analytics::*): Performs formula evaluation and anomaly detection on the collected metrics.evaluate_metric_formulasubstitutes whitespace-separated tokens and evaluates strictly left-to-right with no operator precedence; see its doc comment for the full contract. - Agent Server (
agent::*): Exposes collected metrics via an HTTP server usingaxum. Binds to127.0.0.1:9090by default and refuses any non-loopback address, because it serves without TLS or authentication. - TUI Renderer (
ui::*,tui::*): Renders the terminal dashboard usingcrossterm. Employs frame-skipping and adaptive refresh intervals to gracefully degrade under heavy load.
- Security: The HTTP agent has no TLS, authentication, or rate limiting. It refuses any non-loopback bind address at runtime, and
src/agent.rstests that0.0.0.0,::, and ordinary interface addresses are rejected. Loopback does not isolate users or processes on the same host, and remote metrics access is out of scope for this version. - Completeness: Network and disk I/O are aggregates and do not currently drill down into per-socket or per-file statistics.
- OS Support: CI tests Linux and macOS on stable Rust. Windows is not verified and is not covered by the CI matrix.
Run the same checks locally that CI runs:
cargo fmt --check
cargo check --locked --all-targets
cargo clippy --locked --all-targets -- -D warnings
cargo test --locked
cargo bench --locked --no-runThe Criterion benchmarks can be executed locally with cargo bench. Their results depend on the machine, operating system, and toolchain, so this repository does not present a universal performance claim. See docs/verification.md for the verification contract and docs/architecture.md for the module boundaries.
grainx follows 0.x semantics: the version number is a statement about scope, not a compatibility promise. While the major version is 0, a breaking change to the CLI, the configuration schema, or the exported JSON/CSV shape bumps the minor version, and a compatible fix bumps the patch version. Every change is recorded in CHANGELOG.md.
| Platform | Status |
|---|---|
| Linux | Verified by CI on stable Rust, plus an all-target compilation job on the minimum supported version. |
| macOS | Verified by CI, and used for the recorded captures under demos/. |
| Windows | Not verified; the CI matrix does not cover it. |
The minimum supported Rust version is 1.88; raising it is a minor-version change. A 1.0 would mean the command surface, the configuration schema, and the exported formats have stopped moving, not that every idea in TODO.md has been implemented.
grainx is released under the MIT License. See LICENSE.