homelabby/CLAUDE.md

12 KiB

Project

HWLab

HWLab is a self-hosted, AI-powered hardware inventory management system for homelab environments. It combines local multimodal AI (Gemma 4 via oMLX) for photo-based intake and categorization, NetBox as the authoritative inventory database, and automated label printing with integrated cable testing workflows. Built with Go + React, running entirely on a Mac Mini M4.

Core Value: Any physical item can be cataloged by uploading a photo — AI extracts data, creates a NetBox record, and prints a QR-coded label — with zero manual data entry for 80-90% of items.

Constraints

  • Hardware: Mac Mini M4 with 16GB — Gemma 4 model must fit in memory (E4B confirmed, 26B A4B needs testing with TurboQuant)
  • No cloud dependency: Standard operations must work fully local — OpenRouter only for Tier 2/3 AI
  • NetBox is source of truth: HWLab stores no inventory data locally (only advisor chat history + config in SQLite)
  • USB protocols: Printer and tester protocols need reverse-engineering once hardware arrives
  • Tech stack: Go backend, React TypeScript frontend, Tailwind CSS

Technology Stack

Core Technologies

Technology Version Purpose Why Recommended
Go 1.22+ Backend API, USB/serial control, AI orchestration Native concurrency for USB polling + HTTP serving; single binary deployment; no runtime dependency; best-in-class serial I/O on macOS
React 18.x SPA frontend Mature ecosystem, hooks-based state management, excellent TypeScript support; right level of complexity for a single-operator tool
TypeScript 5.x Frontend type safety Catches API contract drift early; NetBox has complex nested types that benefit from strict typing
Tailwind CSS 3.x Utility-first styling ClickHouse-inspired design system maps well to utility classes; no CSS file sprawl; dark theme with arbitrary values is trivial
SQLite (via mattn/go-sqlite3) 3.x / v1.14+ Local-only storage (chat history, config, session state) Zero-dependency embedded DB; perfectly suited for single-operator append-heavy chat logs; no separate process
oMLX latest Local LLM inference server on Mac Mini M4 Native Apple Silicon MLX backend, OpenAI-compatible API endpoint, paged SSD KV caching, continuous batching; supports Gemma 4 VLM natively; drop-in for any OpenAI-SDK client

Go Backend Libraries

Library Version Purpose When to Use
github.com/netbox-community/go-netbox/v4 v4.x NetBox REST API client All CRUD against NetBox — officially maintained, generated from NetBox OpenAPI spec
go.bug.st/serial v1.x USB serial communication Printer + cable tester I/O; actively maintained, cross-platform, better API than tarm/serial; supports port enumeration
github.com/gin-gonic/gin v1.9+ HTTP router and middleware Fast, well-documented, large middleware ecosystem; handles file uploads for photo intake cleanly
github.com/mattn/go-sqlite3 v1.14+ SQLite driver (cgo) Standard Go SQLite driver; use with database/sql for portability
github.com/jmoiern/sqlx v1.3+ database/sql extension Named params and struct scanning reduce boilerplate for chat history queries
github.com/sashabaranov/go-openai v1.x OpenAI-compatible client Handles both oMLX local endpoint and OpenRouter remote; single client, swap base URL per tier
github.com/skip2/go-qrcode v0.0.0 QR code generation Generate HW-XXXXX QR codes server-side before sending to printer
github.com/google/uuid v1.x UUID generation HW-XXXXX ID assignment; deterministic or random depending on design choice
github.com/spf13/viper v1.x Config management YAML/env config for AI endpoints, NetBox URL/token, USB port paths

Frontend Libraries

Library Version Purpose When to Use
Vite 5.x Build tool and dev server Fastest HMR in class; Go backend runs separately, Vite proxies API calls in dev
TanStack Query (React Query) v5 Server state management NetBox data is server state not client state; handles caching, refetch, stale-while-revalidate
TanStack Router v1 Type-safe routing Better TypeScript integration than React Router v6 for complex nested routes
Zustand v4 Client state (UI state, chat) Lightweight, no boilerplate, perfect for chat message buffer and USB device status
shadcn/ui latest Component primitives Radix UI + Tailwind, fully owned code (not a dependency), dark mode first, ClickHouse aesthetic compatible
react-dropzone v14 Photo drag-and-drop Standard library for file upload UX; works with multipart form to Go backend
react-hot-toast v2 Toast notifications Inventory actions (label printed, test passed) need lightweight non-blocking feedback
lucide-react latest Icon set Consistent, tree-shakeable, TypeScript-native, pairs well with shadcn/ui

Development Tools

Tool Purpose Notes
Air (cosmtrek/air) Go hot reload in development Watch + rebuild backend on save; configure alongside Vite proxy
golangci-lint Go linting Run in CI; catches serial/concurrent code issues early
ESLint + typescript-eslint Frontend linting Strict TypeScript rules; catch NetBox API type drift
Prettier Frontend formatting Single config, no debates
Bruno (or httpie) API testing Test NetBox integration and Go endpoints locally without Postman account

Installation

Go backend — initialize module

Core Go dependencies

Frontend — scaffold

Frontend core dependencies

shadcn/ui init (run in frontend dir)

Dev dependencies

Alternatives Considered

Recommended Alternative When to Use Alternative
go.bug.st/serial tarm/serial tarm/serial is adequate if you only need basic read/write and already have it; go.bug.st/serial is preferred for new projects due to active maintenance and port listing
gin-gonic/gin chi, echo, fiber chi if you want stdlib-compatible handlers; echo for similar feature set; fiber if you need extreme HTTP throughput (not relevant here)
go-openai (sashabaranov) Custom HTTP client Custom client only if you need streaming SSE to browser — go-openai supports streaming too, prefer it
TanStack Router React Router v6 React Router v6 is fine if team is already familiar; TanStack Router has stronger TypeScript guarantees for route params
TanStack Query SWR SWR is lighter but TanStack Query has better devtools and mutation handling for NetBox writes
mattn/go-sqlite3 (cgo) modernc.org/sqlite (pure Go) Use modernc.org/sqlite if you want zero cgo dependency (simpler cross-compilation); slightly slower but avoids gcc requirement
oMLX Ollama Ollama works but oMLX has better Apple Silicon performance via MLX backend; Gemma 4 VLM continuous batching support is oMLX-specific

What NOT to Use

Avoid Why Use Instead
GORM Heavy ORM abstraction for what is essentially two tables (chat logs, config); migrations and reflection overhead not worth it for SQLite local-only store database/sql + sqlx directly
tarm/serial Last commit 2018, unmaintained, no port enumeration, open issues unaddressed go.bug.st/serial
Redux (React) Massive boilerplate for a solo-operator SPA; overkill when TanStack Query handles server state Zustand + TanStack Query
axios Unnecessary HTTP client abstraction; TanStack Query works with native fetch; one fewer dependency fetch API directly inside TanStack Query
Next.js SSR/SSG overhead not needed — Go handles the API, React is a pure SPA served as static files Vite + React SPA
llama.cpp Go bindings Not optimized for Apple Silicon; MLX backend (oMLX) is 2-4x faster on M-series; cgo binding complexity oMLX via OpenAI-compatible HTTP
Direct NetBox HTTP calls (no client) NetBox v4 API has 200+ endpoints; go-netbox generates typed structs from OpenAPI spec — manual HTTP is brittle go-netbox/v4

Stack Patterns by Variant

  • Use a single go-openai client instance per tier, configured with BaseURL pointing to oMLX (http://localhost:PORT/v1) for Tier 1, and https://openrouter.ai/api/v1 for Tier 2/3
  • Switch by returning the appropriate client from a factory based on model config
  • Do NOT hardcode tier selection in business logic — make it config-driven from the start
  • Use go.bug.st/serial with a dedicated goroutine per device, communicating via channels
  • Do not share a serial.Port across goroutines — open one port per device, serialize writes in the owning goroutine
  • USB device paths on macOS follow /dev/cu.usbserial-* or /dev/cu.usbmodem*; use serial.GetPortsList() to enumerate at startup
  • Accept multipart/form-data in Gin; decode image in Go; send as base64 in the OpenAI vision API call to oMLX
  • Store the original photo in a local temp directory only until the NetBox record is created; do not persist photos in HWLab itself
  • Gemma 4 E4B fits comfortably in 16GB; Gemma 4 26B A4B needs TurboQuant KV offload — benchmark before committing to 26B
  • go-netbox v4 represents custom fields as map[string]interface{}; define typed wrapper structs in your own code to handle hw_id, condition, quality_gate etc.
  • Custom fields must be created in NetBox admin before the Go code can write them — treat this as infrastructure provisioning (Phase 1 task)

Version Compatibility

Package Compatible With Notes
go-netbox/v4 NetBox 4.x Generated from NetBox 4.x OpenAPI; not compatible with NetBox 3.x API responses
mattn/go-sqlite3 v1.14+ Go 1.21+ Requires cgo; needs gcc or Xcode CLT on macOS
shadcn/ui React 18, Tailwind 3.x shadcn v2+ requires Tailwind 3.x; not yet tested with Tailwind 4 alpha
oMLX macOS 15+, Apple Silicon M1+ Won't run on Intel Mac or Linux
go-openai v1.x OpenAI API v1, OpenRouter, oMLX Any OpenAI-compatible endpoint works; set BaseURL in ClientConfig

Sources

  • github.com/jundot/omlx — oMLX feature set, Gemma 4 VLM support confirmed (HIGH confidence)
  • github.com/netbox-community/go-netbox — Official Go client, v4 confirmed (HIGH confidence)
  • go.bug.st/serial pkg.go.dev — Active maintenance confirmed, preferred over tarm/serial (HIGH confidence)
  • omlx.ai — macOS 15+ requirement, 16GB minimum RAM, MLX backend (HIGH confidence)
  • WebSearch: tarm/serial maintenance status — last substantive commit 2018, multiple forks active (MEDIUM confidence)
  • Training data: gin, TanStack Query, Zustand, Vite, shadcn/ui versions — standard 2025 React/Go stack (MEDIUM confidence, verify pinned versions before first install)

Conventions

Conventions not yet established. Will populate as patterns emerge during development.

Architecture

Architecture not yet mapped. Follow existing patterns found in the codebase.

Project Skills

No project skills found. Add skills to any of: .claude/skills/, .agents/skills/, .cursor/skills/, or .github/skills/ with a SKILL.md index file.

GSD Workflow Enforcement

Before using Edit, Write, or other file-changing tools, start work through a GSD command so planning artifacts and execution context stay in sync.

Use these entry points:

  • /gsd-quick for small fixes, doc updates, and ad-hoc tasks
  • /gsd-debug for investigation and bug fixing
  • /gsd-execute-phase for planned phase work

Do not make direct repo edits outside a GSD workflow unless the user explicitly asks to bypass it.

Developer Profile

Profile not yet configured. Run /gsd-profile-user to generate your developer profile. This section is managed by generate-claude-profile -- do not edit manually.