# LXC 171 - Claude Agent (Development Environment) **Director:** `proxmox/lxc171-claude-agent/` **VMID:** 171 **IP:** 10.0.20.171 (intern) | 100.95.55.51 (Tailscale) **Host Proxmox:** pvemini (10.0.20.201) **Rol:** Mediu de dezvoltare izolat pentru Claude Code --- ## Scripturi Disponibile | Script | Descriere | |--------|-----------| | `scripts/start-agent.sh` | Pornește/atașează sesiune tmux "agent" | | `scripts/work.sh` | Meniu interactiv pentru workflow complet | | `scripts/new-task.sh` | Creează branch nou pentru task | | `scripts/finish-task.sh` | Finalizează task (commit + push) | | `scripts/reap-orphans.sh` | Curăță procese vscode-server orfane + sesiuni zombie (cron, anti-OOM) | --- ## Informații Container | Parametru | Valoare | |-----------|---------| | VMID | 171 | | Hostname | claude-agent | | IP intern | 10.0.20.171 | | IP Tailscale | 100.95.55.51 | | Host Proxmox | pvemini (10.0.20.201) | | User | claude | | Storage | local-zfs (32GB) | | RAM | 16GB (swap 8GB — vezi nota OOM mai jos) | | CPU | 4 cores | ## Componente Instalate - Ubuntu 24.04 LTS - Node.js v20.x (via nvm) - Claude Code - tmux - Git (configurat pentru Gitea) - Tailscale ## Conectare ### De pe calculator (rețea internă) ```bash ssh claude@10.0.20.171 ``` ### De pe telefon/exterior (Tailscale) ```bash ssh claude@100.95.55.51 ``` ### VS Code Remote SSH Config în `~/.ssh/config`: ``` Host claude-agent HostName 10.0.20.171 User claude ``` ## Scripturi Workflow ### start-agent.sh Pornește sau se atașează la sesiunea tmux "agent". ```bash ~/start-agent.sh ``` ### work.sh (recomandat) Meniu interactiv pentru workflow complet: - Listează proiectele disponibile în /workspace - Permite crearea de branch-uri noi - Continuarea pe branch-uri existente - Finalizare task (commit + push) - Vizualizare branch-uri ```bash ~/work.sh ``` ### new-task.sh Creează branch nou pentru un task (hardcodat pentru romfastsql). ```bash ~/new-task.sh fix/nume-bug ``` ### finish-task.sh Finalizează task-ul curent (commit + push). ```bash ~/finish-task.sh ``` ## Workflow Complet ### De pe telefon (JuiceSSH + Tailscale) 1. Conectează-te la `100.95.55.51` cu user `claude` 2. Rulează: ```bash ~/start-agent.sh # pornește tmux ~/work.sh # meniu interactiv ``` 3. Alege proiectul 4. Alege acțiunea (task nou / continuă / finalizează) 5. Lucrează cu Claude Code 6. Când termini: `~/work.sh` → opțiunea 3 (finalizează) ### De pe calculator (VS Code) 1. VS Code → Remote SSH → `claude-agent` 2. Open Folder → `/workspace/` 3. Terminal → `source ~/.nvm/nvm.sh && claude` ## Structura Directoare pe LXC ``` /home/claude/ ├── .ssh/ │ ├── authorized_keys # Chei SSH pentru acces │ ├── gitea_ed25519 # Cheie pentru Gitea │ └── config # Config SSH pentru Gitea ├── .nvm/ # Node Version Manager ├── .claude/ │ └── settings.json # Permisiuni Claude Code ├── .tmux.conf # Configurare tmux ├── start-agent.sh -> /workspace/start-agent.sh └── work.sh -> /workspace/work.sh /workspace/ ├── start-agent.sh # Script pornire tmux ├── work.sh # Script workflow interactiv ├── new-task.sh # Script creare branch ├── finish-task.sh # Script finalizare task ├── CLAUDE.md # Info agent ├── SETUP-COMPLETE.md # Documentație setup ├── romfastsql/ # Proiect clonat └── test/ # Alte proiecte ``` ## Comenzi tmux Utile | Comandă | Acțiune | |---------|---------| | `Ctrl+A, d` | Detașare din sesiune | | `Ctrl+A, c` | Fereastră nouă | | `Ctrl+A, n` | Fereastră următoare | | `Ctrl+A, p` | Fereastră anterioară | | `Ctrl+A, [` | Mod scroll (q pentru ieșire) | | `tmux attach -t agent` | Reatașare la sesiune | | `tmux ls` | Listare sesiuni | ## Git / Gitea ### Clonare proiect nou ```bash cd /workspace git clone git@gitea.romfast.ro:romfast/.git ``` ### Workflow branch-uri ```bash git checkout main git pull git checkout -b feature/nume-feature # ... lucrezi ... git add . git commit -m "descriere" git push -u origin feature/nume-feature # Creează Pull Request în Gitea ``` ## Memorie & OOM (reaping orfane + zram) ### Context (incident 2026-06-24) Containerul a generat OOM-uri repetate, izolate în cgroup-ul `/lxc/171` (NU la nivel de host — host-ul avea memorie liberă). Cauzele combinate: 1. **Swap fictiv:** LXC 171 are `memory: 16384` + `swap: 8192`, dar host-ul **pvemini nu avea swap deloc** → swap-ul containerului nu era backed de nimic. La atingerea celor 16GB se intra direct în OOM-kill, fără să poată face swap-out. Victimele tipice erau procese mici cu `oom_score_adj` ridicat (`systemd`, `dbus-daemon`, `at-spi-bus-laun`, `sd-pam`) din sesiunile `user@1000`. 2. **Acumulare de fond:** forks `~/.vscode-server` (servere VS Code Remote-SSH) rămase orfane după ce conexiunea SSH moare — reparentate la init (PPID=1), vechi de zile — plus sesiuni `systemd-logind` blocate în stare `closing`. Un spike ocazional de Chromium/Playwright împingea totalul peste 16GB → OOM. ### Fix 1 — zram swap pe host (pvemini) Root-ul pvemini e pe **ZFS**, deci **NU** se folosește swapfile (risc de deadlock). În loc, zram (swap comprimat în RAM): ```bash # pe pvemini (host) apt install -y zram-tools cat > /etc/default/zramswap <<'EOF' ALGO=zstd SIZE=8192 PRIORITY=100 EOF systemctl restart zramswap.service # enabled persistent la boot zramctl; swapon --show # verificare: /dev/zram0 8G zstd ``` Acum cei 8GB `swap` din configul LXC 171 au backing real → vârfurile tranzitorii fac swap-out în loc de OOM-kill instant. ### Fix 2 — reaping orfane (`scripts/reap-orphans.sh`, cron în 171) Script conservator care rulează ca root **în interiorul containerului**, la fiecare 6 ore: - omoară forks `~/.vscode-server` reparentate la init (PPID=1) **și** mai vechi de 24h (conexiune SSH moartă); - termină sesiunile `logind` în stare `closing` cu leader mort (`leader=0`). Exclude explicit daemonul de bază `/usr/lib/code-server` (lansat de ttyd) și procesele Claude Code (pot fi task-uri lungi legitime). Log în `/var/log/reap-orphans.log`. ```bash # instalare în container (din host) pct push 171 reap-orphans.sh /usr/local/sbin/reap-orphans.sh # sau deploy manual pct exec 171 -- chmod +x /usr/local/sbin/reap-orphans.sh # cron: /etc/cron.d/reap-orphans -> 0 */6 * * * root /usr/local/sbin/reap-orphans.sh # rulare manuală + verificare pct exec 171 -- /usr/local/sbin/reap-orphans.sh pct exec 171 -- tail /var/log/reap-orphans.log ``` > ⚠️ **NU** folosi `loginctl terminate-session` pe sesiuni `closing` care au `leader != 0` — > acelea pot fi sesiuni VS Code remote active de lucru. Doar zombiile cu `leader=0` sunt > sigure (asta verifică și scriptul automat). ### Diagnostic rapid OOM ```bash # pe host: confirmă că OOM e în cgroup-ul containerului, nu pe host ssh root@10.0.20.201 "journalctl -k --since '1 hour ago' | grep -iE 'oom_memcg|Killed process'" cat /sys/fs/cgroup/lxc/171/memory.events # oom / oom_kill counters cat /sys/fs/cgroup/lxc/171/memory.current # consum curent vs memory.max (16G) # în container: top consumatori + orfani + sesiuni pct exec 171 -- bash -c "ps -eo pid,ppid,etimes,rss,comm --sort=-rss | head -20" pct exec 171 -- loginctl list-sessions ``` --- ## Troubleshooting ### Claude Code nu pornește ```bash source ~/.nvm/nvm.sh which claude claude --version ``` ### tmux nu găsește sesiunea ```bash tmux ls tmux new -s agent -c /workspace ``` ### Git clone eșuează ```bash # Testează conexiunea SSH la Gitea ssh -T git@gitea.romfast.ro ``` ### Tailscale nu funcționează ```bash sudo systemctl status tailscaled sudo tailscale status tailscale ip ``` ## Instalare Claude Code pe LXC nou (de la zero) ### 1. Creare LXC în Proxmox ```bash # Pe Proxmox host (ex: pveelite) pct create local:vztmpl/ubuntu-24.04-standard_24.04-2_amd64.tar.zst \ --hostname claude-agent \ --memory 4096 \ --cores 2 \ --rootfs local-zfs:32 \ --net0 name=eth0,bridge=vmbr0,ip=dhcp \ --features nesting=1 \ --unprivileged 1 pct start pct enter ``` ### 2. Setup sistem (ca root în LXC) ```bash # Update și pachete de bază apt update && apt upgrade -y apt install -y curl git tmux sudo # Creare user claude useradd -m -s /bin/bash claude echo "claude ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/claude passwd claude # setează parola # Creare /workspace mkdir -p /workspace chown claude:claude /workspace ``` ### 3. Setup user claude ```bash su - claude # Instalare nvm + Node.js curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash source ~/.bashrc nvm install 20 nvm use 20 nvm alias default 20 # Instalare Claude Code npm install -g @anthropic-ai/claude-code # Verificare claude --version ``` ### 4. Configurare Claude Code ```bash mkdir -p ~/.claude cat > ~/.claude/settings.json << 'EOF' { "permissions": { "allow": [ "Bash(git *)", "Bash(npm *)", "Bash(node *)", "Read", "Write", "Edit" ], "deny": [] } } EOF ``` ### 5. Configurare tmux ```bash cat > ~/.tmux.conf << 'EOF' set -g prefix C-a unbind C-b bind C-a send-prefix set -g mouse on set -g history-limit 50000 set -g default-terminal "screen-256color" EOF ``` ### 6. Configurare Git + SSH pentru Gitea ```bash # Generare cheie SSH ssh-keygen -t ed25519 -f ~/.ssh/gitea_ed25519 -N "" # Config SSH cat > ~/.ssh/config << 'EOF' Host gitea.romfast.ro HostName gitea.romfast.ro User git IdentityFile ~/.ssh/gitea_ed25519 IdentitiesOnly yes EOF chmod 600 ~/.ssh/config # Afișează cheia publică (adaug-o în Gitea → Settings → SSH Keys) cat ~/.ssh/gitea_ed25519.pub # Config Git git config --global user.name "Claude Agent" git config --global user.email "claude@romfast.ro" git config --global init.defaultBranch main ``` ### 7. Instalare scripturi workflow ```bash cd /workspace # Copiază scripturile din acest repo (de pe mașina locală) # SAU creează-le manual conform secțiunii "Scripturi Disponibile" # Creare symlink-uri ln -s /workspace/start-agent.sh ~/start-agent.sh ln -s /workspace/work.sh ~/work.sh chmod +x /workspace/*.sh ``` ### 8. (Opțional) Instalare Tailscale ```bash curl -fsSL https://tailscale.com/install.sh | sh sudo tailscale up # Autentifică-te cu contul Tailscale tailscale ip # notează IP-ul ``` ### 9. Clonare proiecte ```bash cd /workspace git clone git@gitea.romfast.ro:romfast/romfastsql.git # alte proiecte... ``` ### 10. Test final ```bash ~/start-agent.sh # În tmux: source ~/.nvm/nvm.sh claude --version ~/work.sh ``` ### Copiere rapidă scripturi (dacă ai alt LXC configurat) ```bash # De pe mașina locală scp proxmox/lxc171-claude-agent/scripts/*.sh claude@:/workspace/ ssh claude@ "chmod +x /workspace/*.sh && ln -sf /workspace/start-agent.sh ~/start-agent.sh && ln -sf /workspace/work.sh ~/work.sh" ``` --- ## Legături Utile - **Proxmox Index:** `../README.md` - **Gitea:** https://gitea.romfast.ro --- **Data setup:** 2025-12-31 **Ultima actualizare:** 2026-06-24 (zram swap pvemini + reap-orphans cron, anti-OOM)