Legger til `synops-ai prompt`-subkommando for enkel prompt-inn/tekst-ut
bruk av LLM via LiteLLM gateway. Eksisterende script-generering
flyttes til `synops-ai script`-subkommando.
Prompt-modus:
- --prompt (påkrevd): bruker-prompt
- --model (valgfri): modellalias, slås opp fra ai_job_routing hvis utelatt
- --system (valgfri): systemprompt
- --job-type: for modelloppslag og logging (default: simple_prompt)
- --temperature: LLM-temperatur (default: 0.7)
- Logger tokenbruk i ai_usage_log
Seed: simple_prompt → sidelinja/rutine i ai_job_routing.
Gjør mindmap til et offisielt trait som kan velges ved opprettelse
av samlingsnoder. Frontend-komponenten (27.1) og BlockShell-panelet
(27.2) var allerede på plass — dette kobler traiten inn i backend-
validering og pakke-definisjoner.
Endringer:
- Lagt til "mindmap" i VALID_TRAITS (intentions.rs)
- Validering av konfig: default_depth 1-3, layout radial/tree
- Inkludert mindmap i Podcaststudio- og Wiki-pakker (traits.ts)
- Oppdatert trait-katalog i docs/primitiver/traits.md
Legger til MindMap-støtte i workspace-siden slik at tankekartet
kan brukes som et fritt plassert BlockShell-panel med fullskjerm,
resize og drag-handle — på linje med alle andre trait-paneler.
Samlingssiden hadde allerede full MindMap-integrasjon fra 27.1.
Workspace-siden manglet import, knownTraits-oppføring og
rendering i både mobil- og desktop-modus.
Ny MindMapTrait-komponent som viser noder og edges fra WebSocket-stores
i radial eller hierarkisk tree-layout via d3-hierarchy.
- Bygger trestruktur fra rotnode med konfigurerbar dybde (1-3 hopp)
- Radial layout (trigonometrisk) og tree layout (hierarkisk) med toggle
- Pan/zoom via d3-zoom, auto-fit ved oppstart
- Klikk node = ny rot (med tilbake-historikk), dobbeltklikk = åpne
- Edge-type-filtrering og visuell stil (farge, stiplet linje)
- Privacy-markering på private noder
- Responsivt: forenklet toolbar på mobil
- Registrert som 'mindmap' trait i katalog og workspace-typer
- Koblet inn i collection-side (desktop BlockShell + mobil tabs)
26.2 er blokkert av SMTP-credentials. Fase 27 (tankekart),
28 (CLI+AI-ruting), 29 (universell input) og 30 (podcast)
avhenger nå av fase 25, ikke 26. Task-runneren kan fortsette.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implementerer synops-mail --send --to <epost> --subject <emne> CLI-verktøy
for utgående epost via msmtp. Alt er ferdig og testet strukturelt:
- tools/synops-mail: Rust CLI som bygger RFC 5322-melding og sender via msmtp
- /srv/synops/config/msmtp/msmtprc: msmtp-konfig mot Hetzner-relay (587/STARTTLS)
- Installert til /usr/local/bin/synops-mail
Blokkert av: mangler SMTP-relay brukernavn/passord. Hetzner-relay
(mail.your-server.de) krever autentisering, port 25 er blokkert utgående.
Trenger credentials i msmtprc for å fullføre.
Legger til username-kolonne i auth_identities med UNIQUE constraint.
Ved innlogging sender SvelteKit preferred_username fra Authentik til
maskinrommet POST /auth/sync, som oppdaterer kolonnen. Grunnlaget
for epost-ruting i fase 26: vegard@synops.no → username-oppslag.
Gjør synops-clip tilgjengelig i orkestreringer ved å:
1. Registrere synops-clip som cli_tool-node (migration 026) med norske
aliases (clip, klipp, hent artikkel) og args_hints for script-kompilatoren.
Orkestreringer kan nå skrive "1. clip fra event (lagre node, bruker)"
som kompileres til "synops-clip --url {event.url} --write --created-by ...".
2. Legge til clip_url som jobbtype i jobbkøen (clip.rs) — spawner
synops-clip med riktige env-variabler (DATABASE_URL, AI_GATEWAY_URL, etc).
3. Legge til POST /intentions/clip_url API-endepunkt slik at frontend
og andre klienter kan trigge URL-klipping direkte.
4. Utvide trigger-konteksten med event.url og event.created_by slik at
orkestreringer som reagerer på URL-deling kan videresende URL til
synops-clip via variabel-substitusjon.
Når en bruker limer inn en URL i chatten, gjenkjenner synops-respond
URL-en automatisk, kaller synops-clip --write for å hente, parse og
oppsummere artikkelen, og inkluderer resultatet i prompten slik at
Claude kan presentere oppsummeringen naturlig.
Ved betalingsmur: Claude informerer brukeren og ber om innlimt innhold.
Maks 3 URL-er per melding, 60s timeout per klipp.
Endringer:
- synops-respond: URL-deteksjon (regex), synops-clip-kall, prompt-kontekst
- maskinrommet/agent.rs: videresend env-variabler for synops-clip
- maskinrommet-env.sh: SYNOPS_CLIP_SCRIPTS env-variabel
- docs/infra/claude_agent.md: dokumentert URL-klipping-flyten
Legger til --write-modus som oppretter:
- content-node med artikkelinnhold og metadata.source_url
- tagged-edge "clipped" (self-tag)
- AI-oppsummering via LiteLLM (integrert i node-innhold)
- mentions-edges til gjenkjente entiteter i kunnskapsgrafen
AI-analysen er robust: feiler den, opprettes noden uten oppsummering.
Gjenbruker eksisterende topic-noder der navnene matcher (case-insensitive).
Nye entiteter opprettes som topic-noder med entity_type i metadata.
Ressursforbruk logges til resource_usage_log.
Nye CLI-flagg: --write, --created-by <uuid>
Payload-JSON utvides med write + created_by for jobbkø-integrasjon.
Nytt verktøy som henter og parser webartikler til ren tekst + metadata.
Bruker Mozilla Readability (via Node.js) for artikkelekstraksjon, med
Playwright som fallback for JS-rendrede sider.
Arkitektur:
- Rust CLI (clap, reqwest) håndterer HTTP-henting, paywall-deteksjon, JSON-output
- Node.js-hjelpeskript (readability.mjs) bruker @mozilla/readability + jsdom
- Playwright-script (playwright.mjs) for headless browser-fallback
- Støtter --payload-json for maskinrommet/jobbkø-integrasjon
Paywall-deteksjon basert på:
- Kort innhold (<200 tegn)
- Norske/engelske paywall-fraser i innholdet
- CSS-klasser/HTML-attributter (piano, schibsted, amedia, etc.)
- Schema.org isAccessibleForFree meta-tagg
Output: JSON med title, author, date, content, url, paywall, excerpt, source
Fem standard-orkestreringer opprettet som seed-data:
- Podcast-pipeline (transkriber → oppsummer → RSS)
- Publiseringsflyt (render → indeks → RSS)
- AI-beriking (foreslå koblinger ved nytt innhold)
- Planlagt publisering (render ved tidspunkt)
- Podcast TTS (kaskade fra pipeline → les opp oppsummering)
Podcast-pipeline → TTS demonstrerer kaskade via triggers-edge.
Script-kompilatoren utvidet med flerords-verbstøtte: aliaser som
"generer feed", "les opp", "foreslå koblinger" matcher nå korrekt
selv om parseren splitter ved første mellomrom. Prøver verb + N
første ord av objekt opptil 3 ord.
8 oppgaver: iTunes/Podcasting 2.0 RSS-tags, nedlastingsstatistikk
(IAB-kompatibel), embed-spiller, import fra eksisterende podcast
med prøveimport-flyt (importer → test → re-importer nye → 301),
og feed-redirect for å flytte bort.
Feature-spec: docs/features/podcast_hosting.md
Ingen castopod — podcasten er noder med riktige edges og en feed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Etter vellykket pipeline-utførelse sjekker handle_orchestrate() om
orkestreringen har utgående triggers-edges til andre orchestration-noder.
Hvert gyldig mål enqueues som ny orchestrate-jobb med kaskade-kontekst.
Syklusdeteksjon via cascade_chain i jobb-payload:
- Sporer alle orchestration-IDer allerede utført i kjeden
- Blokkerer target som allerede finnes i kjeden (direkte + indirekte syklus)
- Dybdegrense på 10 ledd (MAX_CASCADE_DEPTH)
- Blokkerte kaskader logges i orchestration_log med status=skipped
Nedstrøms orkestreringer mottar:
- trigger_event: "cascade"
- upstream_orchestration_id i trigger_context
- {event.upstream_orchestration_id} tilgjengelig i script
Kaskade-feil er ikke-fatale — selve orkestreringen rapporteres som suksess.
8 nye enhetstester for syklusdeteksjon og dybdegrense.
12 oppgaver: skjermklipp, RSS/feed-abonnement, webhook (universell
ekstern input med templates), video-opptak, geolokasjon, håndskrift/
tegning, kalender-import (ICS + CalDAV).
Feature-spec: docs/features/universell_input.md
Prinsipp: modaliteten er transport, noden er det som lever videre.
Alt fra screenshot til GitHub-webhook ender som noder i grafen.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Ny modul script_executor.rs som tar en kompilert pipeline fra
script_compiler og kjører stegene sekvensielt:
- Substituerer {event.*}-variabler fra trigger-kontekst
- Spawner hvert CLI-verktøy som subprosess via generisk dispatch
- VED_FEIL-håndtering: steg-fallback → global fallback → stopp
- Spesialhåndtering av work_item (oppretter oppgave-node i grafen)
- Logger hvert steg i ny orchestration_log-tabell
handle_orchestrate i jobs.rs utvides: kompilerer + utfører i
samme jobb (var tidligere kun kompilering).
Migration 023: orchestration_log-tabell med indekser for
effektiv spørring per orkestrering og per jobb.
Alle eksisterende CLI-verktøy har nå cli_tool-noder i PG med:
- aliases: norske verb for script-kompilatoren ("transkriber", "oppsummer", etc.)
- args_hints: mapping fra menneskelige argumenter til CLI-flagg
("stor modell" → "--model large", "lydfilen" → "--cas-hash {event.cas_hash}")
Muliggjør at script-kompilatoren (24.3) kan slå opp verktøy fra PG
og kompilere menneskelig scriptspråk til faktiske CLI-kall.
Parser menneskelig scriptspråk og kompilerer til tekniske CLI-kall.
"transkriber lydfilen (stor modell)" → "synops-transcribe --cas-hash {event.cas_hash} --model large"
Kompilatoren:
- Parser nummererte steg, ved_feil-fallbacks, og globale feilhåndterere
- Matcher verb mot cli_tool-noders aliases (case-insensitive)
- Mapper argumenter i parentes via args_hints
- Validerer variabelreferanser ({event.*}) mot kjent liste
- Fuzzy-matching med Levenshtein-avstand for forslag ved feil
- Rust-stil kompileringsrapport med ✓/✗ per linje
Integrert i jobbkøen: orchestrate-jobb kompilerer scriptet og
lagrer pipeline i metadata. Utførelse kommer i oppgave 24.5.
12 unit-tester dekker parser, kompilator, feilhåndtering og fuzzy-matching.
Ved node/edge-events fra PG LISTEN/NOTIFY evaluerer portvokteren nå
om noen orchestration-noder matcher triggeren. Implementert som non-blocking
async task som ikke blokkerer WebSocket-flyten.
Ny modul orchestration_trigger.rs:
- Mapper NOTIFY-events til trigger-typer (node.created, edge.created)
- Effektiv lookup via funksjonell B-tree-indeks på metadata->trigger->event
- Evaluerer observes-edges (eksplisitt) vs conditions (implisitt)
- Betingelser: node_kind, edge_type, has_trait, has_tag (AND-logikk)
- Legger matchende orkestreringer i jobbkøen som "orchestrate"-jobb
Ny migration 021: indeks for trigger-event lookup på orchestration-noder.
Jobbkø-dispatcher håndterer "orchestrate" med placeholder (24.3 implementerer utførelse).
Verifisert: content-node trigrer matching orchestration, communication-node hoppes over.
To lag av samme script:
- Menneskelig: "transkriber lydfilen (stor modell)"
- Teknisk: "synops-transcribe --cas-hash {event.cas_hash} --model large"
Kompilator matcher verb mot cli_tool-aliases, argumenter mot
args_hints, variabler fra trigger-kontekst. Rust-stil feilmeldinger.
Tre visninger i editoren (Enkel/Teknisk/Kompilert).
Oppgaver restrukturert: kompilator, alias-metadata, executor,
UI med tre visninger, AI-assistert oppretting, kaskade, seed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Ny node_kind 'orchestration' med strukturert metadata-validering:
- trigger.event valideres mot kjent liste (node.created, edge.created,
communication.ended, node.published, scheduled.due, manual)
- trigger.conditions må være objekt hvis satt
- executor valideres mot script/bot/dream
- intelligence og effort valideres som heltall 1-3
- compiled valideres som boolean
- pipeline valideres som array
Valideringen kjører i både create_node og update_node, identisk
mønster som validate_collection_traits og validate_ai_preset_metadata.
Ref: docs/concepts/orkestrering.md
Validering av fase 22 (SpacetimeDB-migrering) bekrefter:
1. WebSocket-sanntid fungerer:
- maskinrommet lytter på PG NOTIFY-kanaler (node_changed, edge_changed,
access_changed, mixer_channel_changed)
- Enrichment av events med fulle rader fra PG
- Broadcast via tokio::broadcast til WebSocket-klienter
- Tilgangskontroll filtrerer events per bruker
- Frontend kobler til /ws med JWT, mottar initial_sync + inkrementelle events
2. PG LISTEN/NOTIFY-triggere verifisert i database:
- 4 notify-funksjoner: notify_node_change, notify_edge_change,
notify_access_change, notify_mixer_channel_change
- 4 triggere: nodes_notify, edges_notify, node_access_notify,
mixer_channels_notify
3. Ingen STDB-rester i aktiv kode/konfig:
- maskinrommet/src/: rent
- Cargo.toml: ingen spacetimedb-avhengigheter
- docker-compose.yml: ingen spacetimedb-tjeneste
- Caddyfile: ingen spacetimedb-proxy
- Eneste funn: frontend/src/lib/spacetime/ katalognavn —
omdøpt til frontend/src/lib/realtime/ (32 filer oppdatert)
- Historiske referanser i docs/arkiv og scripts/synops.md er OK
7 oppgaver:
- synops-ai: lettvekts LLM-kall via LiteLLM (ikke claude -p)
- AI-rutingskontroll i admin: modell per kontekst, endres uten redeploy
- Kostnadstak per bruker/samling med budsjett-sjekk
- synops-notify, synops-validate, synops-backup, synops-health
Nøkkelprinsipp: admin styrer hvilken modell som brukes til hva.
synops-ai uten --model bruker ai_job_routing-tabellen.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Validering:
- Alle 15 synops-* verktøy kompilerer uten feil
- --help fungerer for alle verktøy med norske beskrivelser
- Feilhåndtering: exit(1) + stderr for alle feiltilfeller
- JSON-output validert (prune, render, node --format json)
- Markdown-output validert (search, context, node --format md)
- XML-output validert (rss)
- synops-common brukes av 14/15 verktøy (db, cas, logging)
- synops-tasks bruker ikke synops-common (som dokumentert)
Funn fikset:
- Installerte manglende binaries i /usr/local/bin: synops-tts,
synops-audio, synops-render (maskinrommet dispatcher fant dem ikke)
Notat: --payload-json (generisk dispatch) er spesifisert i
docs/retninger/unix_filosofi.md men ikke implementert — verktøyene
bruker individuelle CLI-args, og maskinrommet mapper payload→args
i dedikerte dispatcher-moduler. Fungerer korrekt som det er.
3 oppgaver: MindMap Svelte-komponent med radial layout,
BlockShell-panel, og mindmap-trait for samlinger.
Feature-spec i docs/features/tankekart.md.
Ren frontend-visning av eksisterende grafdata — ingen ny backend.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>