Skip to content

dashboard-proxy.py: PUBLIC_HOST hardcoded to 127.0.0.1, STARTUP_TIMEOUT too short for large trends DBs #28

@namastex888

Description

@namastex888

Context

Running on Linux/Proxmox with the daemon dashboard exposed via Tailscale Funnel/Serve to other tailnet devices. Hit two bugs in the hand-managed dashboard-proxy.py (the network-exposed launcher referenced by dashboard-launcher-network.sh). Documenting here in case anyone else trips on them.

Plugin version: 5.5.0 (cache path: ~/.claude/plugins/cache/alexgreensh-token-optimizer/token-optimizer/5.5.0/).
Proxy file: ~/.claude/plugins/data/token-optimizer-alexgreensh-token-optimizer/data/dashboard-proxy.py.


Bug 1 — PUBLIC_HOST hardcoded to 127.0.0.1 contradicts the launcher's purpose

# dashboard-proxy.py header comment
"""Token Optimizer dashboard network proxy.
Binds 0.0.0.0:24842, spawns the upstream `measure.py dashboard --serve` ...
"""

# ...but at line 30:
PUBLIC_HOST = "127.0.0.1"

The dashboard-launcher-network.sh exists specifically so the daemon can serve the tailnet (vs the default localhost-only dashboard-launcher.sh). The systemd drop-in override is already wired to use it. But because PUBLIC_HOST = "127.0.0.1", the proxy still binds local-only and tailnet/LAN access fails with connection refused.

Repro: setup-daemon on Linux with the network drop-in active → curl http://<tailscale-ip>:24842/token-optimizer returns connection refused even though the proxy script is named "network".

Fix (one-liner): change to PUBLIC_HOST = "0.0.0.0".

Better fix: read from env var so users can choose 0.0.0.0 (default for the network launcher) or a specific bind address (e.g. 100.x.x.x to expose only on Tailscale, not LAN):

PUBLIC_HOST = os.environ.get("TOKEN_OPTIMIZER_DASHBOARD_HOST", "0.0.0.0")

Bug 2 — STARTUP_TIMEOUT = 20.0 is too short once trends DB grows

STARTUP_TIMEOUT = 20.0  # line 32

After accumulating ~520 sessions in the trends SQLite (and especially after a one-time jsonl-trim --apply sweep across all sessions), measure.py dashboard --serve --quiet cold-start takes right around 20s (HTML regeneration is proportional to trends/savings/sessions data). Result: proxy times out, upstream did not bind 127.0.0.1:24843 within 20.0s, daemon enters infinite restart loop, ports flap, dashboard unusable.

Repro:

  1. Run jsonl-trim --apply on all session files (or just accumulate ~500+ sessions naturally)
  2. systemctl --user restart token-optimizer-dashboard.service
  3. Watch stderr.log show "upstream did not bind" repeatedly
  4. Standalone test: time python3 measure.py dashboard --serve --host 127.0.0.1 --port 24850 --quiet → bind ~20s exactly

Fix (one-liner): bump to STARTUP_TIMEOUT = 90.0.

Better fix: env var override + maybe progress polling so it can wait longer when needed:

STARTUP_TIMEOUT = float(os.environ.get("TOKEN_OPTIMIZER_DASHBOARD_TIMEOUT", "90.0"))

Bonus context — daemon-token not auto-created

Slightly related: when the daemon is set up but no full session has yet exercised _get_or_create_daemon_token() (only invoked from setup-daemon and one other callsite), the file ~/.claude/plugins/data/token-optimizer-alexgreensh-token-optimizer/data/daemon-token doesn't exist. /api/token returns {"token":""}, all POST endpoints (/api/skill/archive, /api/v5/toggle, /api/mcp/disable) return 403 "Forbidden: invalid token", dashboard buttons silently fail. Minor — can be worked around by importing _get_or_create_daemon_token once. Worth ensuring daemon startup creates the token if missing.

Happy to PR the env-var version of (1) and (2) if useful.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions