The Problem

Operators of a homelab need a single, up‑to‑date visual map of diverse services (Proxmox VMs, Zigbee/Z‑Wave devices, network‑scanned hosts) without manually editing diagrams. The current setup scatters discovery, import, and status monitoring across separate tools, making it hard to see which nodes are online, which services they run, and how they connect.

What This Does

Homelable is a self‑hosted visualizer that combines network scanning, Proxmox/LXC import, Zigbee/Z‑Wave integration, and live status monitoring into a single interactive canvas (frontend/src/components/canvas/CanvasContainer). The backend (backend/app/api/routes/scan.py) runs nmap -sV --open via scripts/run_scan.py and writes discovered hosts as Pending Devices into the database. The frontend then lets users approve, hide, or ignore each device, instantly adding a node to the diagram. Pre‑built design styles and per‑node customisation are available, and the canvas can be exported as PNG or kept live‑synced with service health checks (ping, TCP, /health API). An MCP server (mcp/app/backend_client.py) exposes APIs for AI assistants to query the topology.

How It Is Wired

Execution starts at two entry points:

  • scripts/run_scan.py:24 – invoked manually or via CI; it reaches 45 functions and is called from 1 place. It performs a network scan, writes results to the DB, and populates the Pending Devices queue.
  • backend/app/main.py:32 (lifespan) – reaches 11 functions and is called by nothing else in the repo; it loads overrides from the filesystem at start‑up.

The internal call graph shows post (220 callers) and patch (178 callers) as the most‑touched functions, indicating the primary write path for device state. Hubs such as frontend/src/components/canvas/nodes/nodeTypes (Ca 2, Ce 5, instability 0.71) and mcp/app/backend_client (Ca 3, Ce 1) concentrate change impact; modifying them ripples through many dependent modules.

Code outside the repo: 306 functions make outbound network calls, 83 read/write the database, 14 read/write files, and 7 perform crypto/secret operations. The shortest path from an entry point to a leaving process is main → run_scan [db via db.execute].

How To Use It

Setup

# Clone the repo (verbatim URL)
git clone https://github.com/moses-y/homelable

# Start the full stack with Docker Compose
cd homelab
docker compose -f docker-compose.standalone.yml up -d

The compose file builds the backend (Dockerfile.backend) and frontend (Dockerfile.frontend) containers.

Configuration Copy .env.example to .env and adjust the scanner ranges, e.g.:

SCANNER_HTTP_RANGES=["8080","9000-9100"]
SCANNER_HTTP_PROBE_ENABLED=true
SCANNER_HTTP_VERIFY_TLS=false

These variables are read by backend/app/services/scanner.py and passed to the nmap invocation.

Running a scan

# Single CIDR (requires sudo for root‑level nmap features)
sudo python ../scripts/run_scan.py 192.168.1.0/24

Results appear as Pending Devices in the UI sidebar; approve each to add a node to the canvas.

Access the UI Open http://localhost:3000 (frontend port mapped by compose). Use the live‑status panel to see online/offline flags, or enable the MCP server for AI‑assistant queries.

Real‑World Use

A lab admin discovers a new Proxmox node and a Zigbee light bulb on the same subnet. They run the scan script, review the Pending Devices list, approve the Proxmox host (it appears as a VM node) and the light bulb (a Zigbee node). The admin then toggles the live‑status toggle; the canvas updates within seconds, showing the node online with a green indicator. Later, an AI assistant queried via the MCP server asks “Which devices are offline?” and receives a filtered list drawn from the same DB that the canvas reads.

Code Health & Issues

Measured findings (static analysis, 50 total)

  • 7 high: deep nesting (max indent 6) in frontend/src/components/canvas/nodes/BaseNode.tsx, frontend/src/components/modals/NodeModal.tsx, frontend/src/components/proxmox/ProxmoxImportModal.tsx; duplicated 6‑line blocks (554 occurrences) across 66 files including backend/app/api/routes/canvas.py and backend/app/core/scheduler.py; oversized files >800 lines (frontend/src/components/panels/DetailPanel.tsx, frontend/src/stores/canvasStore.ts, frontend/src/App.tsx); high branching density (59 branches over 206 lines) in frontend/src/components/canvas/SearchBar.tsx, frontend/src/utils/collapseFilter.ts, frontend/src/utils/exportYaml.ts; broad exception handling (bare except) in backend/app/api/routes/scan.py, backend/app/api/routes/status.py, backend/app/api/routes/zigbee.py.
  • 43 medium: additional cognitive‑load and resilience patterns identified but not listed as high‑severity.

Code‑health audit (8 findings)

  • HIGH – Pin third‑party GitHub Actions to commit SHAs (.github/workflows use @vN tags).
  • HIGH – Commit a lockfile beside the manifest (backend/pyproject.toml has no lockfile).
  • MEDIUM – Enable Dependabot/Renovate (no update bot configured).
  • MEDIUM – Pin container base image by digest (Dockerfile.backend uses python:3.13-slim without digest).
  • MEDIUM – Set persist-credentials: false on checkout (docker-ci.yml keeps token).
  • MEDIUM – Add a non‑root USER to the image (Dockerfile.backend has no USER directive).
  • LOW – Set timeout-minutes on workflow jobs (docker-ci.yml declares no timeout).
  • LOW – Add convention files (missing .editorconfig, .gitattributes, formatter config).

The Bottom Line

Homelable delivers a capable, self‑hosted homelab visualizer with real‑time scanning, import, and status monitoring, all wrapped in a React canvas. The codebase is functional but suffers from deep nesting, duplicated logic, and mutable GitHub‑Action pins that risk secret leakage. It is well‑suited for hobbyists and small teams who want a single dashboard for diverse services and are comfortable tightening the identified hygiene items.