# 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 1. **Én jobb, gjort godt.** Hvert verktøy gjør én ting — transkriberer, rendrer, prosesserer lyd, genererer RSS. Ikke alt i én binær. 2. **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. 3. **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. 4. **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: ```bash # 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-` (f.eks. `synops-transcribe`) - **Input:** args + stdin + env-variabler (DATABASE_URL, CAS_ROOT) - **Payload-modus:** `--payload-json ` for jobbkø-dispatch (verktøyet parser selv, vaktmesteren 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 `--write` eller `--apply` (sikkerhetsnett for Claude) - **Idempotent der mulig:** kan kjøres flere ganger uten sideeffekter ## Generisk dispatch Vaktmesteren trenger null konfigurasjon per verktøy. Bare en navnekonvensjon: ```rust 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 vaktmesteren. `cli_tool`-noder i PG bærer metadata (timeout, cpu_weight, dokumentasjon) — men ikke dispatch-logikk. Vaktmesteren leser timeout og cpu_weight fra noden, men selve invokasjon er konvensjonsbasert. ## Migrasjonsstrategi Ikke en big-bang refaktor. Gradvis utbryting: 1. **Nye features** bygges som CLI-verktøy fra start (fase 19+) 2. **Eksisterende kode** brytes ut når den berøres — naturlig refaktor 3. **Maskinrommet** beholder auth, intentions, jobbkø og edge-logikk 4. **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", "aliases": ["transkriber", "transkribering", "transkripsjoner"], "description": "Whisper-transkribering av lydfil", "args_hints": { "lydfilen": "--cas-hash {event.cas_hash}", "stor modell": "--model large", "medium modell": "--model medium" }, "usage": "--cas-hash --model [--initial-prompt ]", "output": "JSON med segmenter, skriver til PG" } ``` 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` — orkestratorrollen - `docs/infra/agent_api.md` — Claude sitt grensesnitt - `tools/README.md` — verktøykatalogen