synops/docs/concepts/orkestrering.md
vegard 77e3d59b46 Orkestrering: AI kun ved oppretting, eventually-modus for Claude Code
Fundamentalt restrukturert:
- AI genererer script ved oppretting, ikke ved kjøring
- Vaktmesteren validerer script før lagring (verktøy finnes? variabler ok?)
- Systemprompt bygges automatisk fra cli_tool-noder i PG
- Kjøring er alltid deterministisk script, ingen AI
- Feil → work_item, ikke AI-eskalering
- "Eventually"-modus: forespørsel lagres, Claude Code (betalt)
  genererer script i neste sesjon med Opus — ingen API-kostnad,
  bedre kvalitet, ingen hastverk

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 16:40:34 +00:00

15 KiB
Raw Blame History

Konsept: Orkestrering

Filsti: docs/concepts/orkestrering.md

1. Konsept

Orkestreringer er noder som gjør ting. De er oppskrifter — sekvenser av CLI-verktøy som utføres automatisk når en trigger aktiveres. Tre nivåer: deklarativt script (ingen AI), fritekst med AI-tolkning, og full drømmemodus.

2. Hvorfor

Synops har mange automatiseringer hardkodet i vaktmesteren: podcast-pipeline, AI-beriking, publisering. De er usynlige, uendrelige og umulige å tilpasse for brukere.

Orkestreringer gjør automatisering til førsteklasses graf- primitiver — synlige, redigerbare, delbare, versjonerbare.

3. Nodemodell

node_kind: 'orchestration'
title: "Podcast: opptak → publisering"
content: <script eller fritekst>
metadata: {
  "trigger": {
    "event": "communication.ended",
    "conditions": {
      "has_trait": "podcast",
      "has_media": "audio"
    }
  },
  "executor": "script" | "bot" | "dream",
  "intelligence": 2,
  "effort": 2
}

Tre typer noder som gjør

node_kind Ikon Aktivering Eksempel
cli_tool 🔧 Kalles av andre synops-transcribe
ai_preset 🔧 Kalles av AI-verktøy "Rens tekst"-prompt
orchestration Trigger-drevet, utfører seg selv Podcast-pipeline

signaliserer: "denne noden gjør noe av seg selv."

4. Tre utførelsesnivåer

Nivå 1: Deklarativt script (ingen AI)

Eksakte CLI-kall med variabler fra trigger-konteksten. Vaktmesteren parser og eksekverer direkte — ingen LLM.

NÅR innspilling.avsluttet
HVIS samling.har_trait("podcast")

1. synops-transcribe --cas-hash {event.cas_hash} --model large
   VED_FEIL: synops-transcribe --cas-hash {event.cas_hash} --model medium
2. synops-summarize --communication-id {event.communication_id}
3. synops-rss --collection-id {event.collection_id}

VED_FEIL: work_item "Podcast-pipeline feilet" --tag bug

Grammatikk:

TRIGGER    NÅR <event> [HVIS <betingelse>]
STEP       <N>. <tool> <args...>
FALLBACK   VED_FEIL: <tool> <args...> | work_item <title> [--tag <tag>]
VARIABLE   {event.<felt>} — substitueres fra trigger-konteksten

Enkelt nok til å parse med en liten Rust-parser i vaktmesteren. Deterministisk, gratis, raskt. De fleste produksjons- orkestreringer vil være på dette nivået.

Nivå 2: AI-assistert oppretting

Brukeren beskriver hva de vil i naturlig språk. AI genererer et deklarativt script (nivå 1) som vaktmesteren validerer. AI brukes ved oppretting, ikke ved kjøring.

Bruker: "Gjør episoden klar for publisering"

  → synops-ai genererer script-forslag:

    NÅR innspilling.avsluttet
    HVIS samling.har_trait("podcast")
    1. synops-transcribe --cas-hash {event.cas_hash} --model large
       VED_FEIL: synops-transcribe --cas-hash {event.cas_hash} --model medium
    2. synops-summarize --communication-id {event.communication_id}
    3. synops-rss --collection-id {event.collection_id}
    VED_FEIL: work_item "Pipeline feilet" --tag bug

  → Vaktmesteren validerer:
    ✓ Alle verktøy finnes
    ✓ Alle variabler er gyldige
    ✓ Syntaks er korrekt

  → Bruker godkjenner eller justerer
  → Lagres som orchestration-node (nivå 1)

Etter oppretting kjører scriptet uten AI — deterministisk, gratis, raskt. AI-kostnaden er én gang, ved oppretting.

Nivå 3: Drømmemodus

Brukeren skriver hva de ønsker, uten å vite hvilke verktøy som finnes. AI prøver å generere et script, og mangler som oppdages blir feature requests.

Bruker: "Lag en lydfil med sammendrag og send til deltakerne"

  → synops-ai genererer:
    1. synops-summarize --communication-id {event.communication_id}
    2. synops-tts ???  ← finnes ikke

  → Vaktmesteren validerer:
    ✗ synops-tts finnes ikke

  → Tilbake til bruker:
    "Scriptet refererer til synops-tts som ikke finnes.
     Jeg oppretter en forespørsel om TTS-verktøy."
    → work_item "TTS for møteoppsummeringer" --tag feature
    → Delvis script lagres med synops-tts markert som manglende

Systemprompt for script-generering

AI-modellen trenger kontekst for å generere gode scripts. synops-orchestrate --generate-system-prompt bygger dette automatisk fra PG:

Du er en orkestreringsplanlegger for Synops.

TILGJENGELIGE VERKTØY:
- synops-transcribe: Whisper-transkribering
  Bruk: --cas-hash <hash> --model <model>
- synops-summarize: AI-oppsummering
  Bruk: --communication-id <uuid>
- synops-rss: RSS-generering
  Bruk: --collection-id <uuid>
[... hentet fra cli_tool-noder i PG]

SCRIPT-GRAMMATIKK:
  NÅR <event> [HVIS <betingelse>]
  <N>. <tool> <args...>
  VED_FEIL: <tool> <args...> | work_item <title> [--tag <tag>]
  Variabler: {event.<felt>}, {input.<felt>}

EKSEMPLER:
[... hentet fra eksisterende orchestration-noder]

Svar KUN med et gyldig orkestreringscript.

Systemprompt oppdateres automatisk når nye verktøy legges til. Fungerer med alle modeller — Claude, Llama, Mixtral, Grok.

Tre-stegs flyten

1. OPPRETTING (AI, én gang)
   Bruker beskriver → synops-ai genererer script
   → vaktmester validerer → bruker godkjenner → lagres

2. KJØRING (ingen AI, hver gang)
   Trigger → vaktmester parser script → utfører CLI-kall
   → logger resultat

3. FEILHÅNDTERING (AI, sjelden)
   VED_FEIL feiler → eskalér til synops-ai
   → foreslå fix eller opprett work_item

AI-kostnad er nesten null i drift.

Naturlig progresjon

Drømmemodus  → Bruker beskriver ønsket resultat
  ↓ AI genererer script-forslag
Script       → Vaktmester validerer, bruker godkjenner
  ↓ Kjører uten AI
Produksjon   → Deterministisk, gratis, raskt
  ↓ Hvis mønster gjentas
Kode         → Eget CLI-verktøy (synops-<verb>)

AI ved oppretting. Ingen AI ved kjøring. Script kan alltid redigeres manuelt.

5. Strukturert trigger

Triggeren er alltid strukturert — vaktmesteren evaluerer den effektivt uten LLM, uavhengig av utførelsesnivå:

{
  "trigger": {
    "event": "communication.ended",
    "conditions": {
      "has_trait": "podcast",
      "has_media": "audio"
    }
  }
}

Kjente trigger-events

Event Beskrivelse
node.created Ny node opprettet
edge.created Ny edge opprettet
communication.ended Samtale/innspilling avsluttet
node.published Node publisert (belongs_to med slot)
scheduled.due Planlagt tidspunkt nådd
manual Bruker trykker "Kjør"

Betingelser

Filtrerer triggeren ytterligere:

  • has_trait — noden/samlingen har denne traiten
  • has_media — noden har media-edge av denne typen
  • has_tag — noden har tagged-edge med denne verdien
  • node_kind — noden er av denne typen

6. Utførelse

Script-modus (nivå 1)

Trigger aktiveres
  → Vaktmesteren finner matchende orchestration-node
  → Parser scriptet
  → Substituerer {event.*}-variabler fra trigger-kontekst
  → Utfører steg sekvensielt via generisk dispatch
    (synops-{tool} --payload-json)
  → Ved feil: kjør VED_FEIL-steg eller opprett work_item
  → Logger i orchestration_log

Ingen LLM. Deterministisk. Raskt.

Feilhåndtering ved kjøring

Alle orkestreringer kjører som script (nivå 1). Ved feil:

Script kjører steg 2
  → synops-summarize returnerer exit 1
  → VED_FEIL definert? → kjør alternativ
  → Alternativ feiler også?
    → Opprett work_item med feilbeskrivelse
    → Logger i orchestration_log
    → Stopp orkestreringen

Ingen AI-eskalering ved kjøring. Feil håndteres av scriptet (VED_FEIL) eller blir work_items for manuell/AI-assistert oppfølging.

Asynkron modus: "eventually"

Brukeren kan godta at et svar eller script-generering kommer etterhvert i stedet for umiddelbart:

Bruker: "Lag en orkestrering for podcast-pipeline"
  → [Nå] [Eventually]

"Eventually":
  → Forespørselen lagres som work_item med tag "script_request"
  → Neste Claude Code-sesjon (task runner) plukker den opp
  → Genererer script med Opus (full verktøy-tilgang, fillesing)
  → Scriptet valideres og lagres
  → Bruker varsles: "Orkestreringen din er klar"

Fordeler:

  • Ingen API-kostnad — Claude Code (betalt) gjør jobben
  • Bedre kvalitet — Opus med full kontekst, ikke en lettvekts API-modell
  • Ingen hastverk — script-generering trenger ikke skje i sanntid

Dette gjelder også feilhåndtering: et feilet VED_FEIL-steg blir en work_item som Claude Code løser i neste sesjon — reparerer scriptet, legger til manglende verktøy, osv.

7. Koblinger mellom orkestreringer

Orkestreringer er noder med edges:

"Podcast: opptak → publisering"
  ──triggers──→ "Varsle redaksjonen om ny episode"
  ──triggers──→ "Post til sosiale medier"

Output fra én orkestrering kan trigge neste via triggers-edge. Kaskade via edges, ikke hardkodet.

8. Brukergrensesnitt

┌─ Podcastorkestrering ⚡ ──────────────────┐
│                                           │
│  Trigger: [Innspilling avsluttet ▼]       │
│  Betingelse: [Samling har podcast-trait ▼] │
│  Modus: [Script ▼]                        │
│                                           │
│  ┌─────────────────────────────────────┐  │
│  │ NÅR innspilling.avsluttet          │  │
│  │ HVIS samling.har_trait("podcast")   │  │
│  │                                    │  │
│  │ 1. synops-transcribe               │  │
│  │    --cas-hash {event.cas_hash}     │  │
│  │    --model large                   │  │
│  │    VED_FEIL: ... --model medium    │  │
│  │ 2. synops-summarize                │  │
│  │    --communication-id {event.id}   │  │
│  │ 3. synops-rss                      │  │
│  │    --collection-id {event.coll_id} │  │
│  └─────────────────────────────────────┘  │
│                                           │
│  [▶ Test kjøring]    [↑ Konverter til AI] │
│                                           │
│  Status: Aktiv  Kjørt: 47 ganger          │
│  Sist: 2026-03-18 12:30 (OK)             │
│                                           │
│   Tilgjengelig: synops-transcribe,       │
│    synops-rss, synops-render...           │
│    (12 verktøy)                           │
└───────────────────────────────────────────┘

Modusvelger: Script / Fritekst / Drømmemodus. "Test kjøring" utfører med dry-run. "Konverter til AI" løfter scriptet til fritekst-modus.

9. Edge-modell

Edge Source → Target Betydning
belongs_to orchestration → collection Tilhører denne samlingen
observes orchestration → any node Overvåker denne noden for trigger-events
triggers orchestration → orchestration Kaskade-kobling
uses orchestration → cli_tool Bruker dette verktøyet
mentions orchestration → any Refererer til denne noden

observes-edge: eksplisitt kobling

Orkestreringen peker på det den observerer:

"Auto-clip URL-er" (orchestration)
  ──observes──→ #Redaksjonen (communication)
  ──observes──→ #Research (communication)

Legg til observes-edge → aktivert for den noden. Fjern edge → deaktivert. Opprettet via drag-and-drop (se docs/retninger/interaksjonsmodell.md).

Implisitt vs eksplisitt

  • observes-edge: Eksplisitt. "Denne orkestreringen overvåker denne noden."
  • Trigger-betingelser: Implisitt. "Overvåk alt som matcher."
  • observes overtrumfer: fjernet observes-edge betyr "ikke her", selv om betingelsene matcher. Brukeren har kontroll.

10. Drømmemodus: brukeren skriver hva de vil

Brukeren begrenses ikke til kjente verktøy. De skriver fritt — boten prøver, og mangler som oppdages blir feature requests.

Bruker skriver: "Lag en lydfil med sammendrag og send til deltakerne"

Boten sjekker:
  ✓ synops-summarize finnes → oppsummerer
  ✗ synops-tts finnes ikke → kan ikke lage lyd

Boten svarer:
  "Jeg oppsummerte møtet, men Synops har ikke tekst-til-tale
   ennå. Jeg oppretter en forespørsel?"

  → work_item i innboks:
    title: "TTS for møteoppsummeringer"
    tagged: "feature"
    source_material → orkestreringsnoden

Systemet lærer hva brukerne vil ha fra det som ikke lykkes.

11. Prinsipp: målet er alltid script

Enhver orkestrering har som mål å bli et deklarativt script. AI-nivåene (fritekst, drøm) er verktøy for å komme dit, ikke permanente driftsmoduser.

Hvis en orkestrering ikke kan uttrykkes som script, betyr det én av to ting:

  1. Verktøyet mangler. Lag et nytt CLI-verktøy som dekker det manglende steget. Da kan scriptet uttrykke det.
  2. Logikken er for vag. Stram opp instruksjonene til de er presise nok for et script. Hvis det ikke er mulig, er orkestreringen kanskje ikke moden nok for automatisering.

AI som permanent feilhåndtering i en orkestrering er et tegn på at noe er galt — enten med verktøyet eller med spesifikasjonen. Det skal fikses, ikke kompenseres.

Drømmemodus  → "Hva vil vi oppnå?"
Fritekst     → "Hvordan gjør vi det?"
Script       → "Nøyaktig dette."
  ↓
Hvis script ikke er mulig:
  → Mangler verktøy?  → Lag synops-<verb>
  → For vagt?         → Stram opp spec
  → Umulig?           → Ikke automatiser dette

12. Avgrensning

  • Orkestreringer er ikke en generell workflow-engine. De er oppskrifter — deklarative eller AI-tolkede.
  • Deklarativt script er primær for produksjon. AI er for oppretting, feilhåndtering og drømmemodus.
  • Triggere evalueres av vaktmesteren, utførelse av vaktmesteren (script) eller bot (fritekst/drøm).
  • Brukeren begrenses aldri til kjente verktøy. Manglende funksjonalitet fanges opp som feature requests.

13. Komponenter

Feature Rolle
Vaktmesteren Evaluerer triggere, parser/utfører scripts, dispatcher til bot
@bot Tolker fritekst-instruksjoner, utfører med function calling
CLI-verktøy Gjør det faktiske arbeidet
Arbeidstavlen Work items opprettes ved feil
Responskvalitet Intelligence/effort per orkestrering

14. Bygger på

  • docs/retninger/unix_filosofi.md — CLI-verktøy som byggeklosser
  • docs/retninger/interaksjonsmodell.md — drag-and-drop for observes-edge
  • docs/concepts/arbeidstavlen.md — @bot, work items ved feil
  • docs/infra/robusthet.md — function calling, fallback
  • docs/features/responskvalitet.md — intelligence/effort-nivåer