From 7,000 Lines to 500: Rebuilding a "Sellable" Lightweight Dashboard from Scratch
Introduction
Our internal OpenClaw Dashboard — covering task management, node monitoring, a family calendar, AI usage stats, and more — had quietly grown past 7,000 lines. Feature-rich, yes, but completely overkill as a product to ship inside a miniPC to customers.
This is the story of extracting only what was needed and rebuilding it as an independent, lightweight "Dashboard Lite" — backend 500 lines, frontend 37KB — in about an hour.
The Problem: Selling a Bloated SPA
The original Dashboard packed in everything:
- Today's schedule & timeline
- Family anniversary calendar
- Bulk monitoring of 8 nodes (OpenClaw status)
- AI (Claude) usage graphs
- External API integrations (OCM Server, home automation, etc.)
Shipping this on a customer's miniPC immediately surfaced problems:
-
Too many dependencies — hard-wired to internal services (
192.168.3.33:8001,:8091, etc.) - Brand leakage — private labels like "TechsFree" and "family" scattered throughout
- Opaque configuration — no clear map of which APIs to disable or which constants to replace
We decided: rewriting from scratch with defined requirements would be faster than surgically trimming the existing code.
Approach: Write from Zero, Bring No Dependencies
Defining requirements by elimination
For the customer miniPC, only two features actually mattered:
- Project task management — simple todos (create / complete / delete)
- Node management (local only) — this machine's OpenClaw status, bot list, log viewer
No timeline. No family calendar. No AI usage. Defining what you don't need is the first step in product design.
Backend: Flask, one dependency
# requirements.txt
flask
That's it. The original server.py had requests, websockets, and several other packages. Lite runs on flask alone.
Endpoints, likewise kept minimal:
GET /api/simple-tasks # list tasks
POST /api/simple-tasks/toggle # toggle complete
POST /api/simple-tasks/add # add task
POST /api/node/status # local node status
GET /api/node/bots # bot list
POST /api/node/restart-gateway # restart gateway
Instead of hitting external APIs, node info is read directly from the local openclaw.json file — zero network dependency.
OC_PATH = os.environ.get('OC_PATH') or detect_oc_path()
def detect_oc_path():
candidates = [
Path.home() / '.openclaw',
Path('/etc/openclaw'),
]
for p in candidates:
if (p / 'openclaw.json').exists():
return str(p)
return str(Path.home() / '.openclaw')
An environment variable override handles non-standard install paths.
Frontend: Strip the brand, create "generic" feel
The original Dashboard used TechsFree's signature orange palette and logo. For the product version:
- Switched accent color to purple (neutral, unimposing)
- Replaced the logo with a plain "OpenClaw Dashboard" text logo
- Unified fonts to system fonts (
-apple-system, BlinkMacSystemFont)
The result looks like "a well-made generic tool" rather than "someone's company tool."
Deployment: One-command install with install.sh
#!/bin/bash
PORT=${1:-8099}
INSTALL_DIR="$HOME/.dashboard-lite"
pip3 install flask --quiet
mkdir -p "$INSTALL_DIR"
cp server.py index.html project_tasks.json "$INSTALL_DIR/"
# Register as a systemd user service
cat > ~/.config/systemd/user/dashboard-lite.service << EOF
[Unit]
Description=Dashboard Lite
After=network.target
[Service]
WorkingDirectory=$INSTALL_DIR
ExecStart=python3 $INSTALL_DIR/server.py
Environment=LITE_PORT=$PORT
Restart=always
[Install]
WantedBy=default.target
EOF
systemctl --user daemon-reload
systemctl --user enable --now dashboard-lite.service
echo "Dashboard Lite started at http://localhost:$PORT"
Run bash install.sh 8099 and you're done. As a systemd user service — no root, no sudo required.
Results and Takeaways
| Metric | Original Dashboard | Dashboard Lite |
|---|---|---|
| Backend lines | ~7,000 | ~500 |
| Frontend size | 100KB+ | 37KB |
| Python dependencies | flask, requests, websockets… | flask only |
| External API calls | 5+ endpoints | 0 (local only) |
| Setup steps | Multiple | 1 command |
The question "can this ship as a product?" fundamentally changes how you design code.
Internal tools accumulate under "as long as it works." Anything shipped externally must satisfy "anyone can run this." Bridging that gap takes cutting dependencies and the courage to start over.
Tags
#WebDev #Flask #SPA #Refactoring #ProductDesign #Python #OpenClaw
Top comments (0)