Files
panel/CLAUDE.md
T
2026-07-14 23:18:05 -07:00

4.9 KiB

panel

Open-source Go-based game-server management panel (AMP-class). Distributed Controller/Target over gRPC, Docker runtime, CEL-driven automation, 26 game module directories, live dashboard + panelctl CLI. Single static binary per component.

First thing every session

Read the latest memory/changelog_*.md (the file with the most recent date in its name) before doing anything else. Each changelog covers what shipped in a previous autonomous session — bugs, root causes, files touched, and live one-off cleanups that didn't survive a recreate. Skipping this means re-discovering bugs you already fixed last time.

If the user opens with a generic ask ("what should we work on?", "any bugs left over?"), the changelog's "What still needs to happen" tail section is the answer.

Start here

  • README.md — public overview: quickstart, modules, panelctl commands, architecture diagram.
  • memory/ — project-specific deep refs migrated from the user's global auto-memory. Covers repo layout, build commands, module quirks, UX preferences, gotchas. Always start with memory/README.md — it's the index pointing at every other deep ref + every changelog.

Component entrypoints

  • Controller: ./controller/cmd/controller (port 8080 web / 8443 gRPC). Embeds DB migrations, admin bootstrap, static dashboard. Default UI is the Refuge Command Center split assets: static/new.html (shell, 1,723 lines) + static/rcc.js (18,928 lines) + static/rcc.css (5,727 lines), served hash-stamped/immutable. static/index.html (23,982 lines) is the frozen classic UI — opt-in via panel_ui=classic cookie, no new features land there.
  • Agent: ./agent/cmd/agent (any host with Docker; dials controller). Loads modules from ./modules/, talks to local Docker daemon.
  • CLI: ./controller/cmd/panelctlagents | instances | create | start | stop | update | backup | rcon | watch … plus admin <subcommand> (HTTP, see memory/admin_cli.md).

Build + run (dev)

export PATH="/c/Program Files/Go/bin:$PATH"
cd /c/Users/dbled/sources/panel && \
  go build -o /c/Users/dbled/AppData/Local/Temp/controller.exe ./controller/cmd/controller && \
  go build -o /c/Users/dbled/AppData/Local/Temp/agent.exe ./agent/cmd/agent

powershell -Command "Get-Process -Name controller,agent -ErrorAction SilentlyContinue | Stop-Process -Force"
# Then relaunch each (see memory/build.md for full cycle)

Static/HTML/CSS/JS changes for the default UI live in controller/cmd/controller/static/new.html + rcc.js + rcc.css — all embedded via //go:embed, so controller rebuild+restart is required on any change. Do NOT add features to static/index.html; the classic UI is frozen.

Gate before any controller deploy: node controller/.test/gate-parse.mjs — extracts and parses every inline <script> block in static/{new,index,login}.html (a syntax slip blanks the whole dashboard; go build can't catch it because the HTML embeds as opaque bytes). For rcc.js itself, node --check controller/cmd/controller/static/rcc.js. (controller/.test/ui.spec.mjs is the Playwright suite; it has not had a first real run yet.)

Running Go tests: the repo is a go.work multi-module workspace — go test ./... from the root does NOT cover everything. Invoke per module dir explicitly: go test ./controller/... ./agent/... ./pkg/... (or cd into each). Known baseline: 1 pre-existing failure TestDialerForUnknown + 1 go vet copylock nit in agent/internal/dispatch/dispatch.go (PortMap).

Golden rules

  • Never switch buf.gen.yaml to local plugins. Smart App Control blocks locally-built protoc-gen-*.exe. Stay on remote buf plugins.
  • When adding a new Agent→Controller reply type, wire it into BOTH the first switch (type-specific) AND the second case in handleAgentMessage that delivers by correlation ID. Missing the second = silent timeout.
  • Docker image rebuild ≠ container rebuild. Containers pin to image ID at create time. Use Settings → Maintenance → Rebuild container, or the API delete-preserve-volumes + create dance.
  • The module manifest loader uses strict KnownFields(true) (pkg/module/loader.go:22). An old agent binary that doesn't know a new module.yaml key (e.g. ready_pattern, appearance) will REJECT the whole manifest. Ship agent binaries BEFORE or WITH any module.yaml sync that adds new keys.
  • SteamCMD exit 2/5/8 is transient. Already auto-retried in steamcmd.go. Don't surface as a user error.
  • Volumes survive container delete unless purge=true. The Delete button's Danger Zone purges. Keep default purge=false for world safety.
  • User prefers local art over CDN hotlinks, gradients + animations over flat UI, sub-tabs for any config >10 fields, no wrapper headings for single items, transparent retry on flaky externals. Full list in memory/ux_rules.md.