Skip to main content
Glama

LinkWatch · Linux preview

A local network diagnostic CLI, MCP server and monochrome dashboard. Built from the selected topology + OpenCode Companion concept. This is an early working prototype, not a complete network management product.

Start

Requires Node.js 22+ and Linux ip (iproute2). No root required for current checks.

npm install
npm run build
node bin/linkwatch.mjs start

Open http://127.0.0.1:8787 on this laptop. The server binds only to loopback. Local HTTP is the default. Optional HTTPS accepts your own certificate and key through LINKWATCH_TLS_CERT and LINKWATCH_TLS_KEY; automatic certificate trust and authenticated LAN/remote access are not implemented. Do not expose this development server publicly.

Related MCP server: ContainerLab MCP Server

CLI

node bin/linkwatch.mjs status --json
node bin/linkwatch.mjs discover --json
node bin/linkwatch.mjs discover --active --json
node bin/linkwatch.mjs check 192.0.2.93 --port 9100
node bin/linkwatch.mjs monitor --printer 192.0.2.93 --interval 30 --seconds 86400
node bin/linkwatch.mjs incidents
node bin/linkwatch.mjs report > report.json
node bin/linkwatch.mjs doctor
node bin/linkwatch.mjs install
node bin/linkwatch.mjs uninstall
node bin/linkwatch.mjs theme light

Exit codes are meaningful: 0 success, 1 runtime failure, 2 invalid usage. A typo in a flag gives 2 and a real network problem gives 1, so scripts can tell them apart.

monitor runs in its own terminal; Ctrl+C stops it. It is not installed as a boot service. The previously configured pos-network-monitor service is separate and has not been replaced. Monitor records TCP handshakes to the selected printer and gateway web port. Failure of the gateway's web port does not prove the gateway is down. Three consecutive failures open an incident; success closes it. A link that cannot be read is written as an explicit missing observation, which breaks a pending failure streak rather than counting as a failure. Only one writer runs at a time: a lock file prevents a second monitor, a lock left behind by a killed process is reported as stale and taken over, and SIGINT/SIGTERM end the loop cleanly and release the lock. Logs rotate at 8 MiB keeping one previous file, and the report reads both. Retention can truncate incident history. Timestamps are ISO; the dashboard shows Bangkok time.

Dashboard

Start it with node bin/linkwatch.mjs start and open http://127.0.0.1:8787. The server binds only to loopback.

  • Monitoring is off by default and starts only when you press Start recording. A bar under the map always states whether anything is recording and shows the interval, start time and pid. A monitor started from the dashboard stops when the dashboard closes, so nothing keeps running unseen in the background. For long runs use the CLI, where you can watch it.

  • Scan subnet sends one ICMP echo per address on the connected /24 or smaller, eight at a time. It sends nothing to any port and never runs automatically.

  • Device notes and service ports are entered per device. They live in .data/labels.json, are kept separate from measurements, and are labelled operator note, not a measurement.

  • Declared links record your own statement that two devices are physically connected. LinkWatch cannot detect switch ports or mesh associations, so nothing is drawn until you declare it. Declared links are dashed, labelled Declared · wired or Declared · wireless, live in .data/links.json, and are never presented as measured. Withdraw them per device.

  • Replay in the live workspace walks the records actually retained for the selected incident. The demo workspace replay is synthetic and is labelled as such.

What is real

  • Ethernet IPv4/interface/route selection, Linux neighbor-cache discovery, MACs where known.

  • Source-address-bound TCP tests with a 2-second timeout and no payload, local subnet targets only.

  • Laptop interface byte counters and receive/transmit rate sampling, not all-device bandwidth.

  • Bounded recording, incident classification, JSON report download.

  • Operator device notes, service ports and declared wiring, stored apart from observations.

  • Theme preference in .data/theme.json; browser preference takes priority and persists in localStorage.

  • Twelve MCP tools, validated through the SDK client handshake.

What is illustrative or not implemented

  • Demo workspace contains sample topology and sample incidents; it never masquerades as real measurements.

  • Dashboard discovery reads the OS neighbor cache. The dashboard's Scan subnet button and CLI discover --active perform bounded ICMP discovery on /24 or smaller networks, eight probes at a time. Quiet or filtered devices can still be missing; cache entries can be stale.

  • Physical topology links, mesh associations, vendor identification, packet capture and per-device traffic accounting are not automatically available. Dashed links are your own declarations, not measurements.

  • Live graphs show no links at all until you declare them, because a neighbor cache entry is not a physical connection.

  • The sample chat is not AI output. Real chat requires the separate OpenCode server setup below.

  • Automatic diagnosis, automatic TLS trust setup, remote or LAN access, capture and per-device bandwidth remain future work.

OpenCode MCP

opencode.json in this folder points to this checkout and is gitignored, because it contains this machine's home directory and Node path. For other checkouts copy opencode.example.json and replace /ABSOLUTE/PATH/TO/.

opencode mcp list

Tools: network_status, discover_devices, check_device, get_topology, list_incidents, inspect_incident, monitor_status, list_labels, save_label, list_links, declare_link, remove_declared_link. No arbitrary shell tool, no printer payloads, no router mutations, and nothing that can start or stop a monitor. MCP stdio logs do not pollute stdout. Device information returned through OpenCode may be sent to your chosen hosted model.

Optional dashboard chat adapter

Configure your hosted model in OpenCode yourself. Start an authenticated loopback OpenCode server in the desired project. Launch LinkWatch with LINKWATCH_OPENCODE_URL=http://127.0.0.1:4096 and matching OPENCODE_SERVER_PASSWORD if authentication is enabled. The API refuses any OpenCode endpoint that is not local HTTP, so evidence cannot be sent to a remote host through it.

The adapter creates a fresh OpenCode session per question and submits only the typed question and the evidence snapshot shown in the dashboard. It is an evidence-explanation adapter, not an agent loop: the message is sent with every tool id the server reports switched off, and the system text states that device names and logs are untrusted data rather than instructions. Verified against the official OpenCode server documentation on 2026-10-04: POST /session takes only parentID and title, and tool restriction is done through the tools field on POST /session/:id/message. Oversized evidence is dropped with an explanation rather than truncated. Nothing is sent until you press send, and credentials stay server-side.

End-to-end hosted inference has not been tested against a real model. The adapter is covered by tests against a local mock OpenCode server. No provider was selected or charged during development.

Development and tests

npm test
npm run dev -- --port 5173

Start the API with npm start; Vite proxies /api to port 8787. The production build is served directly by the CLI. Runtime data belongs to .data/ (override with LINKWATCH_DATA_DIR) and is gitignored. Do not commit real diagnostic exports or credentials.

MIT licensed. See RELEASE-NOTES for what each version does and, more importantly, what it does not do. package.json keeps "private": true, so nothing is published to npm; the MIT license permits it but a global install is a poor fit for a tool that needs a local Linux checkout. Continuous integration runs the tests, the build and the Sites bundle check on Node 22 and 24.

Continue development in OpenCode

Read the complete handoff for decisions, file map, release milestones, validation, and the continuation prompt. The previous hourly Codex watch and standalone monitoring service were stopped at the owner’s request; leave them stopped.

Installed CLI and optional TLS

The CLI is installed on this laptop at ~/.local/bin/linkwatch. Keep this checkout in place. On another machine, run node bin/linkwatch.mjs install after installing dependencies and building, and linkwatch uninstall to remove the symlink. linkwatch doctor checks dependencies, the data directory permissions, whether the CLI is installed, HTTPS configuration and the monitor state without probing the network. linkwatch mcp-config emits a configuration with this machine's Node and CLI paths; merge its MCP entry into your existing OpenCode settings.

To use HTTPS, supply a certificate and key that your browser already trusts:

LINKWATCH_TLS_CERT=/path/to/cert.pem LINKWATCH_TLS_KEY=/path/to/key.pem linkwatch start

Both HTTP and HTTPS bind to loopback only. Setting one variable without the other is refused, and a certificate path that does not exist fails loudly rather than quietly falling back to plain HTTP. LinkWatch never modifies router or operating system trust settings, so a self-signed certificate will show a browser warning; that is expected. The integration test asserts that an untrusted certificate is genuinely rejected, so this cannot silently regress into being trusted.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    Network diagnostics — ping, traceroute, DNS lookup, port scanning, and connectivity testing via MCP.
    14
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Provides network operations tools such as ping, traceroute, DNS queries, and nmap scans via MCP, enabling network diagnostics and monitoring through natural language.
    15
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables interaction with Linux system operations via MCP, including CPU, memory, processes, storage, filesystem, hardware, network, monitoring, and logs.
    9
    MIT