Back to the network

Tooling

tool-kit

A personal toolbox behind one command: safe publishing of private repos, script vetting, checksummed backups, machine diagnosis and AI helpers.

These tools answer questions about the machine itself. Why is the network down? What is this computer, exactly? Why does my terminal look the same on every PC? What does a laptop setting really do? The rule from Safety rails turns into a rule about measuring: say only what was measured, and say what was not.

net-doctor: the first broken layer wins

A network fails from the bottom up. A dead link makes the gateway unreachable, which makes DNS fail, which makes every name lookup fail. So net-doctor walks six layers in order and stops at the first broken one. The layers after it are never run, so they report "skipped", never a result of their own.

Six layers, walked from the top: link asks whether an interface has carrier, address whether an up interface holds a global address, gateway whether the default gateway answers, dns whether the configured resolvers resolve, internet whether the internet answers by IP and by name, and services whether each configured service answers. The first broken layer wins and the walk stops there. In this example walk, link, address and gateway pass and dns fails, so it is the first broken layer; internet and services are skipped, blocked by dns, and report no result of their own.One walk, top to bottompass: the walk goes onfail: the first broken layer, so the walk stopsskipped: never run, so it claims no resultlinkpassdoes an interface have carrier?addresspassdoes an up interface hold a global address?gatewaypassdoes the default gateway answer?dnsfail — first broken layerdo the configured resolvers resolve?internetskipped — blocked by dnsdoes the internet answer, by IP and by name?servicesskipped — blocked by dnsdoes each configured service answer?
net-doctor's six layers, walked in order from link. In this example link, address and gateway pass, DNS is the first broken layer, and internet and services are skipped.

Here is a run on one of its test fixtures: a fake interface, documentation addresses, and a stub in place of every command:

net-doctor on the suite's dead-DNS fixture: every command it runs is a stub
$ network/doctor/doctor.sh
== link ==
✓ eth0 has carrier (up)
== address ==
✓ eth0 has IPv6 2001:db8::1a2b/64 (reported, not diagnosed)
✓ eth0 holds 192.0.2.50/24 (manager state: connected)
== gateway ==
✓ gateway 192.0.2.1 on eth0 answers ping
== dns ==
✗ resolver @192.0.2.1 does not answer
✗ resolver @192.0.2.2 does not answer
== internet ==
skipped — blocked by dns
== services ==
skipped — blocked by dns

fault at dns: none of the configured resolvers answer (@192.0.2.1, @192.0.2.2)
$ echo $?
1

Several of its rules exist because a simpler check would have given a confident wrong answer:

With --fix it repairs one confirmed step at a time. It refuses a remedy that is not marked safe when the session looks remote, or when the remedy would touch the interface the session runs on. It prints that remedy and does not run it, because a repair tool that locks you out of the box is worse than no tool. Where a network manager cannot repair one interface on its own, the doctor names the manager and offers nothing. A remedy that cannot run is worse than no remedy. And if it finds no checks to run at all, it exits 1, not with a clean bill. The suite has 50 fixture scenarios, and it passed 265 of 265 on 2026-10-25.

The system scan: what this machine is, measured

scan writes a machine's full spec, from eight collectors (identity, compute, storage, network, services, software, health and security), into one JSON file and a SPEC.md for people to read. SPEC.md closes with two blocks, Attention and Not measured. Attention is judged on seven rules, every one listed in the docs, and nothing else. Here is that block rendered from the suite's hand-written fixture, a fictional machine in every bad state at once:

The scan's renderer on its hand-written fixture: a fictional machine that breaks every rule at once
$ python3 scan/system/render.py spec
$ sed -n '/^## Attention/,$p' spec/SPEC.md
## Attention

> Stable facts only: SMART, filesystems over 90 %, battery health, failed services, firewall, disk encryption, pending security updates. What could not be measured is under *Not measured*, not here.

- SMART on `sda` (FAILING DISK) reports **FAILED**.
- `/` is **97 % full** (14.2 GiB free).
- Battery holds **62 %** of its design capacity (under 80 %).
- **2 failed services**: `nginx`, `chronyd`
- Firewall (`firewalld`) is **stopped**.
- The system volume is **not encrypted**.
- **3 pending security updates** (package metadata 52 h old).

## Not measured

Re-run with `--sudo` to close the `needs-privilege` gaps, or run the commands below by hand.

| Section | Field | Reason | Re-run |
|---|---|---|---|
| storage | `disks[1].smart` | needs-privilege | `sudo -n smartctl -d sat -a /dev/sdb` |

Two exclusions are deliberate:

The scan sends nothing over the network, and it writes nothing outside its own folder. An isolation test caught two probes that broke that promise. flatpak list creates a folder in the home directory on a machine that has never used flatpak. An unprivileged dnf -C check-update copied the whole system package cache, about 100 MB, into the home directory. Both probes were changed, because a scan plugged into someone else's machine for thirty seconds must not leave a package cache behind.

zconnect: one folder, every machine

I work across several PCs, on Linux and on Windows, and I want the same terminal on each. With zconnect you clone tool-kit and run zc doctor, and the machine works out from its hostname which connection it is. That connection becomes local, and the rest stay remote over SSH. Every device gets the same menu, with the same keys in the same order, local or remote, Linux or Windows.

None of it needs admin rights. Python comes from a pinned uv and CPython in 0-lib/, set up beside the package on the first run, with no change to PATH. zellij comes from the machine when it has one. Otherwise it comes from a pinned portable build, fetched once and checked against its checksum. Nothing is installed system-wide.

Each device gets its own zellij theme: the base theme with a new background and a new family of accent colours. Every palette is one row in one spec file. A generator derives each theme from a shared template, and its --check regenerates them all in memory and compares them with the files on disk:

Six rows of five swatches, in the roles bg, active, frame, accent, bright. The base palette comes first; the five derived themes override its colours and are named by colour family. base: bg #24283b, active #3d59a1, frame #414868, accent #7aa2f7, bright #7dcfff; blue-grey: bg #2e404b, active #1f4e79, frame #4a6474, accent #4ea6e6, bright #78c8ff; grey-purple: bg #4b2d49, active #5a2f57, frame #6e506c, accent #c778dd, bright #e39ef7; teal: bg #264a48, active #10615d, frame #4a6a68, accent #22d3ee, bright #67e8f9; starry night: bg #212c4f, active #35508f, frame #4a5a8c, accent #f5d76e, bright #ffe9a3; red: bg #4a2c2c, active #5f2f2f, frame #6a4a4a, accent #e06c75, bright #f09199.Derived from itbaseblue-greygrey-purpletealstarry nightred
The template and five derived palettes, as zconnect's theme spec file defines them, named by colour family. Which device wears which stays off this page.

Measured, not assumed

Two small laptop tools, each with a claim that turned out wrong once it was checked:

Stack

  • Python
  • Shell

Connected to