# Contributing Homelab **network + hardware topology generator**: scanners and collectors gather a machine's or a network's real topology, a pipeline normalizes + enriches it, and the dashboard draws it live. Reporting agents push each host's map + telemetry to the dashboard server. Domain vocabulary — **Topology, Collector, Card, Store, Widget** — is defined in [CONTEXT.md](CONTEXT.md). Use those names. This file is operational: how to work in the repo. ## Pipeline `collectors/*.py` + `scanners/*.py` gather raw dicts → `core/normalize.py` (dedup by MAC, reconcile by IP/hostname, VLAN by subnet) → `core/enrich.py` (vendor via `core/oui.csv`, kind, aging) → `renderers/card.py` view-model → `renderers/html/` (the dashboard). Two dashboard subsystems live beside it, both server-side only (not in the agent bundle): **Glances** (this host's live metrics — `core/glances.py`; remote hosts push via the agent) and the **Widget Store** (`widgets/` + `renderers/html/widget_store.py`, `/api/widget-*` routes — see [CONTEXT.md](CONTEXT.md) → Widget, `docs/prd/widget-store.md`, `docs/widgets-adding.md`). ## Commands Install: `pip install -r requirements.txt` - Dashboard server: `python renderers/html/topo_server.py [--port 8770]` - Map this machine: `python scanners/make_pc_topo.py` (Windows) · `python scanners/make_linux_topo.py` (Linux) - Map the network: `python scanners/make_network_topo.py` - Report to a dashboard: `agent/report.sh http://:8770` - Run it as a container: `docker compose up -d` (see [docker-compose.yml](docker-compose.yml)) ## Tests Every check is offline and runs in seconds. This list is exactly what CI runs ([.github/workflows/ci.yml](.github/workflows/ci.yml)) — keep the two in sync. ``` python -m compileall -q . python tests/test_pipeline.py # collectors -> normalize -> enrich, on fixtures python tests/test_cards.py # card contract + network-cards adapter python tests/test_routes.py # boots topo_server on a free port, hits its routes python -m collectors.unifi # unifi transforms + the single GET/POST request path python -m core.identity # node id rule + link endpoint resolution python -m collectors.arpscan # arp-scan + nmap output parsers python -m collectors.unifi_snmp # snmpwalk parser + FDB OID -> MAC decode python -m collectors.docker # docker ps line parser python -m collectors.tailscale # peer shaping + overlay mesh python -m collectors.dns # hosts file + pi-hole custom dns rows python -m collectors.pingsweep # arp -a table parser (win + posix) python -m collectors.opnsense # vlan zones + lease/arp merge python renderers/html/_guard.py # shared path-injection barrier python renderers/html/pushcache.py # push-freshness cache (live/stale/miss) python renderers/html/store.py # store slug policy + save/load python renderers/html/widget_store.py # widget store CRUD round-trip python renderers/html/icons.py # service-icon slug candidates python renderers/html/report.py # diagnostic HTML report escaping python renderers/html/pve_tiles.py # proxmox guests -> dashboard tiles python renderers/html/agent_bundle.py # agent tar.gz/zip builder python collectors/transport.py # shared collector HTTP (ssl ctx + get_json) python -m widgets.net # widget SSRF guard python -m widgets.engine # widget engine (auth/mapping) python -m widgets.fetchers # widget stat parsers + collector-backed SSRF guard python -m widgets.policy # widget config/secret policy (mask/whitelist/inherit) python -m widgets.registry # catalog integrity + full_catalog merge python scanners/make_linux_topo.py --selftest python scanners/make_pc_topo.py --selftest # perf-counter iface + cap vocabulary bash tests/test_uninstall_unraid.sh # uninstaller only removes its own boot 'go' lines ``` (`widgets/*` use relative imports — run via `python -m widgets.`, like `collectors/`.) Also in CI: `bash -n *.sh tests/*.sh`; `.ps1` files must be ASCII; dashboard JS via `node --check` on the extracted `