https://claude-agent.tailf7372d.ts.net/claude Redenumire completa: tailscale serve, DASHBOARD_PREFIX, teste, documentatie, ops/install.sh (implicitul pentru instalari noi). Vechiul /punte a fost scos din serve si intoarce 404. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B29CApsP1JkSdjYaGaHpE7
Dashboard de control pentru puntea Discord (LXC 171)
Panou web pentru starea si repornirea puntii, modelat dupa dashboard-ul agentului
echo de pe LXC 110 (/home/moltbot/echo-core/dashboard, port 8088): acelasi tip
de server (stdlib http.server, zero dependinte), aceiasi tokeni de design, acelasi
tipar de endpoint-uri ca in handlers/eco.py.
https://claude-agent.tailf7372d.ts.net/claude <- din tailnet, ca /echo la moltbot
http://127.0.0.1:18790 <- local / prin tunel SSH
Ce arata si ce poate face
| Zona | Continut |
|---|---|
| Serviciu | stare active/running, uptime, PID, memoria cgroup-ului, numarul de restarturi, firele active, costul zilei fata de plafon |
| Butoane | Pornește / Oprește / Repornește puntea, cauta si curata procese orfane (cleanup.py), reporneste dashboard-ul insusi |
| Fire active | ce e in state.json: fir, model, cwd, daca procesul claude traieste, daca are tur in desfasurare, cost |
| Diagnostic | 8 verificari (vezi mai jos), reimprospatate la 30s |
| Confirmari in asteptare | cererile hook-ului PreToolUse — se pot aproba/refuza direct din pagina, nu doar din Discord |
| Jurnal | ultimele 300 de linii din bot.log sau infra.log |
Starea se reimprospateaza automat la 5 secunde.
Decizii de proiectare
O singura unitate controlata. /api/service actioneaza intotdeauna pe
claude-discord.service; numele unitatii nu vine niciodata din cerere. Altfel
panoul ar fi un systemctl remote fara parola pentru tot ce ruleaza sub claude.
Exista un test care trimite {"unit": "ssh.service"} si verifica faptul ca tot
puntea e repornita.
Bind pe 127.0.0.1. Butonul de restart opreste un agent care ruleaza cu
bypassPermissions si are chei SSH catre tot clusterul. Se ajunge la el prin
tunel SSH (mai jos), nu expus in LAN. DASHBOARD_BIND poate schimba asta, dar
atunci tokenul ramane singura bariera.
Restart protejat de tururi in zbor. stop/restart intorc 409 cu lista
firelor care au un tur in desfasurare; interfata intreaba si retrimite cu
force: true doar dupa confirmare. KillMode=control-group din unitul puntii
omoara tot cgroup-ul, deci un restart neatent taie raspunsuri pe jumatate scrise.
Dashboard-ul e un unit separat (claude-discord-dashboard.service), tocmai ca
o repornire a puntii sa nu ia si panoul din care ai apasat butonul. Invers,
/api/restart-self iese cu cod 0 si lasa Restart=always sa-l reporneasca.
Citire fara lock. state.json e citit direct, fara flock: panoul nu are voie
sa blocheze botul. Un JSON prins la mijlocul unei scrieri se ignora si se reia la
urmatorul poll (test: test_state_corupt_nu_arunca).
Verificarile din Diagnostic
- serviciul
claude-discord(stare + numar de restarturi) state.jsoncitibil, cate fire contine- costul zilei fata de
COST_CAP_USD_DAY - spatiu liber pe disc (prag 10%)
- dimensiunea
bot.log(prag 100 MB) - regulile
denydinbot-settings.json— pica daca reapareBash(ssh:*)sauBash(scp:*). Sunt regulile care pe 2026-08-30 au taiat complet accesul puntii la infrastructura:denyare precedenta pestebypassPermissionssi opreste turul inainte de hook (vezi../security/README.md). - prezenta hook-ului de confirmare
- CLI-ul
claudein PATH
Endpoint-uri
Toate cer cookie-ul de sesiune, obtinut cu POST /api/auth/login.
| Metoda | Ruta | Ce face |
|---|---|---|
| GET | /api/status |
serviciu + dashboard + fire + cost + numar de confirmari |
| GET | /api/logs?lines=N&file=bot|infra |
ultimele N linii (plafon 2000) |
| GET | /api/doctor |
verificarile de mai sus |
| GET | /api/approvals |
cererile pending |
| GET/POST | /api/cleanup |
GET = doar cauta; POST {"dry_run": false} = omoara orfanii |
| POST | /api/service |
{"action": "start|stop|restart", "force": bool} |
| POST | /api/approvals/decide |
{"request_id": "...", "decision": "allow|deny"} |
| POST | /api/restart-self |
reporneste dashboard-ul |
| POST | /api/auth/login / /api/auth/logout |
{"token": "..."} / sterge cookie-ul |
Autentificarea e un token din ~/.claude-discord/env schimbat pe un cookie
HttpOnly; SameSite=Strict valabil 30 de zile, comparat cu secrets.compare_digest.
Fara DASHBOARD_TOKEN in env, procesul isi genereaza unul aleator si il scrie in
logs/dashboard.log — nu ramane deschis.
Instalare
ops/install.sh face totul (leaga unitul, genereaza DASHBOARD_TOKEN daca lipseste,
porneste serviciul). Manual:
ln -sfn /workspace/romfastsql/proxmox/lxc171-claude-agent/discord-bridge/dashboard/claude-discord-dashboard.service \
~/.config/systemd/user/claude-discord-dashboard.service
printf 'DASHBOARD_TOKEN=%s\n' "$(python3 -c 'import secrets;print(secrets.token_urlsafe(24))')" >> ~/.claude-discord/env
systemctl --user daemon-reload
systemctl --user enable --now claude-discord-dashboard
Setari optionale in ~/.claude-discord/env: DASHBOARD_BIND (implicit 127.0.0.1),
DASHBOARD_PORT (implicit 18790), DASHBOARD_PREFIX (implicit gol; /claude cand e
publicat prin tailscale serve --set-path).
Acces
Prin Tailscale (recomandat)
Exact tiparul de la echo (https://moltbot.tailf7372d.ts.net/echo/): procesul ramane
legat de 127.0.0.1, iar tailscaled e singurul care ajunge la el si il publica in
tailnet, cu HTTPS si certificat de la Tailscale.
sudo tailscale serve --bg --set-path /claude http://127.0.0.1:18790
tailscale serve status
https://claude-agent.tailf7372d.ts.net/claude
Vizibil doar in tailnet (tailnet only) — nu e funnel, deci nu iese in internet.
Configuratia e persistata de tailscaled, deci supravietuieste repornirilor.
Montarea sub prefix, cele doua capcane si cum sunt rezolvate:
tailscale serve --set-pathtaie prefixul inainte de a proxa, deci serverul vede/api/status, nu/claude/api/status. Toate URL-urile din pagini sunt relative, deci merg la orice prefix, fara sa stie de el.DASHBOARD_PREFIXe nevoie doar pentru redirecturi si e acceptat si intact pe intrare (curldirect pe localhost cu/claude/...functioneaza).- adresa fara slash final (
/claude) ar rezolvaapi/statusla radacina hostului, unde proxy-ul nu mai trimite nimic incoace; de aceea forma fara slash primeste un 301 catre/claude/.
Prin tunel SSH
ssh -L 18790:127.0.0.1:18790 -N claude@10.0.20.171 &
# apoi http://localhost:18790
Tokenul se citeste cu grep DASHBOARD_TOKEN ~/.claude-discord/env.
Teste
cd proxmox/lxc171-claude-agent/discord-bridge
python3 -m pytest tests/test_dashboard.py -q
31 de teste, fara retea si fara systemctl real (dublura inregistreaza apelurile).
Acopera autentificarea, faptul ca unitatea nu poate fi aleasa din cerere, blocajul pe
tur in zbor si trecerea cu force, traversarea de cale in request_id, state.json
corupt, montarea sub prefix (cu si fara slash final) si verificarea de regresie
pentru deny(ssh).