Commit graph

270 commits

Author SHA1 Message Date
54c8d411e8 Legg til tools/ for Claude CLI-verktøy, dokumenter i CLAUDE.md 2026-03-18 01:44:57 +00:00
8c7c0bfff9 Starter oppgave 14.9 2026-03-18 01:43:30 +00:00
86eb54f7ee Spec: Agent API — Claude sitt strukturerte grensesnitt mot maskinrommet 2026-03-18 01:42:22 +00:00
265adea0b3 RSS/Atom-feed (oppgave 14.8): feed-discovery + betinget RSS-lenke
Feeden i rss.rs var allerede implementert med full RSS 2.0 og Atom 1.0
støtte, inkl. podcast-enclosures. Det som manglet var integrasjon med
publiseringstemplates:

- base.html: <link rel="alternate"> for feed auto-discovery (kun når
  samlingen har rss-trait)
- base.html: RSS-lenke i nav vises kun for samlinger med rss-trait
- publishing.rs: has_rss propageres fra CollectionRow gjennom alle
  render-funksjoner til Tera-kontekst
- CAS-rendering (render_article_to_cas, render_index_to_cas) sjekker
  også rss-trait for korrekt template-kontekst

Verifisert: kompilerer, alle 36 tester passerer, feed.xml returnerer
gyldig RSS/Atom, 404 for ukjente slugs, discovery-link i HTML.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 01:42:16 +00:00
71f7264100 Agent leser spec-node via discusses-edge for kontekstuell feedback 2026-03-18 01:40:12 +00:00
88f51dc487 Spec: feature feedback — levende spesifikasjoner med brukertilbakemelding 2026-03-18 01:38:11 +00:00
20b07131da Starter oppgave 14.8 2026-03-18 01:34:57 +00:00
27d0d8db94 Publiseringsflyt i frontend (oppgave 14.7)
Personlig publiseringsflyt for samlinger med publishing-trait der
require_approval: false. Bruker kan publisere artikler fra mottak
til samlingen, og avpublisere ved å fjerne belongs_to-edge.

Backend:
- Nytt delete_edge-endepunkt i maskinrommet med tilgangskontroll
  og automatisk forside-cache-invalidering ved avpublisering

Frontend:
- PublishDialog: forhåndsvisning, slug-editor, tema-info, bekreftelse
- EditorTrait: publiser/avpubliser-knapper på innholdsnoder i
  publiseringssamlinger, velger for upubliserte artikler
- deleteEdge i API-klienten

Docs:
- Oppdatert api_grensesnitt.md med delete_edge, update_edge, set_slot

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 01:33:37 +00:00
703dacd6d0 Lytter-rants: knyttes til podcast (samling), ikke bare episode 2026-03-18 01:29:59 +00:00
a281fcf2fe Utvid audience voice memo: lytter-rants til publiserte episoder + sound pad 2026-03-18 01:29:03 +00:00
7eeee34c74 Legg til fase 19 (spatial canvas) og 20 (universell overføring + panelrework)
Arkitekturskiftet fra "vertikalt stablede traits" til "spatial canvas
med verktøy-paneler" krever:

Fase 19 — Arbeidsflaten:
- Canvas-primitiv (pan/zoom/viewport)
- BlockShell wrapper for alle paneler
- Collection-side rewrite til spatial layout
- Kontekst-header med node-velger
- Snarveier og personlig flate

Fase 20 — Universell overføring:
- message_placements tabell + STDB
- source_material edge-type
- BlockReceiver interface i alle traits
- Transfer service (innholdstransfer + triage)
- Panelrework for Chat, Kanban, Kalender, Editor, Studio

Ref: docs/retninger/arbeidsflaten.md, docs/features/universell_overfoering.md

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 01:28:24 +00:00
ee5a971af5 Starter oppgave 14.7 2026-03-18 01:25:43 +00:00
8a4df2c237 Forside-admin i frontend (oppgave 14.6)
Visuell editor for redaksjonell forside-styring. Rute:
/collection/[id]/forside med tre soner (hero, featured, strøm).

- HTML5 drag-and-drop mellom hero/featured/strøm-plasser
- Pin-knapp per artikkel (forhindrer automatisk fjerning)
- Hurtigknapper for å flytte artikler mellom slots
- Forhåndsvisning via iframe av publisert forside
- Bruker POST /intentions/set_slot API fra maskinrommet
- Sanntidsdata fra SpacetimeDB (belongs_to-edges med slot-metadata)
- PublishingTrait viser nå «Rediger forside»-knapp og publisert-lenke

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 01:24:25 +00:00
9fefa0a8c2 Arbeidsflaten: workspace+tools-modell erstatter vokse-modellen
Ny retning: arbeidsflaten.md — spatial canvas med verktøy-paneler.
Drag-and-drop mellom verktøy oppretter nye noder med source_material-edges.
Noder muterer ikke — de føder nye noder.

Oppdatert docs:
- universell_input.md: "retyping" → "nye noder fra eksisterende"
- rom_ikke_forum.md: "bli" → "føde", siloer → verktøy-paneler
- universell_overfoering.md: blokker → verktøy-paneler, dual-modell
- meldingsboks.md: multi-rolle → visning i flere kontekster

Nye docs:
- arbeidsflaten.md: retning med kompatibilitetsmatrise og inkompatibilitet
- artikkelverktoy.md: langform TipTap-editor med drag-and-drop mottak

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 01:18:35 +00:00
822bcb41d1 Starter oppgave 14.6 2026-03-18 01:17:39 +00:00
141cac9292 Slot-håndtering i maskinrommet (oppgave 14.5)
Ny intention `POST /intentions/set_slot` for redaksjonell
kontroll over forside-slots i publiseringssamlinger.

Håndhever:
- Maks 1 hero: gammel ikke-pinned hero flyttes til strøm
- featured_max: eldste ikke-pinned featured FIFO til strøm
- pinned-flagg beskytter mot automatisk fjerning
- Krever owner/admin-tilgang til samlingen
- Trigger forside-rerendering etter slot-endring

Returnerer liste over displaced edges slik at frontend
kan vise hva som ble flyttet.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 01:16:21 +00:00
6e6e4912c1 Starter oppgave 14.5 2026-03-18 01:10:48 +00:00
82b43a55e9 Caddy-ruting for synops.no/pub → maskinrommet (oppgave 14.4)
synops.no/pub/* proxyes nå til maskinrommet (port 3100) som eier
slug→hash-mappingen og setter Cache-Control-headere:
- Artikler fra CAS: immutable (1 år)
- Dynamisk forside: max-age=index_cache_ttl (default 300s)
- Kategori/arkiv/søk (14.15): kortere TTL når endepunktene kommer

Bruker `handle` (ikke `handle_path`) slik at /pub-prefixet
beholdes — maskinrommets ruter forventer /pub/{slug}/...

Verifisert: Caddy validerer OK, 404 for ukjent slug passerer
korrekt gjennom proxyen med `via: 1.1 Caddy`-header.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 01:09:34 +00:00
72f8bae2fa Starter oppgave 14.4 2026-03-18 01:05:51 +00:00
f537f3dcf3 Forside-rendering med to moduser: statisk CAS og dynamisk in-memory cache (oppgave 14.3)
serve_index støtter nå index_mode fra publishing-trait:
- "static": render_index-jobb rendrer forsiden til CAS ved publisering,
  samlingens metadata.rendered_index.index_hash peker til CAS-fil,
  serveres med Cache-Control: immutable
- "dynamic" (default): in-memory cache med konfigurerbar TTL
  (index_cache_ttl, default 300s), invalidert ved belongs_to-endringer

Tre separate indekserte PG-spørringer erstatter den gamle
alt-i-ett-spørringen — filtrerer på slot i edge-metadata
(hero/featured/strøm) med LIMIT, bruker GIN-indeks.

Trigger-logikk utvidet: belongs_to-edge-opprettelse legger
render_index-jobb i kø (statisk) eller invaliderer cache (dynamisk).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 01:04:31 +00:00
51f49fea22 Legg til fase 17: lydstudio-utbedring (7 oppgaver)
Kodegjennomgang av lydstudio-implementasjonen avdekket:
- Responsivt design mangler (mobil-layout)
- FFmpeg-parametervalidering bør strammes
- Fade/silence-logikkfeil (negativ start, margin-underflow)
- Frontend input-begrensninger mangler
- Job-polling lekker ved navigering
- Temp-filer ryddes ikke ved krasj
- FFmpeg-feilmeldinger når ikke bruker

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 00:55:20 +00:00
2ac0ba5fcb Starter oppgave 14.3 2026-03-18 00:54:18 +00:00
e050612dec HTML-rendering av enkeltartikler til CAS med SEO-metadata (oppgave 14.2)
Implementerer rendering-pipeline: metadata.document (TipTap JSON) → HTML
via Tera-templates → CAS-lagring → metadata.rendered oppdateres.

Nye moduler:
- tiptap.rs: Konverterer TipTap/ProseMirror JSON til HTML. Støtter
  paragraph, heading, blockquote, lister, code_block, image, hr,
  og marks (bold, italic, strike, code, link, underline).
  XSS-sikker med HTML-escaping.

- render_article jobb i jobbkøen: Henter node + samling, konverterer
  document → HTML, rendrer med Tera + tema, lagrer i CAS, oppdaterer
  nodens metadata.rendered med html_hash og renderer_version.

Endringer:
- publishing.rs: SeoData-struct med OG-tags, canonical URL, JSON-LD.
  render_article_to_cas() for full pipeline. serve_article() serverer
  fra CAS (immutable cache) hvis pre-rendret, fallback til on-the-fly.
  RENDERER_VERSION=1 for fremtidig bulk re-rendering.

- intentions.rs: Trigger render_article-jobb automatisk når belongs_to
  edge opprettes til samling med publishing-trait.

- Alle 4 artikkel-templates: SEO-block med meta description, OG-tags
  (type, title, description, url, site_name, image, published_time),
  canonical URL, RSS-link, og JSON-LD structured data.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 00:52:58 +00:00
1cb0d43f21 Legg til fase 16 (lydmixer) i task-runner avhengigheter 2026-03-18 00:49:21 +00:00
b4c4bb8a0f Lydstudio: lydredigering via FFmpeg i nettleseren
Ikke-destruktiv redigering via EDL (Edit Decision List):
- Backend: audio.rs med FFmpeg-subprocess for klipp, normalisering,
  silence trim, fades, noise reduction, EQ, kompressor
- Frontend: /studio/[id] med wavesurfer.js RegionsPlugin,
  verktøypanel, sesjonslagring, og render-dialog
- Studio-trait for samlinger, versjonshistorikk via derived_from-edges
- API: audio_analyze (synkron), audio_process (jobbkø), audio_info

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 00:45:53 +00:00
5d14acf921 Starter oppgave 14.2 2026-03-18 00:43:12 +00:00
4b9f520eab Tera-templates: innebygde temaer for publisering (oppgave 14.1)
Implementerer publiseringsmotoren med fire innebygde temaer:
- Avis: multi-kolonne, informasjonstung, hero+sidebar+rutenett
- Magasin: store bilder, luft, editorial, cards-layout
- Blogg: enkel, én kolonne, kronologisk liste
- Tidsskrift: akademisk, tekstdrevet, nummerert innholdsfortegnelse

Hvert tema har artikkelmal + forside-mal som Tera-templates (Jinja2-like).
CSS-variabler for theme_config-overstyring fra publishing-traiten —
fungerer meningsfullt med bare "theme": "magasin" (null konfigurasjon).

Teknisk:
- publishing.rs: Tera engine, render-funksjoner, DB-spørringer, HTTP-handlers
- Templates innebygd via include_str! (kompilert inn i binæren)
- Ruter: GET /pub/{slug} (forside), /pub/{slug}/{id} (artikkel),
  /pub/{slug}/preview/{theme} (forhåndsvisning med testdata)
- 6 enhetstester for CSS-variabler, rendering og tema-fallback

Ref: docs/concepts/publisering.md § "Temaer"

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 00:41:54 +00:00
260d3d030c Starter oppgave 14.1 2026-03-18 00:33:54 +00:00
51eb089f0c Trait-administrasjon: admin-UI for å administrere traits på samlinger (oppgave 13.4)
Legger til et admin-panel på samlingssiden der man kan legge til/fjerne
traits fra katalogen og konfigurere per-trait-innstillinger. Endringene
sendes via updateNode til maskinrommet som validerer mot VALID_TRAITS.

- Ny updateNode-funksjon i api.ts
- Delt trait-katalog i lib/traits.ts (brukes av collection/new og TraitAdmin)
- TraitAdmin.svelte: toggle traits, rediger config-nøkler, lagre
- Integrasjon i collection/[id] med Traits-knapp i header

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 00:32:31 +00:00
b05b4f6e58 Starter oppgave 13.4 2026-03-18 00:27:29 +00:00
427eae9641 Pakkevelger: UI for ny samling med pakker eller manuelt trait-valg (oppgave 13.3)
Ny side /collection/new med:
- 13 forhåndsdefinerte pakker (nettmagasin, podcaststudio, redaksjon osv.)
  som kort-grid med ikon, beskrivelse og trait-liste
- Manuelt trait-valg med hele trait-katalogen kategorisert i 9 grupper
- Oppsummering med valgte traits og opprett-knapp
- Navigerer til /collection/[id] etter opprettelse

Knapp «Ny samling» lagt til i mottak-headeren.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 00:26:17 +00:00
7079759c24 Starter oppgave 13.3 2026-03-18 00:21:52 +00:00
263f63bec8 Trait-aware frontend: samlingssider med dynamiske trait-paneler (oppgave 13.2)
Samlingsnoder med `metadata.traits` rendres nå som egne sider på
/collection/[id]. Hvert trait-navn mappes til en dedikert Svelte-komponent
som viser relevant UI. Traits uten egen komponent vises med et generisk panel.

Komponenter for 9 traits: editor, chat, kanban, podcast, publishing,
rss, calendar, recording, transcription. Mottak-siden viser traits som
pills og lenker til samlingssiden.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 00:20:35 +00:00
a404751fe4 Starter oppgave 13.2 2026-03-18 00:15:34 +00:00
37cd133e1d Trait-validering for samlingsnoder (oppgave 13.1)
Maskinrommet validerer nå metadata.traits ved create_node og update_node
for collection-noder. Ukjente trait-navn avvises med 400 Bad Request.

Lukket katalog med 48 gyldige traits fra docs/primitiver/traits.md.
Konfigurasjon per trait er fri JSONB — kun nøkkelnavnene valideres.
Noder som ikke er collections valideres ikke (traits ignoreres).

Inkluderer 6 unit-tester for valideringsfunksjonen.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 00:14:21 +00:00
a21da84122 Starter oppgave 13.1 2026-03-18 00:10:25 +00:00
e5c7791dfc Podcast-RSS: samlings-node med publiserings-edges → generert RSS-feed (oppgave 11.4)
Nytt endepunkt GET /pub/{slug}/feed.xml som genererer RSS 2.0 eller
Atom 1.0 feed for samlinger med rss-trait. Feeden er offentlig (ingen auth).

- Slår opp samling via publishing.slug i metadata.traits
- Henter belongs_to-edges (publiserte noder), sortert på publish_at
- Podcast-samlinger (med podcast-trait) inkluderer <enclosure>-tags
  med CAS-URL, MIME-type og filstørrelse fra has_media-edges
- Støtter RSS 2.0 (default) og Atom 1.0 via rss.format config
- iTunes-namespace for podcast-feeds
- Stabile GUID-er basert på node UUID
- 5 min cache (Cache-Control: public, max-age=300)

Manuell XML-generering uten ekstra avhengigheter — enklere enn å
introdusere en RSS-crate for dette omfanget.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 00:09:10 +00:00
da988234dd Starter oppgave 11.4 2026-03-18 00:03:43 +00:00
6d916d9860 Pruning-logikk: TTL per modalitet, signaler, disk-nødventil (oppgave 11.3)
Implementerer automatisk opprydding av CAS-filer basert på dokumentert
spec i docs/retninger/maskinrommet.md:

- TTL per modalitet: lyd 30d, bilde 30d, video 14d, tekst aldri
- Signaler som forlenger levetid: publishing-edge, siste tilgang
  (last_accessed_at), utranskribert lyd beholdes
- Tre-trinns disk-nødventil:
  - >85%: slett generert innhold (TTS osv, kan regenereres)
  - >90%: aggressiv pruning med kraftig redusert TTL
  - >95%: kritisk — alt uten publishing-edge slettes
- Periodisk bakgrunnsloop: hvert 6. time, oftere ved høy disk
- Tilgangslogging: serving oppdaterer last_accessed_at (fire-and-forget)
- Pruning-hendelser logges til resource_usage_log

Ny modul: maskinrommet/src/pruning.rs
Ny migrasjon: 010_pruning.sql (last_accessed_at kolonne + indeks)
CasStore utvidet med delete(), disk_usage_bytes(), disk_usage_percent()

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 00:02:27 +00:00
70fb5eb141 Starter oppgave 11.3 2026-03-17 23:55:59 +00:00
445f32de69 Sanntidslyd: kommunikasjonsnode → LiveKit-rom (oppgave 11.2)
Kobler kommunikasjonsnoder til LiveKit for sanntidslyd.
Bruker sender join_communication-intensjon, maskinrommet validerer
tilgang og returnerer signert LiveKit JWT-token + rom-URL.

Nye komponenter:
- maskinrommet/src/livekit.rs: JWT token-generering (HS256-signert
  med LIVEKIT_API_SECRET, 1-times TTL, publisher/subscriber-roller)
- POST /intentions/join_communication: validerer deltaker-edge,
  genererer token, oppretter rom i STDB, oppdaterer node-metadata
- POST /intentions/leave_communication: fjerner deltaker fra STDB
- POST /intentions/close_communication: stenger rom (krever owner)
- SpacetimeDB: live_room + room_participant tabeller for sanntids
  deltakerliste (frontend abonnerer via WebSocket)

SpacetimeDB-modul publisert som synops-v2 (ny identitet etter
at den opprinnelige ikke lenger var tilgjengelig). .env oppdatert.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 23:54:40 +00:00
5392560807 Starter oppgave 11.2 2026-03-17 23:42:13 +00:00
e95b7d6663 TTS-pipeline: tekst → lyd via ElevenLabs (oppgave 10.4)
Ny jobbtype `tts_generate` som kaller ElevenLabs text-to-speech API,
lagrer MP3-lyd i CAS, og oppretter media-node med has_media-edge.

Voice-preferanse løses i tre lag: eksplisitt i payload → nodens
metadata.voice_preference → ELEVENLABS_DEFAULT_VOICE env.
Dette er "mottaker-preferanse i metadata" — en node kan sette
voice_preference i sin metadata for å styre hvilken stemme som brukes.

Ny migrasjon 009: resource_usage_log-tabell for sporing av
ressursforbruk (TTS, AI, Whisper, CAS). Ref: docs/features/ressursforbruk.md

Endringer:
- maskinrommet/src/tts.rs: TTS-handler med ElevenLabs-integrasjon
- maskinrommet/src/intentions.rs: POST /intentions/generate_tts
- maskinrommet/src/jobs.rs: Dispatcher for tts_generate
- migrations/009_resource_usage_and_tts.sql: resource_usage_log
- scripts/maskinrommet-env.sh: ELEVENLABS_* env-variabler

Krever: ELEVENLABS_API_KEY i /srv/synops/.env (placeholder lagt til)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 23:40:46 +00:00
1803619622 Starter oppgave 10.4 2026-03-17 23:32:29 +00:00
3c1d85026b AI-oppsummering av kommunikasjonsnoder (oppgave 10.3)
Ny jobbtype `summarize_communication` som henter alle meldinger fra
en kommunikasjonsnode, sender dem til LiteLLM for oppsummering, og
oppretter en content-node med sammendraget. Sammendraget knyttes til
kommunikasjonsnoden med `belongs_to`-edge (del av samtalen) og
`summary`-edge (lett å finne sammendrag for en gitt samtale).

API-endepunkt: POST /intentions/summarize { communication_id }
Verifiserer at brukeren er deltaker i samtalen. Jobbprioritiet 3
(bakgrunn). Modell konfigurerbar via AI_SUMMARY_MODEL env-variabel.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 23:31:16 +00:00
b0c037ef71 Starter oppgave 10.3 2026-03-17 23:25:54 +00:00
63f022d739 AI-foreslåtte edges: LLM-analyse av innhold → topics og mentions (oppgave 10.2)
Ny jobbtype `suggest_edges` som automatisk trigges ved opprettelse av
content-noder med tilstrekkelig tekst (≥20 tegn). Sender innholdet til
LiteLLM (sidelinja/rutine) via AI Gateway, parser JSON-respons med
topics og mentions, og oppretter topic-noder + mentions-edges i grafen.

Flyten:
1. create_node oppdager content-node med nok tekst → enqueue suggest_edges
2. Worker henter node-innhold og eksisterende topics fra PG
3. LLM analyserer tekst og returnerer foreslåtte topics/mentions
4. Nye topic-noder opprettes (med ai_generated-flagg i metadata)
5. mentions-edges opprettes fra innholdsnode til topic/entitet-noder
6. Deduplisering: gjenbruker eksisterende topics ved case-insensitivt match

Filer:
- maskinrommet/src/ai_edges.rs: Ny modul med LLM-kall og edge-opprettelse
- maskinrommet/src/jobs.rs: suggest_edges registrert i dispatcher
- maskinrommet/src/intentions.rs: Trigger i create_node
- docs/: Oppdatert jobbkø og AI gateway-docs med ny jobbtype

NB: Krever gyldig API-nøkkel i LiteLLM (OpenRouter/Gemini/Anthropic).
Jobben feiler gracefully med retry+backoff ved manglende nøkkel.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 23:24:29 +00:00
e08a4fd22f Fiks remote-navn: forgejo → origin i task-runner 2026-03-17 23:16:56 +00:00
b498700399 Starter oppgave 10.2 2026-03-17 23:14:11 +00:00
01ad35557f LiteLLM AI Gateway: Docker, DB-ruting, config-generering (oppgave 10.1)
Setter opp AI Gateway med LiteLLM som sentralisert proxy for alle
AI-kall. PG eier all modellkonfigurasjon — LiteLLM er stateløs.

- Migrasjon 008: ai_model_aliases, ai_model_providers, ai_job_routing
  med seed-data for sidelinja/rutine og sidelinja/resonering
- Config-generering fra PG: scripts/generate-litellm-config.sh
  filtrerer bort providers med tomme API-nøkler
- Docker-container kjører på sidelinja-net (intern, ingen eksponert port)
- Maskinrommet har AI_GATEWAY_URL via maskinrommet-env.sh
- API-nøkkel-placeholders i .env (GEMINI, ANTHROPIC, XAI)
- Oppdatert docs/infra/ai_gateway.md med faktisk config

Verifisert: container healthy, modellaliaser eksponert, maskinrommet
har korrekt gateway-URL. Reelle API-kall krever at Vegard fyller
inn leverandør-nøkler i /srv/synops/.env.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 23:12:46 +00:00