nodeIQ
Ask plain-English questions about a Linux server and get answers grounded in that server's real, freshly-collected state — not generic advice.
nodeiq collects live data (processes, disk, services, logs, network, cron jobs, file permissions, login/auth activity, Docker containers), routes your question to the collectors that actually matter, and hands the result to an LLM (OpenAI) to answer. One server, real data, one question at a time — no fleet management, no agents that act on their own.
Features
- Natural-language Q&A about a server's live state —
--askfor a one-shot question,--chatfor a REPL with short-term follow-up memory. - Hybrid routing — a free keyword fast-path for the common case, a single bounded LLM classification call as a fallback for novel phrasing, broad ("full health check") questions, or genuinely out-of-scope ones.
- Troubleshooting, not just reporting — for "why is X high/failing" questions, nodeiq names the specific process/service responsible and suggests a concrete fix as advice. It never runs anything itself: every collector shells out with a fixed argument list, never a string built from a question or an answer, so there's no code path where nodeiq (or the LLM) could execute a command even if it tried to.
- A free, no-LLM health sweep —
--checkapplies threshold rules (disk %, failed services, load, recent errors) and exits 0/1, safe to wire into cron or a monitoring pipeline. - Change tracking —
--diffcompares live state against the last--diffsnapshot and narrates what actually changed. - A saved report artifact —
--reportwrites a full document-style Markdown health check to a file, for pasting into a ticket or handoff doc. - Secret redaction — process command lines and cron job commands are
scanned for common secret shapes (
--password=,Authorization: Bearer, known key prefixes) and redacted before anything is saved or sent to OpenAI. - Readable terminal output — colored, boxed, word-wrapped answers (no
new dependency: plain ANSI + stdlib
textwrap), falling back to plain text automatically when piped, redirected, or$NO_COLORis set. - Resilient collectors — each collector isolates its own independent
data sources, so one failing source (a missing
/procfile, a hungsystemctlcall) doesn't blank out the rest of that collector's report. - An operational log (
logs/nodeiq.log) of what nodeiq itself did — questions received, routing decisions, collector outcomes, LLM calls — separate from the server's logs it reads.
How it works
flowchart TD
Q[Question] --> CLI[nodeiq/cli.py]
CLI --> ORCH[nodeiq/orchestrator.py: route + collect]
ORCH --> COL[nodeiq/collectors/*.py]
COL --> REPORT[JSON report]
REPORT --> LLM[nodeiq/llm.py + OpenAI]
LLM --> ANSWER[Answer, colored + boxed in the terminal]
See docs/architecture.md for the fuller diagram, including the
keyword-vs-AI routing decision and the operational-logging side-channel.
Requirements
- A Linux server. Most collectors also expect
systemd(Ubuntu, Debian, RHEL, and most modern distros) — a few degrade gracefully without it (permissions, most ofcron/auth), a couple simply returnok: false(services,processes,disk,logs,network). nodeiq detects the OS/architecture it's running on (platform_info.py) and announces it once per session — running it on macOS for quick dev testing gives clean "requires Linux" messages instead of crashes, not full functionality. - Python 3.10+.
- An OpenAI API key.
- Docker, only if you want the
dockercollector to return anything — its absence is a normal "not applicable" case, not an error. - No sudo required for most questions. A few checks (firewall rules, full
log history) need it for complete data — nodeiq never escalates
privilege itself; run the whole tool under
sudoif you want that coverage (seedocs/architecture.md).
Quickstart
Option A: install from PyPI
Just want to run it — pypi.org/project/nodeiq:
python3 -m venv venv && source venv/bin/activate
pip install nodeiq
echo "OPENAI_API_KEY=sk-..." > .env # your real key, in the directory you'll run nodeiq from
Option B: install from source
Want to read/edit the code, or run the test suite — see docs/setup.md
for the full walkthrough (including a local Ubuntu VM option if you don't
have a spare Linux box):
git clone <this repo> nodeiq && cd nodeiq
python3 -m venv venv && source venv/bin/activate
pip install -e .
cp .env.example .env # then set OPENAI_API_KEY in it
Either way, then:
nodeiq --list
nodeiq --ask "how much disk space is free?"
nodeiq --chat
nodeiq --check # free health sweep, no LLM call, exit 0/1
nodeiq --diff # what changed since the last --diff run
nodeiq --report # save a full Markdown health report
sudo venv/bin/nodeiq --collect network # for firewall-rule coverage
Testing
python3 -m unittest discover -s tests -v
Covers redact.py and healthcheck.py's rule logic — the two modules
with real branching and no live-system/network dependency. Collectors
are exercised via nodeiq --collect <name> against a real box instead
(see docs/collectors/).
Docs
docs/architecture.md— flow, question routing, permissions/sudo rules, design principlesdocs/collectors/— one file per collector: fields returned, decisions, edge casesdocs/orchestrator.md— routing, chat memory, robustness, terminal outputdocs/llm.md— model choice, system prompt, remediation advice, error handlingdocs/logging.md— nodeiq's own operational log (logs/nodeiq.log)docs/config.md— every tunable setting, the LLM cost guardrails, and--checkthresholdsdocs/redaction.md— what secret-redaction catches, and its honest limitsdocs/setup.md— install, run, optional local test VMdocs/packaging.md— why releases are Cython-compiled, how to build/publishCHANGELOG.md— release history, what's built vs. planned
Configuration
All in nodeiq/config.py, each overridable by an environment variable — see
docs/config.md for the full list and the cost-guardrail reasoning.
| Variable | Required | Default | Purpose |
|---|---|---|---|
OPENAI_API_KEY |
yes | — | LLM calls (see .env.example) |
NODEIQ_MODEL |
no | gpt-5.4-nano |
OpenAI model used for both routing and answers |
NODEIQ_LOG_LEVEL |
no | INFO |
Set to DEBUG for verbose operational logging |
NODEIQ_MAX_LLM_CALLS |
no | 40 |
Hard cap on OpenAI calls per process — see docs/config.md |
NO_COLOR |
no | unset | Set to force plain-text terminal output |
Status
All 9 collectors, hybrid routing, chat, LLM integration, colored/boxed
terminal output, remediation advice, per-source failure isolation,
operational logging, secret redaction, a no-LLM health sweep (--check),
change tracking (--diff), and a saved report artifact (--report) are
built and verified against a live Ubuntu box (and, for the
platform-independent pieces, live against real OpenAI calls). See
CHANGELOG.md for the full release history.
Release files for nodeiq 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
Total release size: 40.1 MB
Release files / nodeiq-0.1.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl
| Download URL | nodeiq-0.1.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl |
|---|---|
| Size | 5.6 MB |
| Tags | CPython 3.14 CPython 3.14 free-threading Linux glibc 2.17+ ARM64 Linux glibc 2.28+ ARM64 |
|
SHA-256 checksum How to use checksums |
7514bcfa6d51ed7efa9512b0b22aa191c9530e4ee7ab6b2fc8e1fb9910d5a848
|
|
BLAKE2b-256 checksum How to use checksums |
13da9655ae08e10cbdd2d0c18be37687c363615ffaf59c5dbbbd93c436c8a1f4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|
Release files / nodeiq-0.1.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl
| Download URL | nodeiq-0.1.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl |
|---|---|
| Size | 4.9 MB |
| Tags | CPython 3.14 Linux glibc 2.17+ ARM64 Linux glibc 2.28+ ARM64 |
|
SHA-256 checksum How to use checksums |
be213011981b53e866f6eb492ce97facf0db8d345cf5cbc90834d555ead23573
|
|
BLAKE2b-256 checksum How to use checksums |
c118e8b63541b46b4a5bb98d20384955a003f4dfc66a9ebdf92f94ca441e9e9a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|
Release files / nodeiq-0.1.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl
| Download URL | nodeiq-0.1.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl |
|---|---|
| Size | 4.9 MB |
| Tags | CPython 3.13 Linux glibc 2.17+ ARM64 Linux glibc 2.28+ ARM64 |
|
SHA-256 checksum How to use checksums |
31ea7c7ba26c3bc86c855a3eb6d9f4b7d35d693bf40021638f3eac9ef49d3bde
|
|
BLAKE2b-256 checksum How to use checksums |
b8c49db9a8e26c1801d4f89da7b28ab62b8f6fad8d531ca23029b78b72c15167
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|
Release files / nodeiq-0.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
| Download URL | nodeiq-0.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 5.2 MB |
| Tags | CPython 3.12 Linux glibc 2.17+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
296d428e7e5d34b94b56f9a2696528264b15aa2e806b4b1f991b712995042de7
|
|
BLAKE2b-256 checksum How to use checksums |
c96bbb00d1e591bbebb4591ef0b7af187823a6b08aa99508f5395d2afe840047
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|
Release files / nodeiq-0.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl
| Download URL | nodeiq-0.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl |
|---|---|
| Size | 5.0 MB |
| Tags | CPython 3.12 Linux glibc 2.17+ ARM64 Linux glibc 2.28+ ARM64 |
|
SHA-256 checksum How to use checksums |
47b116f91cdf849b23284cfe90c308b56d4c839683ab490a0c3ae7107f84ee48
|
|
BLAKE2b-256 checksum How to use checksums |
edbb63d3518e9e445d4d8f5711092825699d0784059f46da3db72202fc3d952c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|
Release files / nodeiq-0.1.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl
| Download URL | nodeiq-0.1.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl |
|---|---|
| Size | 5.0 MB |
| Tags | CPython 3.11 Linux glibc 2.17+ ARM64 Linux glibc 2.28+ ARM64 |
|
SHA-256 checksum How to use checksums |
83ff9b6fb17bebf9ca6c6ed0990d35a639cfaf225a914e9ea6d99d7c501ceb14
|
|
BLAKE2b-256 checksum How to use checksums |
095b4b8dce527cbe2db75b75d13ecbab6097981cc08e70f9a66db9fd68cab435
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|
Release files / nodeiq-0.1.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl
| Download URL | nodeiq-0.1.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl |
|---|---|
| Size | 4.7 MB |
| Tags | CPython 3.10 Linux glibc 2.17+ ARM64 Linux glibc 2.28+ ARM64 |
|
SHA-256 checksum How to use checksums |
091d72ab456c6fd0985d0608ce7f745aa5230f3e4e3130472c7634c229250e28
|
|
BLAKE2b-256 checksum How to use checksums |
57eabf97b5094b6d472560cf7d0af0d49f9bba7f60da8cdce5ef79d91b1a4905
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|
Release files / nodeiq-0.1.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl
| Download URL | nodeiq-0.1.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl |
|---|---|
| Size | 4.7 MB |
| Tags | CPython 3.9 Linux glibc 2.17+ ARM64 Linux glibc 2.28+ ARM64 |
|
SHA-256 checksum How to use checksums |
f47f3e9097cf5f74a87b076b62fec84423983d09e4d13ada8b7470e72bee3e45
|
|
BLAKE2b-256 checksum How to use checksums |
3f1526419cea10418175acfba1e9367e33f41600e52752b43cfb301d84a4d014
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|