Install
npx skillscat add eltmon/overdeck/pan-dev Install via the SkillsCat registry.
Start Overdeck in Development Mode
Start the dashboard server (Node 22, bundled) and the Vite frontend dev server (HMR on port 3010) for active dashboard development. Traefik, skills sync, and TLDR are started the same as pan up.
When to Use
- User is actively developing the Overdeck dashboard (frontend or server)
- User wants HMR for frontend changes
- User says "start overdeck in dev mode", "pan dev", or "bring up dev"
Prerequisites
- Node 22 available at
~/.config/nvm/versions/node/v22.22.0/bin/node(or in PATH) npm run buildhas been run at least once (server needsdist/dashboard/server.js)node_modulesinstalled in both root andsrc/dashboard/frontend/
Architecture
Browser → https://overdeck.localhost (Traefik)
↓
Vite dev server (port 3010) ── HMR, serves React with hot reload
↓ proxies /api/* and /ws/*
Node 22 server (port 3011) ── Effect API, WebSocket, terminal PTYWhy not Bun for the server? Two hard blockers:
node-ptynative addon exits immediately under Bun (breaks/ws/terminal)- Circular ESM deps in source that Node strict ESM rejects
So the server always runs the pre-built dist/dashboard/server.js under Node 22. After server code changes, rebuild with npm run build:dashboard:server and restart the server process.
The frontend runs via Vite dev server with HMR — changes are reflected instantly without rebuild.
Execution Steps
Step 1: Kill any existing dashboard processes
# Kill existing server and frontend processes
pkill -f "node.*dist/dashboard/server\.js" 2>/dev/null
pkill -f "vite.*3010" 2>/dev/null
# Brief pause for port release
sleep 1Step 1b: Export the dev-mode env var
export OVERDECK_DEV=1This is read by generateOverdeckTraefikConfig() (src/lib/traefik.ts) so the
Traefik dynamic config routes the frontend to Vite (port 3010) instead of the
bundled Node server (3011). Without this, https://overdeck.localhost serves the
production-mode static build and you do not get HMR. Export it before any
subsequent step that may regenerate the Traefik config (notably any pan up orpan install invocation in this shell).
Step 2: Verify ports are free
lsof -i :3010 -i :3011 2>/dev/nullIf ports are still occupied, kill the specific PIDs shown.
Step 3: Run skills sync (same as pan up)
cd ~/Projects/overdeck && pan sync 2>&1 | tail -3Step 4: Start Traefik (if enabled) and regenerate dev-mode config
Check config first:
grep -A2 '\[traefik\]' ~/.overdeck/config.toml 2>/dev/nullIf Traefik is enabled:
cd ~/.overdeck/traefik && docker compose up -d 2>&1Regenerate the Traefik dynamic config in dev mode so the frontend route points
to Vite (3010) instead of the bundled server (3011):
OVERDECK_DEV=1 node -e "
import('~/Projects/overdeck/dist/cli/index.js').catch(()=>{});
import('~/Projects/overdeck/src/lib/traefik.ts').catch(()=>{});
" 2>/dev/null
# Or, more reliably via tsx:
cd ~/Projects/overdeck && \
OVERDECK_DEV=1 npx tsx -e "import('./src/lib/traefik.ts').then(m => m.generateOverdeckTraefikConfig())" 2>&1Verify the rendered file has the frontend on port 3010:
grep 'host.docker.internal' ~/.overdeck/traefik/dynamic/overdeck.yml
# Expected: 3010 (frontend) and 3011 (api). If both show 3011, the regen above
# did not run with OVERDECK_DEV=1; check the env var.Step 5: Rebuild server if needed
If server code has changed since last build:
cd ~/Projects/overdeck && npm run build:dashboard:server 2>&1If unsure, always rebuild — it takes ~2 seconds.
Step 6: Start the API server (background)
cd ~/Projects/overdeck && \
nohup node dist/dashboard/server.js \
> /tmp/overdeck-server.log 2>&1 &
echo "Server PID: $!"Step 7: Wait for server health
for i in $(seq 1 15); do
if curl -s http://localhost:3011/api/health | grep -q ok; then
echo "Server ready"
break
fi
sleep 1
doneStep 8: Start the Vite frontend dev server (background)
cd ~/Projects/overdeck/src/dashboard/frontend && \
nohup npx vite --host 0.0.0.0 --port 3010 \
> /tmp/overdeck-frontend.log 2>&1 &
echo "Frontend PID: $!"Step 9: Wait for frontend and verify
for i in $(seq 1 10); do
if curl -s -o /dev/null -w "%{http_code}" http://localhost:3010 | grep -q 200; then
echo "Frontend ready"
break
fi
sleep 1
doneStep 10: Start TLDR daemon (if .venv exists)
cd ~/Projects/overdeck
if [ -d .venv ]; then
pan admin tldr start 2>/dev/null || echo "TLDR unavailable (non-fatal)"
fiStep 11: Report status
Print:
- Server:
http://localhost:3011(API) - Frontend:
http://localhost:3010(Vite HMR) - Traefik:
https://overdeck.localhost(if enabled, proxies to Vite on 3010) - Server log:
/tmp/overdeck-server.log - Frontend log:
/tmp/overdeck-frontend.log
After Server Code Changes
The server runs pre-built JS, so after editing src/dashboard/server/**:
cd ~/Projects/overdeck && npm run build:dashboard:server
pkill -f "node.*dist/dashboard/server\.js"
nohup node dist/dashboard/server.js \
> /tmp/overdeck-server.log 2>&1 &After Frontend Code Changes
Nothing needed — Vite HMR picks up changes automatically.
Troubleshooting
Vite can't proxy to server
Server isn't running or crashed. Check /tmp/overdeck-server.log.
Terminal panel shows "Reconnecting"
Server is running under wrong runtime. Verify: ps aux | grep server.js should show Node 22, not Bun.
Port 3010 already in use
lsof -i :3010
kill <PID>HMR not working through Traefik
Vite HMR WebSocket needs WSS through Traefik. The vite.config.ts handles this when TRAEFIK_ENABLED=true. Start the Vite server with:
TRAEFIK_ENABLED=true npx vite --host 0.0.0.0 --port 3010Stopping Dev Mode
pkill -f "node.*dist/dashboard/server\.js"
pkill -f "vite.*3010"Or use /pan-down which handles all cleanup.