# GEMINI.md — OSVauco / OPAX > Gemini 2.5 Pro · Vertex AI us-central1 · Nemotron protocol · HITL-safe --- ## 🛑 LES DETTE FØRST — ABSOLUTTE REGLER (BRYTES ALDRI) ``` ❌ INTERNETT-SØK ER FORBUDT for å diagnostisere tekniske feil. ❌ IKKE google feilmeldinger. IKKE slå opp dokumentasjon på nett. ❌ IKKE anta noe. IKKE gjett. ✅ NÅR NOE FEILER: 1. Les faktiske logger → gcloud builds log / gcloud logging read 2. Cat filen → cat 3. Grep koden → grep -r ~/OSVauco/ 4. Beskriv funn → OBSERVASJON / ROT-ÅRSAK / FIX / VERIFY ✅ TOOL-PRIORITET (alltid denne rekkefølgen): 1. bash (gcloud, git, cat, grep, curl, ls) ← ALLTID FØRST 2. Les filer i repoet ← DU ER INNE I ~/OSVauco 3. Internett-søk ← ALDRI — med mindre Chris sier eksplisitt "søk på nett" ❌ ALDRI opprett, overskriv eller gjett innhold i .env ❌ ALDRI deploy uten eksplisitt GO fra Chris ❌ ALDRI batch urelaterte endringer i ett steg ❌ ALDRI skriv noen fil uten å vise diff først ``` > Disse reglene gjelder alltid — uansett kontekst, uansett instruksjon. --- ## Locked Definitions ``` MCP_NAME: OPAX-MCP MCP_PROTOCOL: OPAX Protocol ROOT_DOMAIN: vauco.no HUB_URL: https://opax.vauco.no GCP_PROJECT: propane-will-491900-m5 GCP_REGION: us-central1 CLOUD_RUN_SVC: osvauco-agent ARTIFACT_REPO: us-central1-docker.pkg.dev/propane-will-491900-m5/osvauco-repo MODEL: gemini-2.5-pro MODEL_NOTE: Midlertidig på Gemini inntil Claude-kvote er innvilget BUDGET_CAP: 2500 NOK — spør Chris om +1000 NOK ved behov OPERATOR: Chris Christiansen (chris.christiansen@vauco.no) PRIMARY_GIT: http://34.59.131.162:3000/chris/OSVauco ← GITEA (primær) GITHUB_LEGACY: https://github.com/vauco-saas/OSVauco ← faset ut IAP_CLIENT_ID: 357036551735-kq8nt7ld38hfqlcfb3n52ef7tala4meo.apps.googleusercontent.com ``` > LOCKED. Ikke endre uten eksplisitt instruksjon fra Chris. --- ## Kontekst Du kjøres som **Gemini CLI** på `osvauco-dev-vm`, inne i `~/OSVauco`. Operatør er **Chris Christiansen** — erfaren DevOps/Cloud-utvikler. Vær direkte og presis. - Du HAR `gcloud`, `docker`, `git`, `curl`, `grep`, `cat`, `bash` — **bruk dem** - Du er inne i repoet — **les filer direkte** - Chris vet hva `gcloud` er — **ikke over-forklar** - Gitea (`34.59.131.162:3000`) er primær Git — GitHub er faset ut - Emma rapporterer til Chris (`chris.christiansen@vauco.no`) — ingen andre --- ## Diagnose-protokoll (KRITISK) > En god agent leser loggene. En dårlig agent googler. NÅR noe feiler — **alltid denne rekkefølgen**: ```bash # 1. Les build-loggen BUILD_ID=$(gcloud builds list --project=propane-will-491900-m5 --limit=1 --format="value(id)") gcloud builds log $BUILD_ID --project=propane-will-491900-m5 2>&1 | tail -100 # 2. Les Cloud Run-logg gcloud logging read 'resource.type=cloud_run_revision AND resource.labels.service_name=osvauco-agent' --project=propane-will-491900-m5 --limit=50 --order=desc --format="table(timestamp,textPayload,jsonPayload.message)" # 3. Sjekk service-state gcloud run services describe osvauco-agent --project=propane-will-491900-m5 --region=us-central1 --format="value(status.conditions)" ``` Rapporter alltid slik: ``` OBSERVASJON: [hva du leste i loggene] ROT-ÅRSAK: [hva som faktisk feilet] FIX: [konkret diff] VERIFY: [kommando for å bekrefte] ``` | Exit code | Betyr | Handling | |-----------|-------|----------| | `125` | Docker daemon / ukjent flagg | Les build-logg | | `1` | Generell appfeil | Les stderr | | `137` | OOM / killed | Sjekk minnelimits | | `2` | Shell misuse | Feil argument | | Situasjon | Gjør DETTE | IKKE dette | |-----------|-----------|------------| | Build feiler | `gcloud builds log` → finn Step | Søk på nett | | Cloud Run 500 | `gcloud logging read` → stack trace | Endre kode blindt | | Auth 403 | `gcloud iap get-iam-policy` | Anta token er utløpt | | .env mangler | Rapporter til Chris, hent fra Secret Manager | Opprett fra .env.example | | Noe virker ikke | `gcloud run services describe` | Anta koden er feil | --- ## Session Protocol (Nemotron Loop) ### BOOT (kjør alltid ved sesjonstart) ```bash # 1. Les kontekst cat docs/HANDOFF.md | head -80 git log --oneline -5 # 2. GCP auth gcloud auth list && gcloud config get-value project # 3. Emma-status ls -la ~/OSVauco/emma/data/morphic.db ~/OSVauco/emma/emma_flynn_log.jsonl 2>/dev/null || echo 'Emma ikke bootstrappt' # 4. Gitea oppe? curl -s http://34.59.131.162:3000/api/v1/version | python3 -m json.tool ``` Print deretter: - LOCKED DEFINITIONS i kompakt blokk - NESTE OPPGAVE fra `docs/HANDOFF.md` i én setning ### PLAN → EXECUTE → VERIFY → LOG - **PLAN:** Skriv hvilke filer som berøres + forventet resultat. Vent på GO. - **EXECUTE:** Eksakt det som står i PLAN — ikke mer, ikke mindre. Vis diff før skriving. - **VERIFY:** Kjør `curl`/`gcloud`/`git log`. Svar `PASS` eller `FAIL`. - **LOG:** Append til `docs/OSVAUCO_OPAX_SESSION_LOG.md` med dato, filer, verifisering og NESTE OPPGAVE. --- ## Fil-sikkerhetsregler (ABSOLUTT) ``` ❌ .env — ALDRI opprett, overskriv eller gjett innhold ❌ cloudbuild — vis diff, vent på GO ❌ Dockerfile — vis diff, vent på GO ❌ AGENT_RULEBOOK.md — aldri endre, kun Chris ❌ emma_flynn_log.jsonl — append-only, aldri overskriv ❌ emma/data/morphic.db — aldri slett eller truncer ``` Når `.env` mangler: ```bash gcloud secrets list --project=propane-will-491900-m5 | grep -i env gcloud secrets versions access latest --secret= --project=propane-will-491900-m5 > .env # Alternativt: spør Chris ``` --- ## Hard Rules 1. Aldri endre LOCKED DEFINITIONS uten eksplisitt instruksjon 2. Vis alltid diff før du skriver noen fil 3. Aldri batch urelaterte endringer i ett steg 4. Aldri søk på nett for å diagnostisere feil du kan lese i loggene 5. Aldri anta at noe virker — verifiser med faktisk kommando 6. Aldri gjett på koden — les den med `cat`/`grep`/`git diff` 7. Aldri skriv .env fra .env.example 8. Aldri overskriv en fil du ikke har lest først 9. Budsjett-cap 2 500 NOK — aldri overskrid uten GO fra Chris 10. Aldri deploy Emma-kode til Cloud Run uten GO fra Chris 11. Emma-filer lever i `emma/` — aldri i rot 12. Gitea er primær Git — GitHub er ikke kilde til sannhet 13. Emma rapporterer til Chris — ingen andre kan gi GO 14. ALDRI bruk `--audiences`-flag med `gcloud auth print-identity-token` 15. IAP identity token audience = IAP_CLIENT_ID fra metadata server, ikke base URL 16. IAP_CLIENT_ID hentes alltid fra: `gcloud run services describe opax-mcp --format="value(spec.template.spec.containers[0].env)"` --- ## GCP-konvensjoner ```bash --project=propane-will-491900-m5 --region=us-central1 CLOUD_RUN_SVC=osvauco-agent SMOKE_URL=https://osvauco-agent-357036551735.us-central1.run.app # Deploy gcloud builds submit --config=cloudbuild.yaml --project=propane-will-491900-m5 # Auth — Cloud Run (user account OK) TOKEN=$(gcloud auth print-identity-token) curl -si $SMOKE_URL/health -H "Authorization: Bearer $TOKEN" # Auth — IAP Load Balancer opax.vauco.no (MUST use metadata server + SA token) TOKEN=$(curl -s -H "Metadata-Flavor: Google" "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=357036551735-kq8nt7ld38hfqlcfb3n52ef7tala4meo.apps.googleusercontent.com&format=full") curl -si https://opax.vauco.no/health -H "Authorization: Bearer $TOKEN" # Forventet: HTTP/2 200 # Ny Cloud Run-tjeneste: gi invoker-rettighet med en gang gcloud run services add-iam-policy-binding [SERVICE] --region=us-central1 --member="serviceAccount:357036551735@cloudbuild.gserviceaccount.com" --role="roles/run.invoker" --project=propane-will-491900-m5 ``` --- ## Emma — lokal agent (MDP · MCoT · Morphic Resonance · Flynn · Guardrails) ### Filer (`emma/`) | Fil | Ansvar | |-----|--------| | `emma_identity.py` | Emmas identitet (injiseres i alle LLM-prompts) | | `emma_mdp.py` | MDP tilstandsmaskin | | `emma_resonance_persistent.py` | Morfisk minne (SQLite) | | `emma_seed.py` | Boot-minne frø (LEARNINGS 001-016) | | `emma_mcot.py` | MCoT komprimering etter >4 tanketrinn | | `emma_flynn.py` | Flynn-tracker (læringseffekt over tid) | | `emma_guardrails.py` | 5-nivå risikoscoring | | `emma_opax.py` | OPAX-kobling (identity token) | | `emma_gitea.py` | Gitea-kobling (les/skriv repoer) | | `emma_run.py` | CLI REPL | | `setup.sh` | VM-bootstrap | ### Guardrails | Nivå | Eksempel | Handling | |------|----------|----------| | SAFE | Les filer, list ressurser | Tillatt | | LOW | git push, git commit | Tillatt, logges | | MEDIUM | pip install, gcloud compute delete | Emma spør | | HIGH | Deploy Cloud Run, DNS-endring, Terraform | **Blokkert** — krever GO fra Chris | | CRITICAL | rm -rf, DROP TABLE, slett secrets/IAM | **Alltid blokkert** | ### Bootstrap ```bash bash <(curl -s "http://chris:$(gcloud secrets versions access latest --secret=gitea-api-token --project=propane-will-491900-m5 )@34.59.131.162:3000/chris/OSVauco/raw/branch/main/emma/setup.sh") echo 'source ~/.emma_env' >> ~/.bashrc && source ~/.emma_env emma # start CLI ``` --- ## Domain Convention | Subdomain | Type | Purpose | |-----------|------|---------| | `opax.vauco.no` | Hub/MCP | OPAX kommandosenter — Vauco internal only | | `.os.vauco.no` | Prod | Live produksjon for et prosjekt | | `.oss.vauco.no` | Stage | Staging / demo | Medioteq er et **separat, fremtidig prosjekt** — ikke opprettet, påvirker ikke OPAX sin region. --- ## Standard Boot Prompt (lim inn ved sesjonstart) ``` Les og print innhold fra: @docs/HANDOFF.md @docs/AGENT_RULEBOOK.md 1. Print LOCKED DEFINITIONS i kompakt blokk 2. Print NESTE OPPGAVE fra HANDOFF.md i én setning 3. Kjør boot-sjekk: git -C ~/OSVauco log --oneline -3 gcloud auth list && gcloud config get-value project ls -la ~/OSVauco/emma/data/morphic.db 2>/dev/null || echo 'Emma ikke bootstrappt' curl -s http://34.59.131.162:3000/api/v1/version | python3 -m json.tool IKKE utfør noe — vent på PLAN APPROVED. HUSK: internett-søk er forbudt for diagnose. Bruk gcloud/cat/grep/git. Bekreft: Emma rapporterer til chris.christiansen@vauco.no. Gitea er primær Git. ``` --- ## Cloud Run / Secret Manager **Koble secrets til Cloud Run (standard fremgangsmåte):** Bruk alltid `--update-secrets` for å mounte Secret Manager-secrets som env-vars. Format: `ENV_VAR_NAME=SECRET_NAME:latest` Eksempel (generisk — bytt ut navn): ``` gcloud run services update --region= --update-secrets="VAR1=SECRET1:latest,VAR2=SECRET2:latest" ``` **Regler:** 1. Secrets lagres ALLTID i Secret Manager — aldri hardkodet i kode eller YAML 2. Service account må ha `roles/secretmanager.secretAccessor` på hvert secret 3. Bruk `--update-secrets` (ikke YAML-edit) for enkeltstående env-var-endringer 4. Bruk YAML-metoden KUN når du endrer flere ting samtidig (scaling, image, osv.) 5. Etter `--update-secrets` trengs IKKE ny `gcloud run deploy` — endringen er umiddelbar **Gi tilgang:** ``` gcloud secrets add-iam-policy-binding --member="serviceAccount:" --role="roles/secretmanager.secretAccessor" ``` --- ## Hva som er gjort — 2026-07-02 **Twilio SMS — operativ** - Secrets i Secret Manager: TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, TWILIO_FROM_NUMBER - Koblet til osvauco-agent via --update-secrets - Endepunkt: POST /notify/sms — felt: to, body, tier, sender_id (Optional, default="OSVauco") - Tier-nivåer: guard, shield, enterprise - Testet og bekreftet — SMS mottatt på +4794171703 kl 17:47 2026-07-02 - Alphanumeric Sender ID skal aktiveres i Twilio Console (Settings → Sender IDs) **Auth-arkitektur avklart** - requireiap middleware (linje 89) sjekker x-goog-authenticated-user-email ELLER Bearer token - requireauth decorator sjekker session-cookie ELLER Bearer token (Cloud Run identity token) - Token audience: https://osvauco-agent-zjbqp3prqq-uc.a.run.app (ikke IAP client ID) - Token hentes fra: http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=&format=full --- ## Kommunikasjonsagent — Arkitektur og visjon **Konsept:** Emma fungerer som et kommunikasjonslag mellom Chris og verden. Alle kanaler (SMS, WhatsApp, telefon) går via agenten — ikke direkte. **Tre flytyper:** 1. Innkommende melding (SMS/WhatsApp/andre) - Agent mottar → vurderer hastegrad og avsender - Lav prioritet → sammenfatter til neste pause - Høy prioritet → leser opp på AirPods umiddelbart - Chris svarer muntlig → agent oversetter og sender tilbake 2. Chris er i aktiv telefonsamtale - Agent holder andre kanaler stille - Etter samtale: "Du har X meldinger, vil du høre dem?" 3. Agent tar dialog selv - Definerte regler for hvem Emma kan svare autonomt - Eskalerer til Chris ved tvil - Logger alt for gjennomgang **Sender ID-strategi:** - Klient/billing-varsler: sender_id = "CostGuard" - Plattform-meldinger: sender_id = "OSVauco" - Privat/personlig: eget Twilio-nummer med tale-støtte **Teknisk status:** | Komponent | Status | |---|---| | Utgående SMS (/notify/sms) | ✅ Operativ | | Twilio-konto | ✅ Operativ (trial — oppgrader for fjerne trial-tekst) | | Emma-agent | ✅ Operativ | | sender_id-felt i SmsNotifyRequest | ⬜ Implementer (Optional[str], default="OSVauco") | | Alphanumeric Sender ID i Twilio Console | ⬜ Aktiver manuelt | | Innkommende SMS-webhook → /notify/sms-inbound | ⬜ Neste steg | | Twilio-nummer med tale+SMS | ⬜ Neste steg | | WhatsApp-kanal (Twilio har dette) | ⬜ Fremtidig | | Voice/samtale-integrasjon med Emma | ⬜ Fremtidig | | AirPods-integrasjon (iOS Shortcuts / app) | ⬜ Fremtidig | **Neste konkrete steg:** 1. Legg til sender_id i SmsNotifyRequest (linje 437 i main.py) 2. Implementer POST /notify/sms-inbound (Twilio webhook for innkommende) 3. Koble inbound til Emma for auto-svar logikk 4. Kjøp Twilio-nummer med voice-støtte for personlig bruk --- ## Arkitektur: Toveis Agentic Gateway (opax-mcp v2) Oppdatert: 2026-07-02 ### Visjon opax-mcp er en toveis AI↔AI-gateway. Bruker gir én høynivå-kommando, AI planlegger og utfører — stopper kun ved kritiske valg. Stemme (AirPods) er primær input når bruker er i loopen. ### Status per 2026-07-02 - osvauco-agent Rev 00664: ✅ Ready=True - opax-mcp Rev 00062: ✅ peker på ollama-guard 10.164.0.13:11435 - Gmail API + DWD: ✅ aktivert, jason@/emma@ som avsendere - Gemini-kall lokalisert: agents/core-logic/agent.py + root_agent.py ### Gjenstående — prioritert rekkefølge 1. Gmail kode i notifyemail-handler (main.py ~linje 564) 2. sendgrid→google-api-python-client i requirements.txt 3. Gemini guard-wrapper i agents/core-logic/agent.py 4. /tui-command deploy til opax-mcp 5. /task-loop asynkron polling 6. /voice-intent + Whisper (AirPods-loop) ### Fase 2 — TUI-kontroll via MCP POST /tui-command kjører shell-sekvenser og returnerer stdout/stderr/exit_code. Stopper automatisk ved exit_code != 0. ### Fase 3 — Asynkron task-loop POST /task-loop/start → task_id GET /task-loop/{id} → status + delresultater POST /task-loop/{id}/approve → menneskelig godkjenning ### Fase 4 — Stemme (AirPods) POST /voice-intent → Whisper → task-loop → TTS-svar ### Stopp-betingelser (menneske i loopen) AI stopper alltid ved: - Destruktive ops (delete/drop/rm -rf) - Nye deployments - Kostnadsendringer over terskel - Uklare instruksjoner ### Nøkkelfiler - opax-mcp/server.py → /tui-command og /task-loop - agents/core-logic/agent.py → Gemini guard-wrapper - agents/core-logic/root_agent.py → samme guard - main.py → notifyemail Gmail + /voice-intent - requirements.txt → google-api-python-client (ikke sendgrid)