# 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-<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, 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 <hash> --model <model> [--initial-prompt <tekst>]",
    "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
