# Deploy: agent-helm på Pi5 via Gitea Actions → registry → Dockge → NPM Flödet: `git push master` → **Gitea Actions-runnern på Pi5** bygger arm64-image:n → pushar till `localhost:5000/agent-helm-server:latest` → **Dockge** kör stacken → **NPM** exponerar `https://rcai.brasse-pc.eu`. Uppdatering = push + klicka *Update* i Dockge. ``` push master ──► gitea-act-runner (bygg arm64) ──► localhost:5000/agent-helm-server:latest │ Dockge: Update (pull + up -d) ▼ container "agent-helm" :8787 (srv_default) ▲ NPM: rcai.brasse-pc.eu ─┘ (Websockets ON, TLS) ``` Förutsättningar som redan är på plats: DNS `rcai.brasse-pc.eu → 155.4.72.51` (✓), `srv_default`-nätet, `docker-registry` och `npm` körs (✓). Gitea 1.24 har Actions påslaget som default. ## Kataloger & ägarskap (gör FÖRE deploy) Bind-mountade kataloger måste finnas och ägas av **uid 1000** *innan* containern startar. Startar containern först skapar Docker katalogen som **root**, och appen (kör som uid 1000 `node`) kan då inte läsa/skriva den. Skapa som `brasse` (= uid 1000): ```bash # data/config för appen (måste vara uid 1000-ägd — appen skriver hit) mkdir -p /srv/docker/agent-helm # runner-state mkdir -p /srv/docker/act-runner # stack-mappar för Dockge mkdir -p /srv/dockge-staks/act-runner /srv/dockge-staks/agent-helm # verifiera ägarskap (ska visa uid 1000 i andra kolumnen) ls -ln /srv/docker | grep -E 'agent-helm|act-runner' ``` Om någon katalog råkat bli root-ägd (t.ex. för att en container startade först): ```bash sudo chown -R 1000:1000 /srv/docker/agent-helm # starta sedan om stacken så mounten läses om ``` --- ## Steg 1 — Registrera Gitea Actions-runnern (engång) 1. **Hämta registrerings-token** i Gitea: `Site Administration → Actions → Runners → Create new runner` → kopiera token. (Eller repo-nivå: `brasse/agent-helm → Settings → Actions → Runners`.) 2. **Skapa stacken i Dockge** (`dockge.brasse-pc.eu`): - Ny stack, namn `act-runner`. - Klistra in `deploy/act-runner.compose.yaml`. - Lägg `deploy/act-runner.config.yaml` som filen `config.yaml` i stacken (Dockge låter dig skapa extra filer i stack-mappen, dvs `/srv/dockge-staks/act-runner/config.yaml`). - I stackens **env**: `GITEA_RUNNER_REGISTRATION_TOKEN=`. - Deploy. 3. **Verifiera**: i Gitea `Site Administration → Actions → Runners` ska `pi5-docker-runner` dyka upp som *Idle*. Loggen: `docker logs gitea-act-runner`. > Runnern monterar värdens `docker.sock` och bygger med Pi5:ans egen Docker → > arm64 nativt, och `localhost:5000` (registryn) trustas automatiskt. --- ## Steg 2 — Första bygget `.gitea/workflows/build.yaml` triggas på push till `master`/`main`. Trigga det: - Pusha en commit till `master`, **eller** - Gitea repo → `Actions` → välj workflowen → `Run workflow` (manuell dispatch). Följ körningen under repo:ts **Actions**-flik. När den är grön finns `localhost:5000/agent-helm-server:latest` i registryn. Snabbkoll (på Pi5, eller via `claude-docker`): ```bash curl -s http://localhost:5000/v2/agent-helm-server/tags/list # -> {"name":"agent-helm-server","tags":["latest",""]} ``` --- ## Steg 3 — Kör stacken i Dockge 1. **Skapa host-katalogen för config/data** (som `brasse`, uid 1000): `mkdir -p /srv/docker/agent-helm` Den bind-mountas till `/app/data` i containern (där framtida db/auth hamnar); containern kör som uid 1000 = `brasse` så filerna blir korrekt ägda. 2. Ny stack i Dockge, namn `agent-helm`. 3. Klistra in `deploy/agent-helm.compose.yaml`. 4. I stackens **env**: `AGENT_HELM_TOKEN=` — en stark slumpad sträng (≥ 32 byte). Förvaras **bara** i stackens `.env` på Pi5, aldrig i git. Det är denna token som skyddar åtkomsten till dina sessioner, så håll den hemlig. 5. Deploy. Kolla i Dockge att containern `agent-helm` är *running*. --- ## Steg 4 — NPM proxy host (manuellt i NPM-UI:t) I `Proxy.brasse-pc.eu` → **Proxy Hosts → Add Proxy Host**: | Fält | Värde | |---------------------|-----------------------------| | Domain Names | `rcai.brasse-pc.eu` | | Scheme | `http` | | Forward Hostname | `agent-helm` | | Forward Port | `8787` | | **Websockets Support** | **PÅ** (viktigt — WS-kanalen) | | Block Common Exploits | valfritt | Under **SSL**: Request a new SSL Certificate (Let's Encrypt) + Force SSL + HTTP/2. Spara. Öppna `https://rcai.brasse-pc.eu` → logga in med `AGENT_HELM_TOKEN`. --- ## Steg 5 — Anslut en daemon (annars finns inga sessioner) Servern är bara control-plane. En **daemon** kör agenten och ansluter till servern. Kör den var du vill (workstation, eller som egen container senare): ```bash # på workstationen, i agent-helm-repot AGENT_HELM_TOKEN= \ SERVER_URL=wss://rcai.brasse-pc.eu \ AGENT_CMD=gemini \ pnpm dev:daemon ``` Daemonen dyker upp som en session i web-UI:t. (Kräver att NPM:s Websockets är på.) --- ## Klienten (daemon) — installera på en Linux-maskin Klienten distribueras som **självständiga binärer** (Node + node-pty inbäddat, inga beroenden på målet) för `linux-x64` och `linux-arm64`, byggda av `.gitea/workflows/release.yaml` och publicerade som **Release-assets** på Gitea. **Skapa en release** (bygger båda arkitekturerna på Pi-runnern): ```bash git tag v0.1.0 && git push origin v0.1.0 # eller: Gitea -> Actions -> release-client -> Run workflow (ange tag) ``` **Installera på valfri Linux-maskin** (Arch, Ubuntu, …) — ett kommando: ```bash curl -fsSL https://gitea.brasse-pc.eu/brasse/agent-helm/raw/branch/main/install.sh | sh ``` Installern detekterar arch, hämtar rätt binär från senaste releasen, lägger `agent-helm` i `/usr/local/bin` (eller `~/.local/bin`), skapar `~/.config/agent-helm/config.env` och en (valfri) systemd-user-service. Sätt token + kör: ```bash ${EDITOR:-nano} ~/.config/agent-helm/config.env # AGENT_HELM_TOKEN, SERVER_URL, AGENT_CMD systemctl --user daemon-reload && systemctl --user enable --now agent-helm # eller direkt: set -a; . ~/.config/agent-helm/config.env; agent-helm ``` Klienten ansluter till `wss://rcai.brasse-pc.eu` och dyker upp som en session i UI:t. ## Strukturerade godkännanden (BeforeTool-hook + kort-vy) Utöver fallback-tangentbordet kan agentens verktygsanrop visas som **godkännande-kort** i UI:t (Tillåt/Neka). Det sker via en `BeforeTool`-hook i Gemini som anropar `agent-helm hook` — samma binär, så inget extra beroende. **Aktivera** genom att lägga till hooken i `~/.gemini/settings.json` på maskinen där klienten kör (justera vid behov efter din Gemini-versions hook-schema): ```json { "hooks": { "BeforeTool": [ { "hooks": [{ "type": "command", "command": "agent-helm hook" }] } ] } } ``` Daemonen skickar automatiskt `AGENT_HELM_HOOK_PORT` till agentens miljö, så `agent-helm hook` hittar den lokala endpointen själv. **Beteende:** - UI anslutet → verktygsanropet visas som kort, agenten väntar på ditt beslut. - Ingen UI / servern onåbar → `AGENT_HELM_HOOK_DEFAULT` (default `allow` — agenten fungerar som utan hook). Sätt `AGENT_HELM_HOOK_DEFAULT=deny` för strikt läge. - Inget svar inom `AGENT_HELM_HOOK_TIMEOUT` (ms) → default-beslutet används. Den lokala hook-endpointen binder **endast** `127.0.0.1` och är aldrig nåbar utifrån. ## Uppdatera till senaste 1. `git push master` → runnern bygger + pushar `:latest`. 2. Dockge → stacken `agent-helm` → **Update** (kör `docker compose pull && up -d`). Det var det — senaste image:n körs. --- ## Felsökning | Symptom | Trolig orsak / åtgärd | |---|---| | Runnern syns inte i Gitea | Fel/förbrukad token. Skapa ny, uppdatera env, redeploy `act-runner`. | | Workflow fastnar på `actions/checkout` | Runnern når inte github för att hämta action:en, eller inte `gitea-d:3000`. Kolla att runnern är på `srv_default`. | | `docker: command not found` i jobbet | Fel job-image. Labeln ska peka på `catthehacker/ubuntu:act-latest`. | | `push` nekas / `http: server gave HTTP response to HTTPS client` | Pusha till `localhost:5000` (inte `192.168.0.19:5000`) från Pi-runnern — localhost trustas som insecure automatiskt. | | `rcai` ger 502 | `agent-helm`-containern nere, eller fel forward-namn/port i NPM. | | WS ansluter inte (UI loggar in men sessioner laddar ej) | Websockets Support av i NPM-hosten. Slå på. | | Bygget kompilerar node-pty och failar | Ska inte hända — Dockerfilen filtrerar bort `daemon`. Om det sker: kontrollera `--filter`-raderna. |