SpacetimeDB er nå helt fjernet fra Synops. Sanntid håndteres av PG LISTEN/NOTIFY + WebSocket i portvokteren (maskinrommet). Kode fjernet: - spacetimedb/ Rust-modul og spacetime.json - maskinrommet/src/stdb.rs (HTTP-klient for STDB-reducers) - frontend module_bindings/ (23 auto-genererte filer) - spacetimedb npm-avhengighet fra package.json - scripts/test-sanntid.sh (testet STDB-flyt) Infrastruktur: - Docker-container stoppet og fjernet fra docker-compose.yml - Caddy: fjernet /spacetime/* reverse proxy - maskinrommet-env.sh: fjernet STDB_IP og SPACETIMEDB_*-variabler - .env.example: fjernet SpacetimeDB-seksjoner Dokumentasjon oppdatert: - CLAUDE.md: stack, lagmodell, kjerneprinsipper, driftsmodell - docs/arkitektur.md: skrivestien, lesestien, datalag, teknologivalg - docs/retninger/datalaget.md: migrasjonshistorikk, status "fjernet" - 37 andre docs oppdatert (features, concepts, infra, ops, retninger) - Alle kode-kommentarer med STDB-referanser oppdatert Verifisert: maskinrommet bygger og starter OK, frontend bygger OK, helsesjekk returnerer 200. Caddy reloadet.
5.3 KiB
Unix-filosofi: Maskinrommet som orkestrator, verktøy som binaries
Tese
Maskinrommet skal ikke gjøre arbeid — det skal koordinere arbeid. Selve arbeidet gjøres av spesialiserte CLI-verktøy som maskinrommet kaller. Claude har tilgang til de samme verktøyene og kan simulere alt maskinrommet gjør.
Prinsipp
-
Én jobb, gjort godt. Hvert verktøy gjør én ting — transkriberer, rendrer, prosesserer lyd, genererer RSS. Ikke alt i én binær.
-
Delt verktøykasse. Maskinrommet og Claude bruker samme CLI-verktøy. Maskinrommet kaller dem fra jobbkøen, Claude kaller dem fra terminalen. Ingen hemmelig logikk som bare lever inne i maskinrommet.
-
Orkestratoren er frontendens interface. Frontend snakker med maskinrommet via HTTP. Maskinrommet validerer, autoriserer, legger i jobbkø, og delegerer til CLI-verktøy. Maskinrommet eier auth og edges — men delegerer prosessering.
-
Claude kan simulere alt. Fordi maskinrommet gjør alt via CLI, kan Claude kjøre de samme kommandoene manuelt. Nyttig for:
- Debugging ("hvorfor feiler transkripsjonen?")
- Testing ("hva skjer om jeg rendrer denne artikkelen?")
- Utvikling ("la meg prøve den nye FFmpeg-filteren direkte")
- Feilretting ("la meg re-kjøre RSS-genereringen for denne samlingen")
Arkitektur
Frontend (SvelteKit)
│
▼ HTTP
Maskinrommet (Rust)
├── Auth + tilgangskontroll
├── Intentions (validering, edge-logikk)
├── Jobbkø (PG-basert)
│ │
│ ▼ spawn
│ CLI-verktøy (tools/)
│ ├── synops-transcribe (Whisper)
│ ├── synops-render (Tera → CAS)
│ ├── synops-audio (FFmpeg)
│ ├── synops-tts (ElevenLabs)
│ ├── synops-ai (LiteLLM)
│ ├── synops-rss (RSS-generering)
│ ├── synops-context (graf-oppslag)
│ ├── synops-search (fulltekstsøk)
│ └── ...
│
▼ direkte
PG, CAS
Claude har tilgang til hele tools/-katalogen og kan kjøre alt direkte:
# Maskinrommet gjør dette via jobbkøen:
synops-transcribe --cas-hash abc123 --model medium
# Claude kan gjøre det samme fra terminalen:
synops-transcribe --cas-hash abc123 --model medium
Konvensjoner for CLI-verktøy
- Navnekonvensjon:
synops-<verb>(f.eks.synops-transcribe) - Input: args + stdin + env-variabler (DATABASE_URL, CAS_ROOT)
- Payload-modus:
--payload-json <json>for jobbkø-dispatch (verktøyet parser selv, portvokteren trenger ikke kjenne argumentene) - Output: stdout (strukturert — JSON eller markdown)
- Feilhåndtering: stderr for feilmeldinger, exit-kode != 0 ved feil
- Ingen tilstandsendring uten flagg: lesing er default, skriving krever
--writeeller--apply(sikkerhetsnett for Claude) - Idempotent der mulig: kan kjøres flere ganger uten sideeffekter
Generisk dispatch
Portvokteren trenger null konfigurasjon per verktøy. Bare en navnekonvensjon:
let binary = format!("synops-{}", job.job_type);
let mut cmd = Command::new(&binary);
cmd.arg("--payload-json").arg(&job.payload_json);
job_type: "transcribe" → synops-transcribe --payload-json '{...}'.
Verktøyet parser payload selv. Nytt verktøy = legg binary i PATH,
bruk riktig job_type i køen. Ingen rekompilering av portvokteren.
cli_tool-noder i PG bærer metadata (timeout, cpu_weight,
dokumentasjon) — men ikke dispatch-logikk. Portvokteren leser
timeout og cpu_weight fra noden, men selve invokasjon er
konvensjonsbasert.
Migrasjonsstrategi
Ikke en big-bang refaktor. Gradvis utbryting:
- Nye features bygges som CLI-verktøy fra start (fase 19+)
- Eksisterende kode brytes ut når den berøres — naturlig refaktor
- Maskinrommet beholder auth, intentions, jobbkø og edge-logikk
- Jobbkø-handlere endres fra inline-kode til
Command::new("synops-X")
Hva maskinrommet beholder
Kjernen som ikke bør brytes ut:
- Auth-middleware (JWT-validering, node-oppslag)
- Intentions (validering, PG-skriving, edge-logikk)
- Jobbkø (polling, retry, dead letter)
- Tilgangskontroll (node_access, recompute_access)
- Health-endepunkt
Alt annet — prosessering, rendering, generering — er kandidater for CLI-verktøy.
Verktøy som noder
Hvert CLI-verktøy er en node i grafen (node_kind: 'cli_tool'):
cli_tool-node:
title: "synops-transcribe"
content: "Whisper-transkribering av lydfil fra CAS"
metadata: {
"binary": "synops-transcribe",
"usage": "--cas-hash <hash> --model <model> [--initial-prompt <tekst>]",
"output": "JSON med segmenter, skriver til PG",
"replaces": "transcribe.rs"
}
Dette gir:
- Maskinrommet slår opp verktøyets spec før det spawner fra jobbkøen
- Claude spør grafen "hvilke verktøy finnes?" i stedet for å lese filer
- Arbeidselementer kan ha
mentions-edge til verktøyet de berører - Verktøy kan ha edges til hverandre (
depends_on→ synops-common) - Oppdatering av verktøyets spec skjer i PG, ikke i en README
tools/README.md forblir som lesbar oversikt i repo, men den
autoritative spesifikasjonen lever i grafen.
Bygger på
docs/retninger/maskinrommet.md— orkestratorrollendocs/infra/agent_api.md— Claude sitt grensesnitttools/README.md— verktøykatalogen