Puntea trimitea doar `content`-ul mesajului; orice atasament disparea tacut, iar
un mesaj fara text (doar poza) era respins ca "empty". Acum mesajul de utilizator
se construieste ca blocuri, in formatul pe care CLI-ul il accepta pe
`--input-format stream-json` (verificat pe CLI real: Claude descrie corect o
imagine trimisa asa).
- imagini png/jpeg/gif/webp -> blocuri `image` base64, max 4, max 3,5 MB brut
(base64 umfla cu ~4/3, iar API-ul refuza peste ~5 MB codate)
- fisiere text (mime `text/*`, `application/json`, sau extensie cunoscuta) ->
continutul intra in prompt, max 4, trunchiat la 100 KB
- restul (PDF, Office, arhive, svg, heic) -> doar numite, cu motivul
Detalii care conteaza:
- `image/jpg` si `image/png; charset=...` se normalizeaza; cand Discord nu
trimite content_type cadem pe extensie
- marimea se verifica de doua ori: cea declarata (ca sa nu descarcam degeaba) si
cea reala dupa descarcare
- nimic nu dispare tacut: ce n-a putut fi citit apare in prompt ca
"Atasamente ignorate: ..."; o imagine stricata nu anuleaza restul mesajului
- merge si mid-tur: o poza trimisa in timpul unui tur intra pe stdin ca steering
31 de teste noi in tests/test_attachments.py (normalizare tipuri, limite,
trunchiere, erori de descarcare, integrare prin punte, steering). Suita: 426 pass.
README: sectiune "Atasamente" + limitarea veche corectata (ramane doar vocea).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4uzvgm7AyJch5WH8QHRhY
Maria raspunde clientilor ERP ROA. Depozitul ei de documente contine doar
material orientat spre client final, dar adaugam si o bariera in SYSTEM_PROMPT:
refuza intrebarile despre servere, Proxmox, containere, IP-uri, baze de date,
parole sau chei, chiar daca ceva de acest fel ajunge in context.
Regula completa (ce are voie sa intre in ~/.maria-bridge/documents/) e scrisa
in /workspace/claude-agent/CLAUDE.md, sectiunea "Maria (RAG) - GRANITA
OBLIGATORIE".
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4uzvgm7AyJch5WH8QHRhY
Ollama (+ nomic-embed-text) is now installed locally on LXC 171 for
embeddings — previously OLLAMA_URL was an unverified placeholder pointing
at nothing. rclone is installed too, but DRIVE_REMOTE still needs a Google
service account the user must create in GCP Console; noted the
document_store folder ID found via Drive search to save that step later.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Drop the standalone maria-dashboard.service — one common panel now
controls both bridges, at the operator's request. discord-bridge's
dashboard/api.py gains a Maria section (fixed-unit start/stop/restart
for maria-whatsapp/maria-rag, WhatsApp status+QR proxy, document CRUD,
reindex, Drive sync trigger, log tail) reached via subprocess/HTTP —
no cross-module imports, to avoid colliding with discord-bridge's own
`config` module name. index.html gets a matching "Maria — WhatsApp +
RAG" section. maria-whatsapp-bridge loses its dashboard/ folder and
DASHBOARD_* env keys; install.sh/README point at the shared panel.
Co-Authored-By: Claude Agent <noreply@anthropic.com>
The unit file lives in ops/ (alongside the other three units), not in
dashboard/ — install.sh linked the wrong path, so `enable --now` for the
dashboard failed silently. Caught by running the installer for real.
Co-Authored-By: Claude Agent <noreply@anthropic.com>
Move the /tmp prototype (Baileys bridge + RAG consumer) into git as a
proper sibling project to discord-bridge/: own systemd --user units
(whatsapp bridge, rag consumer, dashboard, periodic Drive sync timer),
a filesystem document store with a stdlib control dashboard (start/
stop/restart, document CRUD, reindex, Google Drive sync via rclone),
and an idempotent ops/install.sh following the same conventions.
Co-Authored-By: Claude Agent <noreply@anthropic.com>
Trei lucruri observate in logurile de productie dupa restartul precedent.
1. Ecoul propriilor mesaje umplea bot.log cu WARNING. Propriile mesaje au si
ele `author.bot == True`, iar verificarea generica de bot venea INAINTEA
celei pe `self_id` — deci raspunsurile botului se jurnalizau ca "bot
strain", la fiecare mesaj. Verificarea pe `self_id` trece prima (motivul e
acum precis), iar refuzurile de rutina — propriile mesaje si ceilalti boti —
merg la DEBUG. Guild / canal / utilizator strain si webhook raman WARNING:
alea chiar sunt semnal de securitate si erau inecate in zgomot.
2. `tool_progress` (heartbeat la 30s cat timp o unealta ruleaza) devine
eveniment `ToolProgress`. Mesajul live arata acum "⏳ ruleaza de 2m30s" sub
unealta curenta — singurul semn ca un tur lung lucreaza si nu a inghetat.
3. `rate_limit_event` devine eveniment `RateLimit` si apare in `/status` la
randul `utilizare`. Cum nu exista plafon de cost (abonament, nu API),
fereastra de utilizare e singura limita reala; se avertizeaza in log o data
per schimbare de stare, nu la fiecare eveniment.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B29CApsP1JkSdjYaGaHpE7
Confirmarea per comanda devenea obositoare intr-o sesiune care lucreaza pe
acelasi host: `ssh pvemini ...` de zece ori la rand insemna zece butoane.
Butonul de confirmare are acum trei variante: Allow / Allow (tot firul) / Deny.
"Allow (tot firul)" memoreaza tiparul `(rule, reason)` produs de clasificator,
nu comanda: dupa o aprobare pe `ssh pvemini uptime`, orice comanda catre ACEL
host trece singura, dar `ssh 10.0.20.36` sau un `rm -rf` cer din nou
confirmare. Aprobarile stau in ~/.claude-discord/approvals/grants/<fir>.json.
Domeniul e firul Discord, nu `session_id`: acela se schimba la `--resume`, iar
aprobarile ar disparea exact cand omul se astepta sa tina.
Expirare: `/new` le sterge (sesiune noua = permisiuni noi), `/permisiuni
revoca:True` la cerere, TTL implicit 12h (CLAUDE_DISCORD_GRANT_TTL), iar
CLAUDE_DISCORD_SESSION_GRANTS=off dezactiveaza complet mecanismul.
Fail-closed peste tot, ca restul hook-ului: fara CLAUDE_DISCORD_THREAD_ID (hook
rulat in afara puntii), cu fisierul de aprobari corupt, cu un thread_id care nu
arata a id (`../`, punct la inceput, peste 128 de caractere) sau la orice
exceptie, has_grant() raspunde False si se cere confirmare in Discord.
Adaugat si `/permisiuni [revoca:True]` (listare/revocare) plus butonul
echivalent in dashboard (`decision: "allow_session"`).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B29CApsP1JkSdjYaGaHpE7
Costul raportat de CLI e pretul echivalent la API; pe abonament nu se
factureaza, deci plafonul zilnic oprea puntea fara motiv (5.71 / 5.00 USD).
- limits.parse_cap(): `off`/`none`/`nelimitat`/`0`/gol/gunoi => fara plafon
- stopped()/record_cost() nu mai opresc si nu mai alerteaza cand e dezactivat
- implicit devine `off`; /status arata „(fara plafon)"
- dashboard: /api/status si doctor nu mai crapa pe valoare ne-numerica
- README + ops/env.example explica de ce ramane off pe abonament
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B29CApsP1JkSdjYaGaHpE7
Cerut explicit: tokenul nu se retine. Cu DASHBOARD_AUTH=off nu mai exista login,
/login.html duce inapoi la panou, iar butonul "Iesi" dispare.
Se sprijina pe doua lucruri si nu are sens fara ele: serviciul e legat de
127.0.0.1, deci din retea ajunge la el doar tailscaled; iar tailscale serve il
publica tainet only, unde accesul e deja autentificat de Tailscale.
Compensatie partiala pentru ce se pierde: fiecare start/stop/restart se scrie in
logs/dashboard.log cu identitatea din antetul Tailscale-User-Login pus de
tailscale serve (verificat: ajunge pana la noi). Antetul e DOAR pentru jurnal —
nu decide accesul, fiindca un proces local l-ar putea fabrica.
Implicitul ramane cu token: doar off/none/0/false scot login-ul, orice alta
valoare il pastreaza (are test).
Sase teste noi, 41 pe dashboard.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B29CApsP1JkSdjYaGaHpE7
Simptom: pagina se incarca prin tailscale, dar niciun API nu era cerut; in
dashboard.log se vedea doar GET / si nimic altceva.
Cauza: --set-path taie prefixul, deci /claude si /claude/ ajung la server
identic, ca "/". Fara slash final, URL-urile relative se rezolvau la radacina
hostului (https://host/api/status), unde proxy-ul nu trimite nimic incoace.
Cererile nici nu ajungeau la noi, iar pagina ramanea goala fara nicio eroare.
Redirectul 301 adaugat anterior nu putea ajuta: serverul nu vede forma
originala a adresei.
Paginile se servesc acum printr-un handler propriu care pune <base href> din
DASHBOARD_PREFIX, plus Cache-Control: no-store, fiindca HTML-ul poarta de acum
configuratie si o copie veche ar trimite cererile aiurea.
Patru teste noi. Verificat in browser pe cazul reprodus (pagina servita pe
radacina, ca prin proxy): toate cererile pleaca cu /claude/ si datele se incarca.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B29CApsP1JkSdjYaGaHpE7
Pe un ecran de 390px pagina se intindea pe 2621px si derula orizontal. Cauza:
copiii de grid au min-width:auto, deci liniile lungi din pre.log si tabelul de
fire dilatau coloana lui .wrap, si odata cu ea tot documentul. Rezolvat cu
min-width:0 explicit; derularea ramane inauntrul containerelor cu overflow.
Sub 640px:
- tabelul de fire devine carduri stivuite (capul de tabel dispare, eticheta vine
din data-label) — 5 coloane pe 390px insemnau derulare la fiecare rand;
- butoanele stau doua pe rand, cu tinta de atins de 44px; sub 380px, unul pe rand;
- verificarile si confirmarile se aseaza pe verticala, comenzile lungi se rup;
- antetul trece pe doua randuri, notificarile se intind pe toata latimea;
- corpul trece la 16px, ca iOS sa nu mai dea zoom la focus pe input.
Verificat la 360, 390 si 1440px: zero depasiri pe orizontala, butoanele de
confirmare egale si de 44px inaltime, desktopul neschimbat.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B29CApsP1JkSdjYaGaHpE7
https://claude-agent.tailf7372d.ts.net/punte — acelasi tipar ca /echo de pe
moltbot: procesul ramane legat de 127.0.0.1, tailscaled il proxeaza si pune HTTPS.
Montarea sub prefix a cerut doua schimbari:
- toate URL-urile din pagini sunt acum relative, fiindca --set-path TAIE prefixul
inainte de a proxa (serverul vede /api/status, browserul cere /punte/api/status).
DASHBOARD_PREFIX ramane necesar doar pentru redirectul de login, si e acceptat
si intact pe intrare, ca sa mearga si curl direct pe localhost.
- adresa fara slash final (/punte) primeste 301 catre /punte/: altfel URL-urile
relative s-ar rezolva la radacina hostului, unde proxy-ul nu trimite nimic
incoace, si panoul ar arata gol fara nicio eroare vizibila.
ops/install.sh configureaza serve-ul daca sudo permite; altfel spune comanda.
Sase teste noi pentru montarea sub prefix (31 in total pe dashboard).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B29CApsP1JkSdjYaGaHpE7
Panou web pe 127.0.0.1:18790, unit systemd separat de al puntii. Server stdlib
(fara dependinte noi), tokenii de design si tiparul de endpoint-uri preluate din
/home/moltbot/echo-core/dashboard (handlers/eco.py) de pe LXC 110.
Arata: starea unitatii (uptime, PID, memoria cgroup, restarturi), firele din
state.json cu tur in zbor si cost, costul zilei fata de plafon, confirmarile
PreToolUse in asteptare (aprobabile direct din pagina), bot.log / infra.log si
opt verificari de diagnostic.
Face: start / stop / restart pe punte, cautarea si curatarea orfanilor prin
cleanup.py, repornirea propriului serviciu.
Garantii, cu teste:
- unitatea controlata e fixa in cod; un {"unit": "ssh.service"} in cerere nu
schimba nimic, altfel panoul ar fi systemctl remote fara parola;
- stop/restart intorc 409 cu lista firelor active si cer force explicit, fiindca
KillMode=control-group taie tururile in desfasurare;
- state.json se citeste fara lock: panoul nu are voie sa blocheze botul;
- diagnosticul pica daca reapare Bash(ssh:*) in deny (regresia de azi).
Uptime-ul se calculeaza din time.monotonic(), nu din /proc/uptime: in LXC acela
e virtualizat de lxcfs si da diferenta negativa fata de monotonic-ul systemd.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B29CApsP1JkSdjYaGaHpE7
Regulile deny au precedenta peste --permission-mode bypassPermissions si
opresc turul INAINTE de hook-ul PreToolUse, deci puntea nu putea ajunge la
niciun host prin ssh (simptom: agentul raporta "permisiunea a fost respinsa"
pentru ssh moltbot@10.0.20.173, desi cheia, DNS-ul si reteaua erau in regula).
Nota din README care sustinea ca deny e doar strat cosmetic era gresita:
verificarea de atunci folosise /usr/bin/ssh -V si bash -c "ssh -V", care
ocolesc potrivirea pe prefix, nu forma normala ssh host cmd.
Bariera reala ramane confirm_hook.py + wrapper-ul infra.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B29CApsP1JkSdjYaGaHpE7
Doua defecte, al doilea gasit la verificarea primului.
1. Procesul `claude` al unui fir isi porneste serverele MCP (npm/sh/node pentru
playwright), care nu se numesc `claude` si scapau cautarii. Masurat pe firul viu:
claude 300 MB + MCP 137 MB = ~440 MB per fir, nu 300. find_orphans merge acum pe
arbore, iar kill_orphans opreste copiii inaintea parintilor (altfel se reparenteaza
si scapa).
2. PERICULOS: definitia initiala a orfanului ("orice `claude` absent din state.json")
prindea sesiunile Claude interactive de pe container. Rularea seaca propunea 25 de
procese / ~3864 MB — sesiunile de lucru din tmux, inclusiv cea din care ar fi fost
data comanda. `/cleanup force:True` din Discord si-ar fi omorat propria sesiune.
Apartenenta la cgroup-ul `claude-discord.service` devine conditie necesara pentru
toate familiile, fail-closed la cgroup necitibil. Dupa fix: zero procese raportate.
Test de regresie pe instantaneul real (doua sesiuni in tmux-spawn-*.scope, una in
claude-discord.service): se raporteaza doar a treia. Verificat prin mutant ca testul
musca — cu filtrul scos pica 3 teste.
3. INTERFACES.md cerea pid_start_time in ticks, dar session_store scrie secunde (si
state.json viu contine secunde). Contractul era imprecis, nu codul: un consumator
care compara ticks nu s-ar potrivi niciodata, iar cum acea comparatie protejeaza
turul in desfasurare, esecul ar fi fost tacut si ar fi facut eligibil exact ce
trebuia protejat. Documentat, cu avertismentul explicit.
Bug colateral prins de agent: raportul cu rezultate de omorare ajungea la 2289 caractere,
peste limita Discord — mesajul ar fi fost respins exact la `/cleanup force:True`. Buget
de caractere adaugat.
Suita: 322 passed cu discord.py, 319 passed + 3 skipped fara. Rulare seaca pe container: curat.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B29CApsP1JkSdjYaGaHpE7
Comenzile devin application commands inregistrate pe guild (sync instantaneu,
spre deosebire de cel global care dureaza ~1h): /new [fork], /cd <cale>,
/model <sonnet|opus> cu Choice, /status, /stop, /cleanup [force], /help.
- allowlist-ul se aplica identic la interactiuni (check_ids comun, ca sa nu
existe a doua implementare care diverge); refuz efemer, fara executie
- fiecare comanda face defer() inainte de lucru — altfel Discord marcheaza
interactiunea esuata dupa 3s desi comanda a rulat
- sync tolerant: la esec (lipsa scope applications.commands) botul porneste
normal si logheaza linkul de reinvitare necesar
- mesajele obisnuite raman neschimbate, inclusiv steering-ul mid-tur
- linkul de invitatie primeste scope=bot%20applications.commands; referintele
la ! din ops/ si documentatie trecute pe /
Verificat in productie: 7 comenzi inregistrate pe guild, citite inapoi din API.
Suita: 296 passed cu discord.py, 293 passed + 3 skipped fara.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B29CApsP1JkSdjYaGaHpE7
Unitul avea PATH explicit doar pentru CLI-ul claude din nvm. Wrapperul `infra`
se leaga in ~/bin, care lipsea, deci botul nu l-ar fi gasit — stratul 4 de
securitate ar fi fost prezent pe disc si inutilizabil in practica.
Verificat: infra refuza un host din afara listei cu exit 3.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B29CApsP1JkSdjYaGaHpE7
- DEFAULT_CWD trece de la /workspace la /workspace/claude-agent, un spatiu cu git
propriu, ca fisierele facute din Discord sa aiba istoric separat de proiectele
reale. `!cd <cale>` ramane disponibil oriunde in /workspace, deci decizia din
plan (fara allowlist de proiecte) nu se schimba.
- setup_logging: sub systemd unitul redirecteaza deja stdout in bot.log
(StandardOutput=append:), iar FileHandler-ul scria fiecare linie a doua oara
in acelasi fisier. FileHandler ramane doar la rulare manuala.
Verificat in productie: bot conectat, un tur real incheiat curat (inflight null,
cost $0.0742 contabilizat), restart fara orfani. Suita: 275 passed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B29CApsP1JkSdjYaGaHpE7
Application ID 1543576449624186880 (aplicatie dedicata, creata 2026-08-30).
Linkul e util la reinvitare, cand botul a fost scos din server sau i s-au
schimbat permisiunile. Nu e secret: Application ID e public, spre deosebire
de DISCORD_TOKEN.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B29CApsP1JkSdjYaGaHpE7
- permisiunile de invitatie omiteau *View Channel*, fara de care botul nu vede
canalul deloc, oricat de permis ar fi in allowlist
- link de invitatie gata calculat (permissions=309237763136), fiindca bifele din
URL Generator sunt greu de nimerit pe telefon
- *Bot -> Add Bot* nu mai exista: portalul creeaza user-ul bot odata cu aplicatia
- MESSAGE CONTENT INTENT are nevoie de *Save Changes*; fara apasare setarea se pierde
- pasii de copiere ID: pe telefon e apasare lunga, nu click dreapta
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B29CApsP1JkSdjYaGaHpE7
Implementeaza planul claude-master-plan-discord-bridge-20260830 (15 taskuri,
3 lane-uri paralele) — un bot subtire discord.py peste CLI-ul `claude`, cu
proces persistent per fir alimentat pe stdin cu --input-format stream-json.
Nucleu: runner (proces persistent + reaper 20min + respawn --resume), stream
(parser tolerant), session_store (scriere atomica, lock per fir, detectare PID
reuse, recovery), limits (max 4 procese, timeout tur, rate per user, plafon cost
pe zi), render (un loop de editare per canal, interval adaptiv).
Adaptor: allowlist guild/canal/user fail-closed cu respingerea webhook-urilor,
comenzi !new/!cd/!model/!status/!stop/!cleanup, cost si model in subsolul
fiecarui raspuns. Mesajul sosit in timpul unui tur devine steering, nu tur nou.
Securitate: hook PreToolUse fail-closed care cere confirmare in Discord pentru
operatiuni ireversibile, wrapper `infra` cu lista explicita de hosturi. Deny
rules raman strat cosmetic, nu bariera (verificat: /usr/bin/ssh trece pe langa).
Ops: alerte email pe conventia repo-ului, !cleanup pentru orfani, unit systemd
user cu KillMode=control-group si limite de memorie, install.sh idempotent.
Verificat: 275 teste fara retea/Discord/API (10.8s), identic cu si fara
discord.py instalat; e2e pe CLI real confirma steering-ul mid-tur (mesaj la 6s
intr-un tool call de 25s schimba raspunsul final).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B29CApsP1JkSdjYaGaHpE7
Doar line endings, zero modificari de continut (verificat cu
git diff --ignore-cr-at-eol: fara diferente ramase pe aceste fisiere).
Fisierele aveau CRLF comis efectiv in repo, nu doar in working tree.
Sunt scripturi care ruleaza pe Linux (migrarea Oracle, LXC 171 claude-agent),
iar deployate direct din working tree bash le refuza cu
"$'\r': command not found" - exact capcana pe care .gitattributes (comis in
9475842) o previne de acum inainte pentru fisierele noi.
Nu sunt incluse fisierele .md/.sql din roa-windows-setup: acelea au
modificari reale de continut, in curs, si apartin altui commit.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhQBTegE4PiMPPaapLHjkc
LXC 110 (moltbot) a picat dupa un OOM local containerului urmat de reboot:
tailscaled a ramas delogat, iar containerul mostenea resolv.conf-ul Tailscale
de la host-ul pve1 (doar MagicDNS 100.100.100.100) -> rezolutie DNS zero desi
L3 era functional -> echo-core in crash-loop pe telegram.error.TimedOut.
Fixuri aplicate:
- pct set 110 --nameserver '10.0.20.1 1.1.1.1' (elimina dependenta de Tailscale)
- zram-tools pe pve1 (8G zstd, prio 100) - `swap: 4096` din config era fictiv,
host-ul nu avea niciun swap; root pe ZFS deci zram, nu swapfile
- MemoryHigh/MemoryMax pe pocket-tts + supertonic-tts - toate serviciile user
rulau cu limite `infinity`, de unde OOM-uri recurente (Apr 25, May 28 x4)
cu victime aleatorii alese dupa oom_score_adj
Documentatie:
- nou post-mortem in cluster/incidents/, adaugat in indexuri
- README lxc110: host corectat pveelite -> pve1 (+ RAM/CPU/storage reale),
comenzile pct redirectionate spre nodul corect
- README lxc171: tabel cu starea swap pe cele 3 noduri (pveelite are zvol,
nu zram - nu necesita acelasi fix)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Incident 2026-06-24: OOM-uri repetate în cgroup /lxc/171 cauzate de swap
nebacked pe host (pvemini fără swap) + acumulare de forks vscode-server
orfane și sesiuni logind zombie.
- scripts/reap-orphans.sh: reaping conservator (forks ~/.vscode-server
orfane >24h + sesiuni closing cu leader mort), rulat din cron la 6h
- README: secțiune Memorie & OOM (zram pe host ZFS, reaper, diagnostic),
corectat date stale host/RAM/CPU (pvemini, 16GB, 4 cores)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Rename proxmox/claude-agent/ to proxmox/lxc171-claude-agent/
- Move scripts to scripts/ subdirectory
- Add complete installation guide for new LXC from scratch
- Update proxmox/README.md with LXC 171 documentation and navigation
- Add LXC 171 to containers table
- Remove .serena/project.yml
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>