Files
ttrpg-initiative-tracker/.pi/skills/dev-serve/SKILL.md
T
david raistrick 54e8df9ffa M3: add dev-serve skill (boot stack + headed browser for human testing)
- pkill stale procs, boot backend + frontend in background
- STORAGE=ws default (firebase opt-in)
- agent_browser --headed fresh session for user-visible window
- troubleshooting table + teardown

Skill loads via /skill:dev-serve
2026-06-29 11:24:23 -04:00

4.1 KiB

name, description
name description
dev-serve Boots the TTRPG Initiative Tracker dev stack (Node backend + CRA frontend) for hands-on human testing, then opens a headed browser window the user can see and click. Use when user says "let me test", "open it for me", "give me a browser", "run it locally", "boot the app", or wants to manually use the app. Handles STORAGE mode selection (ws vs firebase), port collision cleanup, background process management, and headed agent_browser launch in one shot.

dev-serve

Run the full app stack for human testing, then open a headed browser window the user can see and drive.

Prerequisites

  • Repo root has server/, shared/, src/ (npm workspaces).
  • Node 18+.
  • Ports 4001 (backend) and 3999 (frontend) free, or let this skill kill stale procs.

Defaults

  • Backend: DB_PATH=/tmp/tracker-dev.sqlite PORT=4001
  • Frontend: REACT_APP_STORAGE=ws (self-hosted backend) unless user asks for firebase. Override: user says "firebase mode" → REACT_APP_STORAGE=firebase + requires .env.local with REACT_APP_FIREBASE_*.
  • Frontend port: 3999. Backend: 4001.

Steps

1. Kill stale procs (idempotent)

pkill -f "node server/index.js" 2>/dev/null
pkill -f "react-scripts start" 2>/dev/null
sleep 2

Do not error if pkill finds nothing.

2. Boot backend (background, log to /tmp)

rm -f /tmp/tracker-dev.sqlite*
DB_PATH=/tmp/tracker-dev.sqlite PORT=4001 nohup node server/index.js > /tmp/tracker-backend.log 2>&1 &
sleep 2
curl -s http://127.0.0.1:4001/health   # must return {"ok":true}

If health fails, tail /tmp/tracker-backend.log, diagnose, fix. Do not proceed.

3. Boot frontend (background, log to /tmp)

REACT_APP_STORAGE=ws \
REACT_APP_BACKEND_URL=http://127.0.0.1:4001 \
REACT_APP_BACKEND_WS=ws://127.0.0.1:4001/ws \
BROWSER=none PORT=3999 nohup npm start > /tmp/tracker-frontend.log 2>&1 &

Wait ~10s, then confirm compile:

grep -E "Compiled successfully|Failed to compile" /tmp/tracker-frontend.log | tail -1

BROWSER=none stops CRA from stealing focus; we open our own headed window.

4. Open headed browser window for user

Use agent_browser tool, fresh session (headed flag is launch-scoped):

{
  "agent_browser": {
    "args": ["open", "http://127.0.0.1:3999", "--headed"],
    "sessionMode": "fresh",
    "timeoutMs": 20000
  }
}

Then snapshot to confirm UI rendered (look for "TTRPG Initiative Tracker" heading + "Create Campaign" button, NOT "Loading campaigns..." after 2-3s).

5. Tell user the URL

App:     http://127.0.0.1:3999   (browser window open)
Backend: http://127.0.0.1:4001
Logs:    /tmp/tracker-frontend.log, /tmp/tracker-backend.log

User can also navigate to that URL in their own browser if they closed the agent_browser window.

Troubleshooting

Symptom Cause Fix
"Loading campaigns..." stuck WS subscribe silent fail Check /tmp/tracker-backend.log for WS connection; check ws.js ensureWs uses .onopen/.onmessage not .on('open')
"Configuration Error" screen firebase mode without .env.local, OR init not gated on STORAGE_MODE Confirm STORAGE=ws; confirm initializeStorage() gates firebase
Port 4001/3999 EADDRINUSE stale proc Rerun step 1
Campaign created but not visible WS broadcast not wired, or path prefix not normalized Check ws.js norm() strips artifacts/.../public/data/
Headed window not on screen remote/VM/headless env --headed only guarantees browser context, not OS visibility; tell user env limitation

Teardown

When user done testing, kill both:

pkill -f "node server/index.js"
pkill -f "react-scripts start"

Or leave running if user continuing dev. Ask which.

Storage mode notes

  • ws (default here): self-hosted backend. Cross-device via backend WS. No Firebase creds needed.
  • firebase: original upstream. Needs .env.local. Behavior identical per characterization tests.
  • memory: in-process, tests only. Resets on reload.

Switching modes mid-session: kill procs, re-export REACT_APP_STORAGE, reboot.