# Konsept: Arbeidstavlen (Prosjektstyring)
**Filsti:** `docs/concepts/arbeidstavlen.md`

## 1. Konsept
Alt prosjektarbeid i Synops — oppgaver, bugs, ideer, forslag,
feature-forespørsler — er noder i PostgreSQL. Én kanban-tavle
organiserer arbeidet. Claude og Vegard deler samme data via CLI
og web. Arbeidselementer oppstår organisk fra samtaler, manuelt
input, eller systemhendelser.

## 2. Hvorfor

`tasks.md` var en pragmatisk bootstrap. Den har tre fundamentale
problemer:

1. **Race conditions.** Flere Claude-instanser redigerer samme fil
   samtidig. Endringer overskrives, status forsvinner, git-konflikter
   oppstår.
2. **Fragil parsing.** Bash-scripts parser markdown med regex
   (`grep -P '^\- \[~\]'`). Formateringsendringer knekker parseren.
3. **Frakoblet fra grafen.** Oppgaver kan ikke lenkes til samtaler,
   dokumenter, eller personer via edges. De lever utenfor
   datamodellen.

Løsningen: arbeidselementer er noder. De deltar i grafen som alt
annet. De har edges til samtaler (hvor ideen kom fra), til
personer (hvem som jobber), til dokumenter (hva de implementerer),
og til hverandre (foreldre/barn).

## 3. Nodemodell

Arbeidselementer bruker `node_kind: 'work_item'`:

```
work_item-node:
  title:    "Forbedre lydkvalitet ved opptak"
  content:  "Brukere rapporterer at ..."   (ren tekst, søkbar)
  metadata: {
    "size": "small",                       // small | medium | large
    "origin": "chat"                       // chat | manual | system
  }
```

### Kategorisering via edges, ikke typer

Det finnes ingen `node_kind` per kategori (task, bug, idea).
Distinksjonen gjøres med `tagged`-edges:

```
work_item ──tagged──→ board  { "tag": "bug" }
work_item ──tagged──→ board  { "tag": "idea" }
work_item ──tagged──→ board  { "tag": "feature" }
work_item ──tagged──→ board  { "tag": "tech-debt" }
```

Dette følger eksisterende filosofi: edges definerer hva en node er,
ikke noden selv.

### Størrelse er organisk

Ingen tvungen hierarki-klassifisering. Et element starter som
`small` og vokser:

```
"Fiks fade-bug"              → small (én commit)
"Redesign lydpipeline"       → medium (noen timer)
"Redesign lydpipeline"       → large (har fått barn-items)
  ├── belongs_to: "Nytt EDL-format"
  ├── belongs_to: "FFmpeg wrapper"
  └── belongs_to: "Oppdater studio-UI"
```

Samme tekst-primitiv-filosofi: en node kan vokse.

## 4. Edge-modell

| Edge-type | Source → Target | Metadata | Betydning |
|-----------|----------------|----------|-----------|
| `belongs_to` | work_item → board | `{ "position": 1.5 }` | Kortet tilhører tavlen |
| `status` | work_item → board | `{ "value": "neste" }` | Kolonneplassering |
| `assigned_to` | work_item → person/agent | — | Hvem jobber på dette |
| `belongs_to` | work_item → work_item | `{ "position": 1.0 }` | Deloppgave |
| `source_material` | work_item → content | `{ "context": "summarized", "excerpt": "..." }` | Hvor ideen kom fra |
| `tagged` | work_item → board | `{ "tag": "bug" }` | Kategorisering |
| `mentions` | work_item → any node | — | Relatert dokument/feature |

`assigned_to` er en ny edge-type. Retning: work_item → person.
Semantikk: "dette elementet er tildelt denne personen/agenten."

Barn-items har sin egen `status`-edge. Et barn kan være ferdig
mens forelderen fortsatt er i arbeid.

## 5. Kanban-oppsettet

Tavlen er en `collection`-node med `kanban`-trait:

```jsonc
{
  "node_kind": "collection",
  "title": "Synops Arbeidstavle",
  "metadata": {
    "traits": {
      "kanban": {
        "columns": ["innboks", "backlog", "neste", "pågår", "review", "ferdig"]
      }
    }
  }
}
```

### Kolonnesemantikk

| Kolonne | Hva | Hvem styrer | WIP-grense |
|---------|-----|-------------|------------|
| **Innboks** | Ubehandlede elementer fra chat og automatikk | System/@bot | Ingen |
| **Backlog** | Vurdert, ikke prioritert. Kan være hundrevis | Vegard | Ingen |
| **Neste** | Prioritert og klar. Claude plukker herfra | Vegard | ~10 |
| **Pågår** | Noen jobber aktivt på dette | Claude/Vegard | 2–3 |
| **Review** | Implementert, venter på Vegards sjekk | Claude | ~5 |
| **Ferdig** | Arkivert. Alltid søkbart | System | Ingen |

### Bevegelsesregler

```
Innboks → Backlog/Neste    Vegard triagerer
Backlog → Neste            Vegard prioriterer
Neste   → Pågår           Claude/Vegard starter. assigned_to-edge opprettes
Pågår   → Review          Claude ferdig. Commits refererer work_item UUID
Review  → Ferdig           Vegard bekrefter
Review  → Pågår           Vegard ber om endringer
Enhver  → Backlog          Deprioritering
```

### Backlog-visning

Backlog trenger ikke være kanban. Hundrevis av elementer er
bedre i en filtrert listevisning med søk, tags og sortering.
Bare **Neste → Pågår → Review → Ferdig** er aktive kanban-lanes.

## 6. @bot-konvensjonen

`@bot` er Synops sin generiske markør for AI-assistanse i
samtaler. Boten er først og fremst en **samtalepartner** — den
svarer på spørsmål, forklarer, diskuterer og hjelper. I tillegg
fanger den opp actionable innhold og oppretter noder i bakgrunnen.

### Boten er en generell samtalepartner

`@bot` svarer på alt:

```
"Hva betyr CTR?"
  → Forklaring i chatten. Ingen node.

"Lydkvaliteten var dårlig i dag"
  → Svar + diskusjon i chatten.
  → work_item i innboks: "Undersøk lydkvalitet" + tagged "bug"

"Kan du sjekke om RSS-feeden oppdaterte seg?"
  → Kjører synops-rss, rapporterer resultat i chatten.

"Vi bør legge til kapittelmerkering"
  → Diskuterer i chatten.
  → work_item i innboks: "Kapittelmerkering i podcast" + tagged "idea"

"Forklar hvordan edge-validering fungerer"
  → Forklaring i chatten. Ingen node.
```

Brukeren merker bare at de får svar. Noder dukker opp i
innboksen i bakgrunnen for Vegard å triagere.

### To output-kanaler

1. **Chat-svar** (alltid) — boten svarer i samtalen
2. **Noder** (når relevant) — boten oppretter work_items,
   melder fra om feil, fanger opp forslag

Kanal 2 er usynlig for brukeren. De ser bare svaret.

### Slik fungerer det

1. En bruker skriver i en kommunikasjonsnode der bot-agenten er
   `member_of`.
2. Portvokteren trigger `agent_respond`-jobb (eksisterende flow).
3. Boten svarer i samtalen.
4. Boten vurderer: er noe her actionable?
5. Hvis ja: oppretter riktig node-type med riktig tag.

### Hva fanges opp?

| Innhold | Resultat | Tag |
|---------|----------|-----|
| Bug / feil / noe virker ikke | work_item + mentions berørt cli_tool | `bug` |
| Idé / forslag / "vi bør" | work_item | `idea` |
| Feature-forespørsel | work_item | `feature` |
| Teknisk gjeld / "dette er rotete" | work_item | `tech-debt` |
| Generelt spørsmål | Bare chat-svar, ingen node | — |

### Hva opprettes?

For hvert actionable element:
- `work_item`-node med tittel og beskrivelse
- `belongs_to`-edge → arbeidstavlen
- `status`-edge med `value: "innboks"`
- `source_material`-edge → chat-meldingen (proveniens)
- `tagged`-edge med riktig kategori
- `mentions`-edges til berørte noder (verktøy, features)
- Eventuelt `assigned_to`-edge til agent-noden (om boten kan
  gjøre det selv)

Vegard triagerer innboksen og prioriterer.

### Ruting

`@bot` rutes av portvokteren basert på kontekst:
- Standard: Claude (nåværende `agent_respond`-flyt)
- Fremtidig: spesialiserte agenter, andre modeller, eller
  regelbaserte svar — uten endring i brukergrensesnittet

## 7. Task runner og jobbhenting

### CLI: `synops-tasks`

```bash
synops-tasks --list [--status <status>] [--tag <tag>]
synops-tasks --next                     # neste fra "neste"-kolonnen
synops-tasks --claim <uuid> --write     # atomisk: status → pågår + assigned_to
synops-tasks --complete <uuid> --write  # status → review
synops-tasks --prompt <uuid>            # generer prompt for autonom sesjon
```

`--claim` bruker `SELECT ... FOR UPDATE` for atomisk status-
endring. Ingen race conditions.

### Task runner

`run-next-task.sh` blir en tynn wrapper:

```bash
TASK_JSON=$(synops-tasks --next --format json)
TASK_ID=$(echo "$TASK_JSON" | jq -r '.id')
synops-tasks --claim "$TASK_ID" --write
claude -p --dangerously-skip-permissions \
  "$(synops-tasks --prompt "$TASK_ID")"
synops-tasks --complete "$TASK_ID" --write
```

### Stale-deteksjon

Items som har stått i "pågår" lenger enn 60 minutter uten
commit frigjøres tilbake til "neste":

```bash
synops-tasks --unstale --write
```

## 8. CLAUDE.md som bootstrap

CLAUDE.md forblir prosjektets startdokument — det lastes alltid
inn i konteksten. Strukturen beholdes i hovedsak, men
oppgavehenting endres:

**Erstatt tasks.md-referanser med:**

```markdown
## Arbeidshenting
Oppgaver hentes fra arbeidstavlen (PG). Bruk CLI:
- `synops-tasks --next` — vis neste oppgave
- `synops-tasks --list` — vis hele tavlen
- `synops-tasks --claim <uuid> --write` — ta en oppgave
- `synops-tasks --complete <uuid> --write` — marker ferdig

Task runner: `./scripts/run-next-task.sh`
Se `docs/concepts/arbeidstavlen.md` for full spesifikasjon.
```

Doc-treet i CLAUDE.md beholdes — det er verdifull navigasjon.
Endringen er kirurgisk: erstatt oppgaverelaterte instruksjoner.

## 9. Migrering fra tasks.md

### Steg 1: Opprett arbeidstavle-noden
Én `collection`-node med kanban-trait og seks kolonner.
Fast UUID som dokumenteres i CLAUDE.md.

### Steg 2: Migrer gjenstående oppgaver
Script leser `tasks.md`, oppretter `work_item`-noder for
gjenstående `- [ ]`-elementer. Ferdigstilte `[x]`-elementer
kan migreres til "ferdig" for historikk, eller forbli i
`tasks.md` som lesbart arkiv i git-historikken.

Fase- og avhengighetsinfo overføres til `metadata` og
`belongs_to`-edges mellom relaterte items.

### Steg 3: Switch task runner
`run-next-task.sh` bruker `synops-tasks` i stedet for
markdown-parsing. `tasks.md` redigeres ikke lenger.

## 10. CLI og web: samme data

```
Terminal (Claude/Vegard)          Web (SvelteKit)
  │                                  │
  synops-tasks --list                KanbanTrait panel
  synops-tasks --claim <uuid>        Drag-and-drop kolonne
  psql → direkte SQL                 Arbeidsflaten
  │                                  │
  └──────────── PG ──────────────────┘
                 │
                 ↕ synk
                 │
              SpacetimeDB → WebSocket → sanntid i frontend
```

| Grensesnitt | Leser fra | Skriver til |
|-------------|-----------|-------------|
| `synops-tasks` CLI | PG direkte | PG direkte |
| Web (KanbanTrait) | SpacetimeDB | Maskinrommet → PG + STDB |
| `synops-respond` | PG | PG + STDB (via maskinrommet) |

Ingen nytt UI trengs — arbeidstavlen er bare en `collection`-node
med kanban-trait. Vegard ser den på arbeidsflaten ved siden av
andre paneler.

## 11. Komponenter

| Feature | Rolle i Arbeidstavlen |
|---------|----------------------|
| Kanban (trait) | Visuell tavle med kolonner og drag-and-drop |
| Chat | @bot i samtaler skaper arbeidselementer |
| `synops-tasks` CLI | Claude og scripts henter/oppdaterer arbeid |
| `synops-respond` | Boten oppretter work_items fra chat-innsikt |
| Jobbkø | `run-next-task.sh` orkestrerer autonome sesjoner |

## 12. Utviklingsfaser

1. Opprett arbeidstavle-noden i PG med kanban-trait og seks kolonner.
2. Implementer `synops-tasks` CLI (list, next, claim, complete, prompt).
3. Migrer gjenstående oppgaver fra `tasks.md`.
4. Oppdater `run-next-task.sh` til å bruke `synops-tasks`.
5. Utvid `synops-respond` til å opprette work_items fra chat.
6. Oppdater CLAUDE.md med ny arbeidshenting-seksjon.

## 13. Fallback: `synops-snapshot`

PG nede betyr at Claude mister tilgang til verktøyoversikt,
arbeidstavle og arkitektur-noder. Løsningen er en generert
snapshot-fil som alltid ligger i repo:

```bash
synops-snapshot --write
  → Kobler til PG
  → Henter: cli_tool-noder, work_items (neste/pågår/review),
    arbeidstavle-status, aktive agenter
  → Skriver til docs/snapshot.md
  → Deterministisk output — ingen diff hvis ingenting endret seg
```

### Når den kjøres
- **Automatisk:** Post-hook i `run-next-task.sh` etter hver oppgave
- **Periodisk:** Cron (hvert 5. minutt) som sikkerhetsnett
- **Manuelt:** `synops-snapshot --write` ved behov

### Hva den inneholder
- Alle `cli_tool`-noder med usage og metadata
- Arbeidstavle-status (antall per kolonne, items i neste/pågår)
- Siste endringer (nyeste work_items)
- Tidsstempel for når snapshot ble generert

### CLAUDE.md-referanse
```markdown
## Fallback-kontekst
Hvis PG er utilgjengelig, se `docs/snapshot.md` for siste kjente
tilstand. Generert av `synops-snapshot`. Ikke rediger manuelt.
```

Filen committes og pushes som del av normal arbeidsflyt.
`synops-snapshot` er selv et CLI-verktøy og en `cli_tool`-node
i grafen.

## 14. Avgrensning

- Arbeidstavlen erstatter `tasks.md` for prosjektstyring.
  Den erstatter **ikke** docs-filer — arkitektur, retninger,
  feature-specs og konseptdokumenter lever fortsatt som
  markdown i `docs/`.
- `@bot` er en chat-konvensjon, ikke en ny primitiv. Den bruker
  eksisterende `member_of`-edge og `agent_respond`-flyt.
- Work items er noder i grafen — ikke en separat
  prosjektstyringsmodul. De følger alle regler for noder,
  edges, visibility og tilgangskontroll.
