# Dibrix: guide for AI-agenter (agent guide)

Versjon 2026-10-30.1 · doc_version 2 · rev 3c00e39b · https://draw.dibrix.com

## OPPSKRIFT (5 sekunder): tegning → modell → søknadstegninger

1. POST /sessions/{sid}/agent/import-drawings/json  {files:[{name,data_b64}], mode:"build"}  → jobb-id
2. GET  /sessions/{sid}/agent/import-drawings/{jid}  til state=waiting_for_user
3. POST /sessions/{sid}/agent/import-drawings/{jid}/confirm  {"mode":"build"}  → KI bygger
4. POST /sessions/{sid}/agent/drawings/add_sheet_set  {"set":"soknad"}  → E-/D-/K-serien
5. GET  /sessions/{sid}/agent/delivery-check → rett → GET /sessions/{sid}/export/sheets.pdf
Åpne økta: https://draw.dibrix.com/?session={sid}

## Last opp tegning uten klikk

Ikke driv BuildChat-vedlegget eller `<input type=file>` — Chrome krever ekte brukerhandling. Bruk API med `Authorization: Bearer $DIBRIX_API_KEY` (access=share; Konto → API-nøkler). Samme som Fil ▸ Importer ▸ Tegninger:

```bash
# Med KI (import_drawings_upload)
curl -sS -H "Authorization: Bearer $DIBRIX_API_KEY" \
  -F "files=@plan.pdf" -F "mode=build" \
  "https://draw.dibrix.com/sessions/$SID/agent/import-drawings"

# Uten KI (import_drawings_vector)
curl -sS -H "Authorization: Bearer $DIBRIX_API_KEY" \
  -F "files=@plan.pdf" \
  "https://draw.dibrix.com/sessions/$SID/agent/import-vector"

# JSON/base64 (import_drawings_job) — se også 5-sekunders-oppskriften over
curl -sS -H "Authorization: Bearer $DIBRIX_API_KEY" -H "content-type: application/json" \
  -d '{"files":[{"name":"plan.pdf","data_b64":"<base64>"}],"mode":"build"}' \
  "https://draw.dibrix.com/sessions/$SID/agent/import-drawings/json"
```

## Start her: Tegning/skann → modell → tegningssett → PDF (oppskrift `tegning-til-pdf`; alt skjer i Dibrix)

1. Tilgang: `login` eller agentnøkkel (DIBRIX_API_KEY, `Authorization: Bearer dk_…`); nytt prosjekt `create_project`, så `bind_session` (project=<id>).
2. Bygg: `get_spec_schema` → `build_house_from_spec` (POST /sessions/{sid}/spec). PDF/skann: `import_drawings_job` → `get_import_job` → `confirm_import_job` (Konverteringer).
3. Etasjer (audit_storeys): `delivery_check` (only=etg) og `list_tags`; rett med `set_storeys` / `tag_by_storey`. Se på modellen: `render`.
4. Eksisterende bygg: `import_approved_drawings` (approved_date=…) legger originalen inn som sidene «Sist godkjent – …».
5. Tegningssett i Pages: `add_sheet_set` med set = soknad | presentasjon | konstruksjon (`missing` i svaret = sider Dibrix ikke lager ennå).
6. Firmaets tittelfelt: `list_layout_profiles` → `apply_layout_profile`, eller feltene med `set_sheet_chrome`.
7. PDF: `delivery_check`, så `export_sheets_pdf` = GET /sessions/{sid}/export/sheets.pdf (?sheet= for ett ark).
8. `save_version` (comment) etter hvert ferdig steg, ikke bare til slutt.

REGEL: Lag aldri tegninger utenfor Dibrix; mangler noe i Pages, meld det (`report_to_developer`) i stedet for å omgå det.

Flere oppskrifter: `recipes` i /agent.json, MCP `list_recipes` / `get_recipe`. HTTP-rute per verktøy: `tools[].path` i /agent.json. Hele guiden: /agent.

Dibrix Draw er en BIM-modellerer i nettleseren (vegger, innervegger, åpninger, dekker, tak, etasjer, snitt, terreng, mål, tekst, scener og ark; eksport IFC/PDF/DXF/DWG/SKP) med konfigurator, pris og regelsjekk. Alt under er levende: ingen repo eller Git trengs. Maskinlesbar tvilling med input-skjema per verktøy: https://draw.dibrix.com/agent.json. Kompakt OpenAPI med skjemaene (liten nok til å hentes hel): https://draw.dibrix.com/openapi-sandbox.json. Bare GET? https://draw.dibrix.com/agent/quick. Cache: legg `?v=3c00e39b` på adressene for en frisk kopi.

Arbeidsmåte: INSPISER → PLANLEGG → HANDLE → SJEKK. Små steg; sjekk med plan/areal etter hver endring.


## Bare GET? Start her (ingen POST, ingen økt)

En chat-agent med bare nettsidehenting kan ikke POSTe og får derfor ikke opprettet en sandkasseøkt. Bruk GET-inngangen: den gir pris, matrikkelkode, regelsjekk-sammendrag og lenker i ett kall, uten økt og uten bivirkninger (samme motor og rate limit som `POST /configurator/public/quote`). Kortversjon: https://draw.dibrix.com/agent/quick

- Pris: `GET https://draw.dibrix.com/configurator/public/quote?type=garasje&width=8&depth=6&door=south&window=east` (legg til `&plan=1` for 2D-plan, `&roof=gable|hip|shed|flat`, `&kommune=nesodden`, `&full=1` for alle regelfunn og fakta)
- Tomtedata (valgfritt; uten dem er avstandsreglene «ukjent»): `site_nabo_m` (avstand til nabogrense, m), `site_annen_bygning_m`, `site_vei_m` (til veiens senterlinje) + `vei` (f.eks. fv157), `site_sjo_m`, `gulv_over_terreng_m`, `bebygd_eiendom=1|0`, `tomt_m2`, `eksisterende_bya_m2`, `over_ledninger=1|0`. Eksempel: `…&site_nabo_m=1.2&site_annen_bygning_m=6&bebygd_eiendom=1`. Ugyldig verdi gir 400 med forklaring.
- Svaret: `still_unknown` lister hvilke parametre som gjør ukjente funn kjent; `compliance.unknown_help` gjør det per funn; `defaults` viser standardmålene som ble brukt (dør/port 2,5 × 2,1 m, vindu 1,2 × 1,2 m, vegg ytter_198, takvinkel, høyde); `price_includes`/`price_excludes` sier hva prisen dekker.
- Planlenken: lim `links.plan_page` ORDRETT fra svaret (ferdig URL; gjengi den aldri fra hukommelsen).
- Regelsjekk: `GET https://draw.dibrix.com/configurator/public/compliance?type=garasje&width=8&depth=6&door=south` (`type` velger bygningstype og dermed regelsett; `&full=1` gir alle funn og fakta)
- Plan som SVG: `GET https://draw.dibrix.com/configurator/public/plan.svg?type=garasje&width=8&depth=6&door=south&window=east`
- `links` i svaret har ferdige lenker til SVG-planen og til `/konfigurator/plan#c=…` (delelenke: åpner modellen i konfiguratoren for et menneske).
- 400 = ukjent `type`, `door`, `window` eller `roof`, eller mål utenfor 2–20 m; 429 = rate limit.


## Retninger, enheter og grenser

**Akser (konfigurator, plan, `boundary`):** meter. x+ = øst, y+ = nord, Z opp. «south» er veggen ved lav y (y = 0), «north» ved høy y (y = depth), «west» ved lav x (x = 0), «east» ved høy x (x = width). Fotavtrykket med width x depth går fra (0,0) til (width,depth); `boundary` er en liste av [x, y]-punkt i meter (enkel polygon, minst 3 punkt, flyttes til origo, 2–20 m i begge retninger). Veggnavn i `openings`: south, north, east, west (dubletter får tall: south2, east2 …). `pos_m` måles fra veggens vest/sør-ende.

**Sandkasse (grenser):**

- Maks 2 økter per IP, maks 200 totalt; en økt lever 30 min etter siste bruk (`ttl_s` i svaret). Frigi med `POST …/release` når du er ferdig.
- Uten driftsflagget `DIBRIX_SANDBOX=1` svarer alle sandkasseruter 404 (ikke 403): da finnes ingen sandkasse og GET-inngangen over er veien.
- Maks 400 elementer per økt; kun tegning fra konfigurasjon + lesing (ikke fri tegning med verktøy).
- Samme rate limit som `/configurator/public/*` (120 kall per minutt per IP, 429).

**Feilkoder:** 400 ugyldig input (teksten sier hva) · 401/403 krever innlogging eller delelenke, eller ruten er ikke åpen i sandkassen · 404 ukjent/utløpt økt, eller sandkasse ikke slått på · 409 økta er ikke tom (`/drawing`) · 413 tegningen er for stor for sandkassen · 422 feil felt (manglende/ukjent felt i body) · 429 rate limit eller maks økter per IP · 503 prisliste ikke satt opp, eller sandkassen full.


## Start her: 3 steg uten innlogging (sandkasse)

Sandkasse: **aktiv**. Anonym økt, 30 min, maks 2 per IP, bare tegning fra konfigurasjon + lesing.

```bash
B=https://draw.dibrix.com
# 1) opprett økt
SID=$(curl -s -X POST $B/configurator/sandbox/session | python -c 'import sys,json;print(json.load(sys.stdin)["id"])')
# 2) tegn: ring (boundary, meter) + dør og vindu (openings på navngitt vegg)
curl -s -X POST $B/configurator/sandbox/session/$SID/drawing -H 'content-type: application/json' -d '{"type":"garasje","boundary":[[0,0],[8,0],[8,6],[0,6]],"openings":[{"wall":"south","kind":"door","w_m":1.0,"h_m":2.1,"pos_m":2.0},{"wall":"east","kind":"window","w_m":1.2,"h_m":1.2}]}'
# 3) hent plan, pris og regelsjekk
curl -s $B/sessions/$SID/composer/plan            # JSON: vegger, åpninger, rom, mål
curl -s $B/sessions/$SID/composer/plan.svg        # se planen
curl -s -X POST $B/configurator/sandbox/session/$SID/price -H 'content-type: application/json' -d '{"choices":{}}'
curl -s "$B/configurator/sandbox/session/$SID/compliance?type=garasje"
curl -s -X POST $B/configurator/sandbox/session/$SID/release   # rydd opp
```

**Uten sandkasse:** `POST /configurator/public/quote` med samme felt + `"plan": true` gir pris og 2D-plan i ett svar, og `POST /configurator/public/compliance` med `{"config": {…}, "kommune": "3212"}` gir regelsjekk. Typer, former og valg: `GET /configurator/public/catalog`.

## Start her: innlogget eller med delelenke (full editor)

Delelenke fra mennesket: `https://draw.dibrix.com/?session=<sid>&share=<token>`. `sid` = verdien av `session` (32 heks-tegn), `share` = verdien av `share`. Den gamle nøkkelen (og `pr_`) skriver ALDRI til den kjørende økta (skrivesperre, 401/403): åpne en privat arbeidskopi med `POST /view/open {session, share}`, jobb i `/sessions/{kopi}/agent/*` og lagre med `POST /sessions/{kopi}/versions` (ny utkastversjon eieren godkjenner). Bare en `wr_`-nøkkel overskriver den kjørende økta bare sammen med innlogging eller `dk_…` (`?share=wr_…` alene → 401 «wr_ key alone is not enough»). Når serveren har innlogging på (draw.dibrix.com), krever alle skrivende `/sessions/*`-ruter utenom sandkassen og arbeidskopier en innlogget eier, admin, redigerer i prosjektet eller (innlogget + wr_-nøkkel). Uten delelenke: logg inn og lag din egen økt.

**Agentnøkkel (`dk_…`, anbefalt):** be Kjetil lage en i **Konto → API-nøkler** og legg den i `DIBRIX_API_KEY`. Send den som `Authorization: Bearer dk_…` (aldri `?key=`: en nøkkel i URL-en avvises med 400). Ingen cookie og ingen innlogging. Nøkkelen handler som eieren, men er knyttet til nøyaktig én økt eller noen få prosjekter og har ett nivå: `read` (leser), `propose` (privat arbeidskopi via `POST /key/open`, lagres som NY utkastversjon, standard) eller `write` (endrer den levende økta/prosjektet). `GET /key/self` sier hva nøkkelen er. Nøkkelen kan aldri godkjenne versjoner, lage delelenker eller nøkler, røre konto, billing, team eller admin, eller slette prosjekt. Utløper (standard 30 d, write 24 t) og kan trekkes tilbake av eieren med en gang.

```bash
B=https://draw.dibrix.com
curl -s -c jar -X POST $B/auth/login -H 'content-type: application/json' -d '{"email":"…","password":"…"}'
SID=$(curl -s -b jar -X POST $B/sessions | python -c 'import sys,json;print(json.load(sys.stdin)["id"])')
# 1) tegn vegger (ring); svaret har vegg-id-ene
curl -s -b jar -X POST $B/sessions/$SID/agent/walls -H 'content-type: application/json' -d '{"corners":[[0,0],[8,0],[8,6],[0,6]],"closed":true,"height_m":2.65,"thickness_m":0.25}'
# 2) åpning i en vegg (host_id fra svaret over), tak, terreng
curl -s -b jar -X POST $B/sessions/$SID/agent/openings -H 'content-type: application/json' -d '{"host_id":"<vegg-id>","kind":"window","offset_m":2,"width_m":1.2,"height_m":1.2,"sill_m":0.9}'
curl -s -b jar -X POST $B/sessions/$SID/roof_from_walls -H 'content-type: application/json' -d '{"form":"gable"}'
# 3) plan, pris, regelsjekk
curl -s -b jar $B/sessions/$SID/composer/plan
curl -s -b jar $B/configurator/session/$SID/price
curl -s -b jar "$B/sessions/$SID/agent/compliance?type=garasje&kommune=3212"
```

**Raskeste vei til et helt hus:** `GET /spec/schema` (åpen) gir hus-spec v1 med et bygbart eksempel; `POST /sessions/$SID/spec` med `{"spec": {…}}` bygger etasjer, vegger, åpninger, dekker, tak, trapper, rekkverk, skorstein og terreng i ETT kall og ett angre-steg (svaret har `timing`); `GET /sessions/$SID/spec` leser modellen ut igjen. Bruk dette i stedet for mange enkeltkall.

Koordinater i **meter**, Z opp. Vegg 0,25 m, etasje 2,65 m. Hver endring er ett angre-steg (`POST /sessions/{sid}/undo`). Mennesket ser endringene live i nettleseren.

## Tegneverktøy

Sandkasse = virker i en anonym sandkasseøkt (uten innlogging). I sandkassen tegner du gjennom `sandbox_load_drawing` (boundary/walls/openings); resten krever innlogging eller delelenke.

| Kategori | Verktøy (MCP-navn) | Rute / BuildChat | Uten innlogging (sandkasse) | Innlogget |
|---|---|---|---|---|
| Vegg (yttervegg) | `draw_walls`, `draw_rectangle`, `create_wall`, `wall_segment`, `bim_wall`, `house` … | `POST /sessions/{sid}/agent/walls` · `walls_closed([(0,0),(8,0),(8,6),(0,6)], height=2.65, thickness=0.25)` | ja (boundary) | ja |
| Innervegg | `draw_inner_wall` | `POST /sessions/{sid}/agent/walls` · `create_wall((3,0), (3,6), wall_type='inner_98')` | ja (walls) | ja |
| Åpning (dør/vindu/port) | `place_opening`, `face_opening`, `delete_openings`, `edit_opening` | `POST /sessions/{sid}/agent/openings` · `place_opening(host_id, kind='window', offset_m=2.0, width_m=1.2, height_m=1.2, sill_m=0.9)` | ja (openings) | ja |
| Dekke og gulv | `create_railing`, `fit_slab_to_walls`, `add_slab`, `slab_from_walls`, `slab_from_walls_status`, `heal_slab` … | `POST /sessions/{sid}/agent/slabs/{eid}/fit` · `fit_slab_to_walls('<slab id>', ['<wall id>'], slab_type='terrasse', thickness_m=0.15)` | ja (automatisk) | ja |
| Tak, ark og takvindu | `create_column`, `create_beam`, `create_chimney`, `add_roof`, `heal_roof`, `join_roofs_as_t` … | `POST /sessions/{sid}/roof_from_walls` · `create_roof_from_walls(form='gable', slope_deg=30)` | ja (roof_form) | ja |
| Etasje | `list_levels`, `ensure_levels`, `set_active_level`, `save_levels` | `GET /sessions/{sid}/levels` · `etasjer()` | ja (lese) | ja |
| Rom og areal | `list_rooms`, `edit_room`, `rebuild_rooms`, `set_terrace_shed`, `detect_rooms`, `measure_areas` … | `GET /sessions/{sid}/agent/rooms` · `list_rooms()` | ja (lese) | ja |
| Snitt | `list_sections`, `create_section`, `edit_section`, `patch_section`, `delete_section`, `move_section` … | `GET /sessions/{sid}/sections` · `snitt_liste()` | nei | ja |
| Terreng | `get_terrain`, `set_terrain`, `fill_terrain_pit` | `GET /sessions/{sid}/agent/terrain` · `get_terrain()` | nei | ja |
| Mål | `list_dimensions`, `move_dimension`, `set_dimension_extension`, `add_dimension`, `edit_dimension`, `delete_dimension` … | `GET /sessions/{sid}/composer/sheets/{name}/cotas` · `list_cotas(sheet='…')` | nei | ja |
| Tekst og strek på ark | `add_sheet_text`, `edit_sheet_text`, `add_sheet_line`, `plan_labels`, `opening_marks`, `list_sheet_annots` … | `POST /sessions/{sid}/composer/sheets/{name}/text` | nei | ja |
| Scene, ark og side | `delivery_check`, `accept_delivery_finding`, `auto_fix_delivery_finding`, `rename_scene`, `edit_sheet_viewport`, `list_scenes` … | `GET /sessions/{sid}/agent/delivery-check` · `delivery_check()` | ja (lese) | ja |

## Klienter: koble til (gjelder alle MCP/API-klienter)

BuildChat, Claude, Cursor, Hermes, ChatGPT-lignende og egne skript bruker de samme inngangene. Ingen repo eller Git trengs.

| Hva | URL |
|---|---|
| Agent-guide | https://draw.dibrix.com/agent |
| Maskinlesbar (verktøy + skjema) | https://draw.dibrix.com/agent.json, https://draw.dibrix.com/.well-known/dibrix-agent.json |
| llms.txt | https://draw.dibrix.com/llms.txt, https://draw.dibrix.com/.well-known/llms.txt |
| OpenAPI, kompakt (sandkasse + public + agent, liten nok til å hentes hel) | https://draw.dibrix.com/openapi-sandbox.json |
| OpenAPI, full (kuttes ofte av henteverktøy) | https://draw.dibrix.com/openapi.json |
| GET-hurtigstart (ingen POST) | https://draw.dibrix.com/agent/quick |
| Helse | https://draw.dibrix.com/health |
| Selvtest av enhet (finger, penn, mus; 2 min; ingen innlogging, sender ingenting) | https://draw.dibrix.com/konfigurator/selvtest |
| Web-MCP-pakke | https://draw.dibrix.com/agent/dibrix-web-mcp.zip (`pip install https://draw.dibrix.com/agent/dibrix-web-mcp.zip`) |
| Web-MCP over HTTPS | ikke satt opp på denne serveren (bruk stdio-pakken eller HTTP direkte) |

**MCP for web (stdio, etter `pip install` over):**

```json
{
  "mcpServers": {
    "dibrix-web": {
      "command": "python",
      "args": [
        "-m",
        "dibrix_web_mcp",
        "--transport",
        "stdio"
      ],
      "env": {
        "DIBRIX_WEB_URL": "https://draw.dibrix.com",
        "MCP_ALLOW_INSECURE": "1"
      }
    }
  }
}
```

**Agentoppskrift (anbefalt, uten passord):** be Kjetil lage en agentnøkkel i Konto → API-nøkler (velg økt eller prosjekt, nivå og utløp) og legg den i `DIBRIX_API_KEY` (`env`/`.env`, aldri i git, aldri i en URL) sammen med `DIBRIX_URL`. Nøkkelen sendes som `Authorization: Bearer dk_…`; `bind_session` uten argumenter åpner det nøkkelen får bruke. Innlogging til web-MCP uten nøkkel: sett `DIBRIX_EMAIL` / `DIBRIX_PASSWORD` i `env` (fra brukeren, aldri i git), eller bruk en delelenke (`bind_session`). Uten MCP: kall HTTP-rutene direkte, det er de samme verktøyene.

| Klient | Hvor konfigurasjonen limes inn |
|---|---|
| Claude Desktop | `claude_desktop_config.json` (Innstillinger > Utvikler > Rediger konfig) |
| Claude Code | `claude mcp add …` eller `.mcp.json` i prosjektet |
| Claude web / mobil | Egendefinert connector: HTTPS-MCP-URL (over), ellers HTTP via web-henting |
| Cursor | `~/.cursor/mcp.json` |
| Hermes og andre MCP-klienter | klientens MCP-konfig: samme `mcpServers`-blokk |
| ChatGPT-lignende / uten MCP | HTTP: `/agent.json` + `/openapi.json`, kall med curl/fetch |
| BuildChat | ingenting: kjører inne i økta, verktøyene står i systemprompten |

## Alle verktøy

Tilgang: åpen = uten innlogging · sandkasse = anonym sandkasseøkt eller innlogget · innlogget + eier/wr_ = innlogget og eier, admin, redigerer i prosjektet eller `?share=wr_…` (skrivesperre) · innlogget = cookie fra `/auth/login`.
Effekt: read = leser · write = endrer modellen (ett angre-steg) · account = konto · external = sender noe til mennesker (spør brukeren først).

### Økt og delelenke / Session & share link

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `list_recipes` | MCP | åpen, uten innlogging | read | Oppskriftene for vanlige jobber (id, tittel, steg med verktøynavn). Start her ved første besøk; samme liste som recipes i /agent.json. |
| `agent_actions` | `GET /agent/actions.json` | åpen, uten innlogging | read | Alle verktøy med det folk kaller dem (fraser, synonymer, når ikke) og hvor de finnes i appen, og alle innstillinger med gruppe. Svar på «hvor finner jeg …» herfra. |
| `get_recipe` | MCP | åpen, uten innlogging | read | Én oppskrift med alle steg (id fra list_recipes, f.eks. tegning-til-pdf: tegning/skann → modell → tegningssett → PDF). |
| `bind_session` | MCP | åpen, uten innlogging | read | Bind økta fra en delelenke (?session=&share=), sid+share, eller project=<id> (innlogget eller API-nøkkel: åpner prosjektets økt). Én gang per chat. |
| `create_session` | `POST /sessions` | innlogget | write | Ny tom redigeringsøkt (innlogget, ikke med API-nøkkel). Økta blir den bundne økta for senere verktøy. Vil du ha den i et prosjekt: create_project, så bind_session(project=<id>). |
| `close_session` | `DELETE /sessions/{sid}` | innlogget | write | Lukk en økt. |
| `create_share_link` | `POST /sessions/{sid}/share` | innlogget | account | Lag/hent økta sin gamle delingsnøkkel (?share=<token>). Nå nivå PROPOSE: den åpner en privat arbeidskopi (view_open med session=<økt-id>), aldri den kjørende økta. Vil du gi overskriv-tilgang, bruk share_link role=write. Tilbakekall med unshare_session. |
| `unshare_session` | `DELETE /sessions/{sid}/share` | innlogget | account | Trekk tilbake økta sin gamle delingsnøkkel; åpne arbeidskopier laget med den lukkes med en gang. |
| `sandbox_session` | `POST /configurator/sandbox/session` | åpen, uten innlogging | write | Anonym sandkasseøkt (uten innlogging, 30 min, maks 2 per IP). 404 når serveren ikke har sandkasse. |
| `ordbok` | `GET /ordbok` | åpen, uten innlogging | read | BIM-ordbok: norsk/engelsk/kode, dør-/vindu-/belegg-typer, oppskrifter, fallgruver. ?q=ord søker. |
| `share_link` | `POST /sessions/{sid}/share-links` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Lag en delelenke for økta på ett av TRE nivåer. role=viewer (LESE: ingen innlogging, privat skrivebeskyttet kopi per seer), role=propose (LAGE NYE VERSJONER, standard for agenter: ingen innlogging, privat ARBEIDSKOPI der alle agent-ruter, igz-opplasting og endringer virker; resultatet lagres som NY versjon med status utkast, merket med lenken. Kan ikke røre den kjørende økta, overskrive, godkjenne eller endre siste godkjente) eller role=write (OVERSKRIVE den kjørende økta; krever innlogging; utløper etter 24 t, maks 7 d; lag den bare når eieren ber om det). Godkjenning går aldri med nøkkel. role=editor er gammelt navn for propose. version (viewer/propose): approved (viewer-standard: SIST GODKJENTE versjon), latest (propose-standard: den levende modellen, utkast og alt) eller et versjonsnummer (v3: låst). ttl_days (viewer 1-730, standard 90; propose 1-90, standard 30) eller ttl_hours (write 1-168, standard 24). Svar: link.path (?session=<lenke-id>&share=<token>, token vises BARE nå; legg til &scene=<navn> for å åpne en bestemt scene), link.level, shows, warning=no_approved_version. Lenke-id er ikke økt-id. Tilbakekall med revoke_share. |
| `list_share_links` | `GET /sessions/{sid}/share-links` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | List delelenkene til økta (uten token): rolle, utløp, tilbakekalt, sist brukt, antall åpninger. |
| `revoke_share` | `DELETE /sessions/{sid}/share-links/{link_id}` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Tilbakekall en delelenke (link_id fra list_share_links). Åpne kopier lukkes med en gang. |
| `view_open` | `POST /view/open` | åpen, uten innlogging | read | Åpne en viewer- eller propose-lenke uten innlogging: session=<lenke-id>, share=<token> -> en privat økt (session_id). viewer: skrivebeskyttet (les med scene_summary, render, list_entities; skrive-kall gir 403). propose: en ARBEIDSKOPI du kan endre fritt (agent-ruter, igz-opplasting maks 100 MB med Content-Length); lagre resultatet med save_version, det blir en NY versjon med status utkast merket med lenka. Samme 404 for ukjent, utløpt og tilbakekalt lenke; maks 10 bomskudd per minutt. Den gamle økt-nøkkelen (session=<økt-id>) åpner også en arbeidskopi. |
| `sandbox_release` | `POST /configurator/sandbox/session/{sid}/release` | åpen, uten innlogging | write | Frigi sandkasseøkta når du er ferdig. |
| `select_tool` | `POST /sessions/{sid}/tool` | sandkasse (anonym) eller innlogget | write | Velg et pekerverktøy i UI (vegg, dør, vindu …); tegning skjer med pekeren over WS. |
| `release_tool` | `POST /sessions/{sid}/tool/release` | sandkasse (anonym) eller innlogget | write | Slipp aktivt pekerverktøy. |
| `key_open` | `POST /key/open` | innlogget | write | Hent økta nøkkelen jobber i (bind_session gjør dette selv). read: privat skrivebeskyttet kopi. propose: privat ARBEIDSKOPI du kan endre fritt (lagre med save_version, blir NY utkastversjon merket med nøkkelen). write: den levende økta (mode=copy gir arbeidskopi likevel). Gi session=<økt-id> (økt-nøkkel) eller project=<prosjekt-id> (prosjekt-nøkkel; source=saved åpner lagret fil). |

### Hus-spec (hele huset fra én JSON) / House spec (a whole house from one JSON)

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `get_spec_schema` | `GET /spec/schema` | åpen, uten innlogging | read | Hus-spec v1: JSON Schema + et bygbart eksempel (kopier og endre) + bruksnotater. Åpen, uten økt. Start her for å bygge et helt hus fra én JSON. |
| `build_house_from_spec` | `POST /sessions/{sid}/spec` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Bygg et helt hus fra ÉN hus-spec (etasjer, vegger, åpninger, dekker, tak, trapper, søyler, bjelker, rekkverk, skorstein, terreng) på sekunder, ett angresteg. Kledning/hjørnekasser/rom bygges én gang på slutten. replace=true fjerner BIM-elementene først. Svar: counts, ids, warnings, timing. |
| `get_house_spec` | `GET /sessions/{sid}/spec` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Les modellen ut som hus-spec (JSON): rediger og bygg tilbake med build_house_from_spec. meta.not_carried viser det v1 ikke bærer. |
| `configurator_link_to_spec` | `POST /spec/from-configurator` | åpen, uten innlogging | read | Konfigurator-lenke (/konfigurator/plan#c=… eller selve state) som hus-spec: omriss, etasjer, yttervegger, innervegger MED justering slik konfiguratoren bygde dem, dører/vinduer (hengsel, slå), tak, kledning. Åpen, beholder ingenting (maks 12/min). Svar: spec, counts, rooms, not_carried (det som ikke følger med). Bygg den videre med build_house_from_spec, eller åpne direkte med open_configurator_link. |
| `open_configurator_link` | `POST /spec/from-configurator/open` | innlogget | write | «Åpne i Dibrix»: bygg planen fra en konfigurator-lenke som NY økt (mode=new, standard) eller som NY VERSJON (utkast) av en økt du kan redigere (mode=version + source_sid). Den kjørende økta overskrives aldri; eieren godkjenner utkastet. Innlogget. Svar: session_id, url, counts, rooms, not_carried, warnings. Med bare propose-nøkkel: configurator_link_to_spec + build_house_from_spec på arbeidskopien + save_version. |

### Utkast: tegn først, spør etterpå (hverdagsspråk) / Draft: draw first, ask later (everyday language)

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `utkast_status` | `GET /sessions/{sid}/utkast` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Utkastet nå: «Dette har jeg antatt», høyst 3 spørsmål, varsler med rettingsknapp, felt for Enkel/Proff og kommunevalg. |
| `utkast_verktoy` | `POST /sessions/{sid}/utkast/verktoy` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Kjør ett utkast-verktøy med enums og tall: set_dimensions | set_roof_style | set_cladding_style | set_colors | add_rooms | place_openings | add_overbygg | set_site | check_rules | set_draft_prefs | draft_from_description | draw_from_image. Lagrer en versjon, bygger hus-spec på nytt (ett angresteg). |
| `draft_from_description` | BuildChat | innlogget | write | Hverdagsord -> utkast: tegner et første utkast (med antakelser) eller oppdaterer det («litt større», «to vinduer mot sør», «svalgang»). |
| `draw_from_image` | BuildChat | innlogget | write | Første utkast fra bildet brukeren la ved: form, takform, takbratthet, kledningsretning, farger, åpningsmønster, proporsjon (enums og tall). |
| `set_dimensions` | BuildChat | innlogget | write | Mål i meter (lengde, bredde, høyde) eller relativt (scale 1,15 = litt større). |
| `set_roof_style` | BuildChat | innlogget | write | Takform (gable|hip|shed|flat), takvinkel i GRADER (slope_deg, anbefalt; slope_pct i % godtas fortsatt), utstikk, taktekke, møneretning. |
| `set_cladding_style` | BuildChat | innlogget | write | Kledning: stående | liggende | ingen. |
| `set_colors` | BuildChat | innlogget | write | Farger (nøkler som hvit, sort, gra, antrasitt, rod, tre) for kledning, tak og knuter. |
| `add_rooms` | BuildChat | innlogget | write | Antall rom (skillevegger med åpen dør), layout jevnt | langsgaende. |
| `place_openings` | BuildChat | innlogget | write | Vinduer/dører etter ord: kind, count, wall_side (sor|nord|ost|vest|front|bak|venstre|hoyre|alle), distribution (senter|jevnt|hjorne_venstre|hjorne_hoyre). Regner ut posisjoner (dør 0,9 m, vinduer sentrert/jevnt). |
| `add_overbygg` | BuildChat | innlogget | write | Svalgang eller takoverbygg på en vegg (utstikk + stolper). |
| `set_site` | BuildChat | innlogget | write | Sted og tomtefakta: kommune (valg fra regelsettene eller «annen»), bruk, avstand til nabogrense osv. |
| `check_rules` | BuildChat | innlogget | read | Regelsjekk av utkastet mot nasjonale regler + kommunens regelsett: ok/brudd/ukjent med kilde, det regelsettene IKKE dekker, vennlige varsler med fiks og disclaimer. |
| `set_draft_prefs` | BuildChat | innlogget | write | Innstillinger for utkastet: mode = enkel|proff (ordvalg og felt), standardmål og grenser. |

### Mål på stedet (måle-ankere) / Site measurements (anchors)

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `list_anchors` | `GET /sessions/{sid}/agent/anchors` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Måle-ankere i økta: mål fra stedet (tastet, laser, avlest fra tegning, Finn) knyttet til vegg/åpning/etasje/side. Svar: anchors + valglistene (kind, source, side). |
| `add_anchor` | `POST /sessions/{sid}/agent/anchors` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Lagre ETT måle-anker (ett angresteg). kind: ytterlengde|bredde|dybde|hoyde_raft|hoyde_mone|etasjehoyde|apning_bredde|apning_hoyde|apning_brystning|veggtykkelse|romlengde|etasjeareal; value i unit (m|mm); source: tastet|laser|tegning|finn; én referanse: wall (vegg-id), side (nord|sor|ost|vest), opening, level, room, eller page+p0+p1 (piksler på arket). Brukeren sier «nordveggen er 8,03 m»: add_anchor(kind='ytterlengde', value=8.03, side='nord'). Ankeret skalerer skann og kontrollerer modellen. |
| `edit_anchor` | `PATCH /sessions/{sid}/agent/anchors/{aid}` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Endre et måle-anker (bare feltene du gir; ny referanse erstatter den gamle). Ett angresteg. |
| `delete_anchor` | `DELETE /sessions/{sid}/agent/anchors/{aid}` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Slett et måle-anker (ett angresteg). |
| `check_anchors` | `GET /sessions/{sid}/agent/anchors/check` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Kontroller modellen mot ankerne: per anker målt, modell og avvik (mm), status ok|advarsel|rod|ukjent. Terskel fra innstillingene anchor.warn_mm / anchor.red_mm (kan overstyres). |

### Bildetur: bilder med pinne på planen / Photo tour: photos pinned on the plan

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `list_photos` | `GET /sessions/{sid}/agent/photos` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Bildeturen: bildene i økta i turrekkefølge, filtrert på etasje (level), rom, element («D2», «V7», navn eller id), fasade (Nord/Øst/Syd/Vest), fag (arkitekt/tomrer/elektro/ror/ventilasjon/annet), vegg, kind (rett/perspektiv/oversikt/innhuk/detalj) og tidspunkt (since/until) — kombinerbare. Hvert bilde: id, name, x, y, level, yaw_deg (kompass i modellen, 0 = +y), fov_deg, fag, fasade, vegg, kind, focal_mm, focal35_mm, pixels, distance_m, target, geo, device, occlusion, hides, elements + element_names, room, note, order, taken. Svaret har også counts_by_element (antall bilder per element). |
| `add_photo` | `POST /sessions/{sid}/agent/photos` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Legg ETT bilde (jpg/png/heic) i bildeturen (ett angresteg). Originalen lagres uforandret med EXIF, miniatyr lages. Gi bildet som data_base64 (JSON) eller send filen som kropp med Content-Type image/*; pose og kobling er valgfrie: x, y (m i modellen), level (etasje-n), yaw_deg (kompass i modellen, 0 = +y/nord, med klokka), fov_deg (synsfelt, standard fra innstillingen photo.fov_deg), elements (D2, V7, navn eller id), room, note. Maskinen gjetter ALDRI posen: sett den bare når brukeren har sagt hvor bildet er tatt. Kundebilder blir i prosjektet og sendes ikke videre. Kall save_version etterpå. |
| `set_photo_pose` | `PATCH /sessions/{sid}/agent/photos/{pid}/pose` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Flytt/drei pinnen til et bilde (ett angresteg). x, y (m) og level flytter hele pinnen (alle bilder på den); yaw_deg (kompass i modellen, 0 = +y, med klokka) og fov_deg gjelder bare dette bildet; order = plass i turen; same_pin_as = id til et bilde du vil dele pinne med; unplace=true tar pinnen bort. Posen er omtrentlig: dokumentasjon, ikke måling. |
| `link_photo` | `POST /sessions/{sid}/agent/photos/{pid}/link` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Knytt et bilde til elementer, rom og notat (ett angresteg; bare feltene du gir). elements: «D2», «V7», navn eller id; mode: add (standard) | set (erstatt) | remove. Bildet viser da disse elementene, og Entity Info på elementet teller bildet. BuildChat kan foreslå «dette bildet viser D2»; brukeren bekrefter. |
| `get_photo_image` | `GET /sessions/{sid}/agent/photos/{pid}/image` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Selve bildet (original, uforandret, med EXIF) som bytes; miniatyr er .../thumb (for UI). Bare bilder i økta/prosjektet. |
| `delete_photo` | `DELETE /sessions/{sid}/agent/photos/{pid}` | innlogget | write | Slett et bilde fra turen. BARE en innlogget person med rett (oppretter, team-admin, eier, systemadmin) gjør det i appen: agenter, API-nøkler og delelenker får 403 (samme regel som sletting av versjoner). Er bildet med i «Sist godkjent»/«Som bygget»-versjonen, kreves confirm_name = prosjektnavnet (409 protected_versions). Original og miniatyr slettes fra lageret. Ingen MCP-tool. |

### Tolkebenk: oppdrag, avklaringer, rettelser og regler (C18) / Interpretation bench: tasks, clarifications, corrections and rules (C18)

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `list_tasks` | `GET /c18/tasks` | innlogget | read | Tolkebenk-oppdragene du har tilgang til (valgfritt project_id), med fremdrift (deler, akseptert, åpne spørsmål). Nøkkel: bare oppdrag i prosjekter innenfor nøkkelens omfang. |
| `get_task` | `GET /c18/tasks/{tid}` | innlogget | read | Ett oppdrag med de sju feltene, delene (status, kilde, mål, kvitteringer), avklaringene, rettelsene og målefaktatabellen (avvik over terskelen er markert). |
| `create_task` | `POST /c18/tasks` | innlogget | write | Nytt tolkebenk-oppdrag i et prosjekt (kort uten tavle): title (nøytral, uten kundenavn), project_id, user_instruction, agent_instruction. Krever redigeringsrett i prosjektet. |
| `add_task_part` | `POST /c18/tasks/{tid}/parts` | innlogget | write | Legg en del til oppdraget: kind = form | plan | vegg | rom | bilde_rom | bilde_vegg | apning | fasade | snitt | tak, label, ref (side/bilde-id), step (1 ytre form, 2 innvendig per rom og vegg, 3 ytre fasade og tak), element_ids (D2, V7), source (handmaal|laser|skann|foto|salgsoppgave|antatt) og facts (mm per kilde, «modell» = modellens mål). Delen starter som ikke_sett; aksept er et menneskes. |
| `add_clarification` | `POST /c18/tasks/{tid}/clarifications` | innlogget | write | Still et spørsmål til brukeren på oppdraget (valgfritt part_id og element_id). Et åpent spørsmål stopper aksept av delen; bare et menneske svarer. |
| `log_correction` | `POST /c18/tasks/{tid}/corrections` | innlogget | write | Logg en rettelse (rettelse): hva du hadde tolket (interpreted) og hva som var riktig (correct), med kilde (handmaal|laser|skann|foto|salgsoppgave|antatt) og element. Hver agentkjøring skal avsluttes med rettelser og regelforslag (propose_rule). |
| `propose_rule` | `POST /c18/rules` | innlogget | write | Foreslå en tolkeregel (status forslag; bare systemadmin godkjenner). Teksten er anonym: ingen navn, adresser, gnr/bnr eller prosjektnavn (renses, og avvises hvis den nevner oppdraget). task_id er påkrevd med nøkkel; correction_ids er beviset. |
| `list_rules` | `GET /c18/rules` | innlogget | read | Tolkereglene: godkjente (alle innloggede) og eget teams forslag. Anonymt: id (R12), tekst, gjelder, bevis, treff/bom. Valgfritt status = forslag|godkjent|avvist. |

### Punktsky (skann): lagre, snitt og mål fra mobil / Point cloud (scan): store, slice and measure from a phone

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `list_punktsky` | `GET /sessions/{sid}/punktsky` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Punktskyene som er lagt inn i prosjektet: id, navn, antall punkter, utstrekning (m), etasjenivåer. Skyen bygges lokalt med `python -m ingest.punktsky bygg`. |
| `punktsky_stotte` | `GET /sessions/{sid}/punktsky/{pid}/stotte` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Støttemål (tolkesjekk): andel av hver vegg, hvert dekke og hver takflate i modellen som har skypunkter innen ca. 5 cm; flagger flater under min_andel. Gjelder modeller bygget fra skyen (samme koordinater). Leser bare. |
| `upload_punktsky` | `POST /sessions/{sid}/punktsky` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Legg inn en ferdig bygd sky (kroppen = .dpc.npz, maks 80 MB; samme innhold gir samme id). Av på serveren til DIBRIX_PUNKTSKY_UPLOAD=1 (disk/backup avklares først); svarer 503 da. Skrives aldri om. |
| `delete_punktsky` | `DELETE /sessions/{sid}/punktsky/{pid}` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Slett en lagret punktsky (blob-filer i prosjektet). Bare innlogget person med slett-rett; agenter og API-nøkler får 403. Krever prosjektnavn hvis prosjektet har «Sist godkjent»/«Som bygget». |
| `get_punktsky` | `GET /sessions/{sid}/punktsky/{pid}` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | En sky: metadata (kilde, voksel, origo, rotasjon, nord, bbox) og standard snitt (plan 0,9 m over gulvet; loddrette snitt i midten). |
| `punktsky_snitt` | `GET /sessions/{sid}/punktsky/{pid}/snitt.png` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Snitt gjennom en sky som PNG: axis z (plan) | x | y, lo/hi i meter, px_per_m, grid_m, point_px, gray, u0/u1/v0/v1 for utsnitt. Mål ut av bildet: headeren X-Snitt-Info har px_per_m, utstrekning og bildestorrelse (u = u0 + px/px_per_m, v = v0 + (h-1-py)/px_per_m). 404 når snittet er tomt. |
| `punktsky_mobil` | `GET /sessions/{sid}/punktsky/{pid}/mobil` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Lett side for mobil (ikke 3D): velg plan eller snitt, dra glidebrytere, trykk to punkter for å måle avstanden. Samme lenke som skyen, med /mobil bak. Legg ?share=… eller innlogging som ellers. |
| `punktsky_viewer` | `GET /sessions/{sid}/punktsky/{pid}/viewer` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Full 3D-viewer (Three.js): orbit, navigere og måle i 3D. Samme produkt som python -m ingest.punktsky viewer / *_viewer.html — ikke PNG-snittet /mobil. Bruk denne når brukeren vil se skyen i 3D. |
| `punktsky_points` | `GET /sessions/{sid}/punktsky/{pid}/points.bin` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Binær xyz(+rgb) for å tegne skyen i Draw modell-3D sammen med vegger/tak (T-1912). Query max=LOD-tak (standard 54000). Header X-Punktsky-Points har n/n_full. Ikke viewer-HTML. |
| `punktsky_infrastruktur` | `POST /sessions/{sid}/punktsky/{pid}/infrastruktur` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Finn infrastruktur-møbler i en punktsky: toalett, servant, badekar, dusj, trapp, pipe/skorstein og peis (og vinduer/dører i veggbildene). Hvert funn: type, etasje, sentrum, rot_deg (fronten), mot_vegg, skann_maal_m, maal_m (forslag; standard når skannet er usikkert), sikkerhet, status (usikker = rødt, bekreft_maal = oransje) og spor (ETT mål å bekrefte). Trapper er alltid røde (antall trinn oppgis). plasser=true setter funnene inn som bibliotekkomponenter / parametrisk trapp og pipe i riktig etasje. Veggbildene (1 cm/px, sett fra rommet) hentes med punktsky_veggbilde. Tersklene er brukerinnstillinger skann_infra.* (get_prefs). |
| `punktsky_veggbilde` | `GET /sessions/{sid}/punktsky/{pid}/veggbilde/{navn}.png` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Et veggbilde (PNG, 1 cm/px, punktene fra 8 cm bak til 0,9 m foran veggen, sett fra rommet) fra punktsky_infrastruktur: bruk veggbilder[].url. |
| `bekreft_skann_funn` | `POST /sessions/{sid}/skann-funn/bekreft` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Tegneren har målt et skann-funn (gruppe fra punktsky_infrastruktur plassering): sett bredde_m/dybde_m/hoyde_m og merk det bekreftet (ikke lenger rødt/oransje). Uten mål: bare bekreft typen og målet som står. |

### Fasadefoto: tagger på veggen → mål → hus-spec / Facade photo: tags on the wall → measurements → house spec

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `facade_photo_families` | `GET /fasadefoto/families` | innlogget | read | Taggfamiliene serveren kan lese (AprilTag 36h11/36h10/25h9/16h5, ArUco) og brukerens innstillinger: familie, taggstørrelse (svart kant, mm), mm per piksel, rutenett. |
| `facade_photo_rectify` | `POST /fasadefoto/rectify` | innlogget | read | Ett fasadebilde (base64) med utskrevne tagger på veggen → tagger med id, felles homografi G (plan u,z i meter → bildepiksler), kvalitet (restfeil mm, størrelsesavvik mellom taggene), avstander mellom taggene, og et rettet bilde i meter med rutenett (rect_jpeg_b64 + rect). family=auto prøver alle. Uten tagger: corners_px (4 klikk) + width_m + height_m. known_distances=[{a, b, m}] (laser) avslører feil taggstørrelse. Lagrer ingenting. |
| `facade_photo_measure` | `POST /fasadefoto/measure` | innlogget | read | Mål i det rettede fasadebildet: ground = to punkt på bakkelinjen (venstre og høyre hjørne), boxes [{x0, y0, x1, y1, kind}], points, lines (etasjeskille). Med rect er alt i piksler i det rettede bildet. Svar i meter: left_m fra venstre hjørne, width_m, bottom_m over bakken, height_m, length_m. |
| `facade_photo_suggest` | `POST /fasadefoto/suggest` | innlogget | read | Forslag til vinduer og dører i et fasadebilde (konturer i det rettede bildet, lokalt, uten KI): bokser i rect-piksler; med ground blir høye bokser på bakken dører. Brukeren godkjenner antall og form. Innstillingen foto.suggest=off gir ingen forslag. |
| `facade_photo_spec` | `POST /fasadefoto/spec` | innlogget | read | Fasadene til en grov hus-spec: storeys [{name, kind kjeller|etasje, floor_m over bakken, material mur|tre}], lengths {sor|nord|ost|vest: {etasje: m}}, heights {ug_gesims_m, og_gesims_m, mone_m} (laser fra bakken), roof {form saltak|valm|pult|flatt, pitch_deg?, ridge ow|ns|auto, low_side, overhang_m}, openings [{facade, kind, left_m, width_m, bottom_m, height_m}]. Bygg svaret med build_house_from_spec. Samme tagg-id i to fasader gir notatet shared_tag. |

### Faser, rehab, tidsplan (4D) og kost (5D) / Phases, rehab, schedule (4D) and cost (5D)

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `list_phases` | `GET /sessions/{sid}/phases` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Fasene i modellen (eksisterende, rivning, nybygg, tilbygg …) med antall element per fase og kind, status, datoer, farge og skjult/vist. Element uten fase er i «ny» (Nytt). elements=true gir element→fase. |
| `create_phase` | `POST /sessions/{sid}/phases` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Ny fase: name, kind (existing|demolition|new|custom; eksisterende vises grå og koster 0, rivning koster rivepris), color #rrggbb, start/end ÅÅÅÅ-MM-DD, deps (fase-id-er som må være ferdige først), status planlagt|pågår|ferdig. Ett angresteg. |
| `set_phase` | `POST /sessions/{sid}/phases/{pid}` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Endre en fase (navn, farge, status planlagt|pågår|ferdig, start/slutt, deps, kind, rekkefølge). Ett angresteg. |
| `delete_phase` | `DELETE /sessions/{sid}/phases/{pid}` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Fjern en fase; elementene i den faller tilbake til «ny». Ett angresteg. |
| `add_phase_presets` | `POST /sessions/{sid}/phases/presets` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Legg til forvalgsfaser (eksisterende, rivning, ny, tilbygg, utvendig, innvendig, ferdig); ids = bare disse. Eksisterende faser beholdes. |
| `assign_phase` | `POST /sessions/{sid}/phases/{pid}/assign` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Legg elementer i en fase: element_ids, og/eller alle av kind (wall|roof|slab|door|window …), level, wall_type; all_elements=true tar alt; selection=true de valgte. Kledning, dørblad og vindusramme følger verten; en dør kan ha egen fase. phase «ny» = standard. Ett angresteg. |
| `set_phase_visibility` | `POST /sessions/{sid}/phases/visibility` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Vis/skjul/farge per fase i 3D: hidden (fase-id-er som skjules; erstatter listen), mode phase (fasefarge) | material, existing_grey. Ett angresteg. |
| `plan_summary` | `GET /sessions/{sid}/plan` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Alt om planen i ett svar: faser, Gantt (rader med datoer, slakk og kritisk sti, ressursdager), kost per fase og kind (5D), kostkurve per måned (S-kurve) og avvik mot budsjett. |
| `plan_tasks` | `GET /sessions/{sid}/plan/tasks` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | 4D: oppgavene med datoer, slakk og kritisk sti (Gantt-data). |
| `set_task` | `POST /sessions/{sid}/plan/tasks` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Legg til/endre én oppgave: id?, name, phase, duration_d (arbeidsdager), deps (task-id eller {id, lag_d}), resource, kinds (wall …), elements (id-er), start ÅÅÅÅ-MM-DD, pct. Avvises med norsk feil ved syklus. Ett angresteg. |
| `delete_task` | `DELETE /sessions/{sid}/plan/tasks/{tid}` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Fjern en oppgave. Ett angresteg. |
| `suggest_plan` | `POST /sessions/{sid}/plan/suggest` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Foreslå tidsplan: tasks per fase og byggegruppe (dekker, vegger, åpninger, tak …) med varighet fra mengder og produktivitet (estimat). apply=true (standard) erstatter tasks. start ÅÅÅÅ-MM-DD, crew = antall lag. |
| `set_plan_settings` | `POST /sessions/{sid}/plan/settings` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Plan-innstillinger: start, calendar work5|all, unit_prices {'wall:ytter_250'|'wall'|'roof'|'rive:wall'…: {unit m2|m3|m|stk, nok}}, overrides {element-id: kr}, budget {total, phases:{fase: kr}}. Hver nøkkel som sendes erstatter sin del. Ett angresteg. |
| `plan_visible_at` | `GET /sessions/{sid}/plan/visible` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | 4D-animasjon: element-id-ene som står på en dato (ÅÅÅÅ-MM-DD): visible, hidden, progress 0..1. Eksisterende står alltid, revet forsvinner etter rivefasen. |
| `plan_timeline` | `GET /sessions/{sid}/plan/timeline` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Jevnt fordelte datoer fra plan-start til slutt med antall synlige element (forhåndsvisning av byggefremdriften). |
| `set_plan_date` | `POST /sessions/{sid}/plan/date` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | 4D i 3D: skjul det som ikke er bygget på en dato (ÅÅÅÅ-MM-DD) for alle som ser økta; date=null viser alt. Endrer ikke modellen (ikke i angrehistorikken). Svar: progress 0..1, antall synlige/skjulte. |
| `plan_snapshot` | `GET /sessions/{sid}/plan/snapshot` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Faser, plan og kostoppsummering som JSON (det en versjonspost lagrer i phases/plan). Bruk cost-delen i compare_cost. |
| `cost_summary` | `GET /sessions/{sid}/cost` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | 5D: kost per fase og kind, uten-pris-antall, budsjett og avvik, kostkurve per måned. Pris: overstyring, egne enhetspriser, konfiguratorens prisgrunnlag. rows=true gir kost per element. |
| `compare_cost` | `POST /sessions/{sid}/cost/compare` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Kostnad før/etter: before (cost-oppsummering fra plan_snapshot eller en versjonspost) eller with_session (annen økt) mot after (utelatt = modellen nå). Svar: total, per fase og per kind med før, etter, delta, prosent. |
| `mark_all_existing` | `POST /sessions/{sid}/rehab/mark-existing` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Start på et rehab-prosjekt: legg ALLE elementer i fasen «eksisterende» (grå, koster 0). Lager forvalgsfasene ved behov. Deretter assign_phase(phase="ny"|"rivning"|"endres", …) på det som skal endres. Ett angresteg. |
| `show_phases_only` | `POST /sessions/{sid}/rehab/show` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Filter i 3D: vis bare fasene med disse kind-ene (existing|demolition|new|modified|custom) eller fase-id-ene; utelatt = vis alt. Ett angresteg. |
| `rehab_summary` | `GET /sessions/{sid}/rehab` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Rehab i ett svar: elementer per status (eksisterende/rives/ny/endres), kost per fase (arbeid/materiell/mva; intervall når pris mangler), utførende, varer og tidsplan. |
| `rehab_report` | `GET /sessions/{sid}/rehab/report.json` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Hele kunderapporten som JSON: per fase hva som endres, hva det koster (arbeid/materiell/mva, usikkerhet som intervall), hvem som utfører, hva som må kjøpes og tidsplan; baseline=true (standard) tar med «sist godkjent av kommunen» og «endret siden». |
| `rehab_report_html` | `GET /sessions/{sid}/rehab/report.html` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Kundevennlig rapport som HTML (utskriftsvennlig, lagre som PDF fra nettleseren). Fungerer også med en viewer-lenke. |
| `rehab_report_csv` | `GET /sessions/{sid}/rehab/report.csv` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Rehab-rapporten som CSV (semikolon, UTF-8): oversikt, poster, utførende, varer, tidsplan. |
| `rehab_report_xlsx` | `GET /sessions/{sid}/rehab/report.xlsx` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Rehab-rapporten som Excel (.xlsx, ett ark per del; uten ekstra avhengigheter). |
| `set_work_item` | `POST /sessions/{sid}/rehab/work-items` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Arbeidspost i en fase: {phase, kind | element_ids, name?, qty? (utelatt = fra modellen), unit?, labor?, material? (kr per enhet; utelatt = prisliste, ellers «ukjent»), performer?: {role, name}, id?}. Samme id erstatter. Ett angresteg. |
| `delete_work_item` | `DELETE /sessions/{sid}/rehab/work-items/{wid}` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Fjern en arbeidspost (den automatiske linjen per fase og type kommer tilbake). Ett angresteg. |
| `set_performer` | `POST /sessions/{sid}/rehab/performers` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Standard utførende for en fase: role Entreprenør|Tømrer|Elektriker|Rørlegger|Maler|Selvbygger/kunde (eller fritekst), name = firma/person; role tom = fjern. Ett angresteg. |
| `set_goods_item` | `POST /sessions/{sid}/rehab/goods` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Vare som må innhentes: {name, phase, supplier, qty, unit, unit_price, deadline ÅÅÅÅ-MM-DD, status planlagt|bestilt|levert, id?}. Samme id erstatter. Ett angresteg. |
| `delete_goods_item` | `DELETE /sessions/{sid}/rehab/goods/{gid}` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Fjern en vare fra innkjøpslisten. Ett angresteg. |
| `get_pricelist` | `GET /sessions/{sid}/rehab/pricelist` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Prosjektets prisliste (JSON). Uten lagret liste: tom eksempelmal (enheter, ingen priser). |
| `set_pricelist` | `POST /sessions/{sid}/rehab/pricelist` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Sett prisliste: pricelist {items: {"wall"|"wall:ytter_250"|"rive:wall"…: {unit, labor, material, labor_low/high, material_low/high}}, vat_pct} eller csv_text (kolonner key;unit;labor;material;…). Uten argumenter lagres tom eksempelmal. Ukjent pris = null (markedspriser blir aldri funnet på). Ett angresteg. |

### Komponenter (parametriske møbler og sanitær) / Components (parametric furniture and sanitary)

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `find_component` | `GET /library` | åpen, uten innlogging | read | Søk i komponentbiblioteket: Dibrix' parametriske møbler, kjøkken, hvitevarer og sanitær (seng, sofa, spisebord, kjøkken-underskap, kjøleskap, vaskemaskin, badekar, toalett …; id dibrix-furn-<type>, params med område) og dør- / vindustyper. q, category, page. Hver treff har id, navn, mål i cm og params. Ingen mesh-katalog. Åpen, uten økt. Miniatyr (SVG): GET /library/{id}/thumb. |
| `library_thumb` | `GET /library/{id}/thumb` | åpen, uten innlogging | read | Miniatyr (SVG) av en komponent, cachet. |
| `insert_component` | `POST /sessions/{sid}/library/insert` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Sett inn et parametrisk møbel (id fra find_component, f.eks. dibrix-furn-seng) med midten av bunnen i (x, y, z) meter, rot grader om Z; size_m=[b, d, h] i meter gir møbelets størrelse (innenfor typens område); params = typens øvrige parametre (sink, drawers, appliance, round …). Front mot -y, rygg / vegg mot +y; kjøkkenmoduler med samme y står på linje. Instans av en DELT prototype (lett selv med hundrevis), ett angresteg. Uten x og y startes klikk-plassering i modellen. Samme id brukes i hus-spec furniture[].ref. |

### Inspiser og velg / Inspect & select

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `inspect` | MCP | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Oversikt: flater/kanter/etasjer, antall per type, problemer, arealer, lenke. Start her. |
| `plan_build` | MCP | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Gjør et mål om til en kort plan ut fra modellen (endrer ingenting). |
| `query` | `GET /sessions/{sid}/query` | sandkasse (anonym) eller innlogget | read | Rå modellstatus (flater, kanter, utvalg, verktøy). |
| `list_entities` | `GET /sessions/{sid}/agent/entities` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | loose=true tar ogsa med grupper og komponenter som ikke er BIM-elementer (id g<uid>, kan velges og slettes). List BIM-elementer (vegger, dekker, tak …); problems_only=true finner dårlige skjøter. |
| `get_entity` | `GET /sessions/{sid}/agent/entities/{eid}` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Ett element med mål, payload og helse. |
| `select_entities` | `POST /sessions/{sid}/agent/select` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Velg elementer etter id i den levende visningen. |
| `select_all` | `POST /sessions/{sid}/selection/all` | innlogget | write | Velg alt (Ctrl+A). |
| `select_box` | `POST /sessions/{sid}/selection/box` | innlogget | write | Velg med rektangel (vindu/kryssing). |
| `delete_selection` | `POST /sessions/{sid}/selection/delete` | innlogget | write | Slett det som er valgt (angre virker). |
| `get_selection_props` | `GET /sessions/{sid}/selection/props` | innlogget | read | Egenskaper for utvalget (Entity Info). |
| `set_selection_props` | `POST /sessions/{sid}/selection/props` | innlogget | write | Endre egenskaper på utvalget (veggtype, høyde, stil …). |
| `transform_selection` | `POST /sessions/{sid}/selection/transform` | innlogget | write | Speil eller roter utvalget (høyreklikk ▸ Speil / Roter). |
| `duplicate_selection` | `POST /sessions/{sid}/selection/duplicate` | innlogget | write | Kopier det valgte (vegger med dører/vinduer, grupper) dx/dy meter i plan; kopiene blir valgt (Ctrl+D / Ctrl+C, Ctrl+V). |
| `copy_selection` | `POST /sessions/{sid}/selection/copy` | innlogget | read | Husk utvalget for innliming (Ctrl+C); duplicate_selection(source='clipboard') limer inn. |
| `list_buildings` | `GET /sessions/{sid}/buildings` | innlogget | read | Bygninger i modellen. |
| `select_building` | `POST /sessions/{sid}/building/select` | innlogget | write | Velg aktiv bygning. |
| `element_props` | `GET /sessions/{sid}/agent/elements/{eid}/props` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Endrer ingenting: Entity Info-feltene til ett element (nøkkel, type, lovlige valg) og nåverdiene, med id (GUID), short_id (8 tegn) og navn. Elementet kan oppgis som id, short_id eller navn («D3»). Bruk FØR set_element_props. |
| `set_element_props` | `POST /sessions/{sid}/agent/elements/props` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Endre egenskaper på ett eller flere elementer som i Entity Info (height_m, thickness_m, wall_type, join_mode, cladding.on …); ukjente nøkler avvises. Ett angresteg. Sprosset glassdør (dørtype glass/helglass): style.glass_cols og style.glass_rows 1-4 (ruter bortover/oppover), style.glass_h (glassets del av bladet 0,2-1,0; 1 = hele bladet), style.glass_bar_w (sprossebredde i m), leaf_state open|closed; tegnes i 2D (dørlisten) og 3D, også for dobbeltdør (leaf_type glass). Vindu med overlys/lufteklaff: style.overlys_h (m, feltet over hovedglasset, del av vindushøyden; 0 = ingen) og style.vent ingen|spalte|klaff (ventilspalte i overlyset / toppstyrt lufteklaff; vent uten overlys_h gir 0,20 m); tegnes i 3D, fasade og vindusliste. |
| `control_measure` | `POST /sessions/{sid}/agent/elements/control-measure` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Kontrollmåling: brukerens mål (tekst eller lest fra bilde av målebånd/laser) mot modellen. items [{ref «D3»/«V4»/navn eller id, width_m, height_m, sill_m, offset_m, source, confidence, note}], rules for flere (refs + mål, f.eks. alle faste glassfelt 0,90 x 2,10), source, at. Innenfor toleranse (innstillinger buildchat.tol_opening_cm, standard ±2 cm; rom ±5 cm): målet settes, taggen «Antatt (tolket)» fjernes og «Kontrollmålt» legges på (bare sporing, ingen farge: objektet beholder sin opprinnelige farge). Over toleransen: målet settes likevel, taggen blir «Avvik målt» (rød) og svaret har forskjellen. Målt verdi, kilde og tid lagres på elementet. Svaret: results per element (model_before_m, measured_m, diff_m, status), within_tolerance, deviations, failed. Kall save_version etterpå. |
| `list_sources` | `GET /sessions/{sid}/agent/sources` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Alt Dibrix vet om huset som kilder, samlet: tegningsfiler (PDF/bilder fra Last opp, dra-og-slipp og BuildChat, med sider, om sidene og modellen er lagt inn og om et første utkast står), lasermål/ankere og brukerens beskrivelse i chatten. Tolkeren får lasermål og beskrivelsen sammen med sidene. Kilde og sikkerhet per element står i element_props (source_info, source_conf, source_how). |

### Se: bilde, kamera, sammenligning / See: picture, camera, compare

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `render` | `GET /sessions/{sid}/render.png` | sandkasse (anonym) eller innlogget | read | Bilde (PNG) av økta uten nettleser: view=iso|front|back|left|right|top|bottom, layers=a,b (bare disse), hide=lag/type/id, focus=<element-id|selection|x0,y0,z0,x1,y1,z1> (kommaseparert streng, ikke JSON-objekt), section=z:2.4, projection, w/h, side_by_side=<sid2>. isolate=<id|short_id|navn,…> tegner BARE de elementene (en dør med bladene sine, ingen vegg eller annen dør foran) og rammer inn det første: nærbilde av ett element. Se på modellen etter hver endring. |
| `render_index` | `GET /sessions/{sid}/render.json` | sandkasse (anonym) eller innlogget | read | Hva som er hvor i bildet render ville gitt (samme parametre): hvert element med piksler, senter og boks, og med at=x,y;x,y elementet under pikselen. Gjør «vinduet ved piksel (500,300)» om til en element-id. Sender ikke bildet. |
| `scene_summary` | `GET /sessions/{sid}/scene-summary` | sandkasse (anonym) eller innlogget | read | Kompakt JSON om økta uten å bygge mesh: antall per type, boks per element, lag, etasjer, referansegrupper. Start her på store filer. |
| `get_camera` | `GET /sessions/{sid}/camera` | sandkasse (anonym) eller innlogget | read | Agentens eget kamera (eye, target, projeksjon). Nettleserens kamera er klientens. |
| `set_camera` | `POST /sessions/{sid}/camera` | sandkasse (anonym) eller innlogget | read | Sett agentens kamera: preset (iso/front/…) eller eye+target, projection, zoom_to=all|selection|<element-id>. Brukes av render uten view. Endrer ikke modellen. |
| `compare` | `GET /sessions/{sid}/compare` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Sammenlign to økter (original og tolket): bbox, areal, volum, antall per type, og valgfritt ett bilde ved siden av hverandre. |
| `set_layers` | `POST /sessions/{sid}/layers` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Vis/skjul flere lag i ett kall: show=[…], hide=[…], only=[…] (alle andre av), all=true. Navn velges fra list_tags; ukjent navn gir 404 med «mente du …?»; et navn som slutter på * er et prefiks («Sist godkjent*» = alle underlagene fra godkjente tegninger). Endrer hva mennesket ser; for bare et bilde bruk render?layers=&hide=. |
| `list_tags` | `GET /sessions/{sid}/tags` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Merkelappene du kan VELGE mellom: etasjer (egen gruppe, med synlighet og antall) og lag/tagger. Bruk id/navn herfra i set_layers, set_selection_props (layer, tags, storey) og render?layers=; skriv aldri navn fra hukommelsen. Ukjente navn avvises med «mente du …?». |
| `create_tag` | `POST /sessions/{sid}/tags` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Ny merkelapp: den ene, eksplisitte veien til en ny tagg. Unike, normaliserte navn: «1.etasje» ved siden av «1. etasje» avvises (422 med did_you_mean). Nesten-likt navn krever confirm_similar=true. |
| `session_status` | `GET /sessions/{sid}/status` | sandkasse (anonym) eller innlogget | read | Status for økta: laster en stor fil (fase, fremdrift) eller klar; bruk etter opplasting av store igz/skp. |

### Vegg (yttervegg) / Wall (exterior)

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `draw_walls` | `POST /sessions/{sid}/agent/walls` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Tegn veggløp: corners=[[x,y],…] i meter; closed=true for en ring. wall_type for innervegg. |
| `draw_rectangle` | MCP | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Rektangulært fotavtrykk (vegger), valgfritt dekke og tak. |
| `wall_segment` | `POST /sessions/{sid}/wall` | innlogget | write | Én vegg a→b over vanlig økt-API (fallback når agent/* er stengt). |
| `bim_wall` | `POST /sessions/{sid}/bim/wall` | innlogget | write | Én BIM-vegg a→b. |
| `house` | `POST /sessions/{sid}/house` | innlogget | write | Hel bygning fra form (rect, L, T, H, U …): vegger, dekke, tak, vinduer og dør. |
| `heal_problems` | MCP | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Finn problemvegger og -tak og reparer dem (eller ett element med eid). |
| `heal_wall` | `POST /sessions/{sid}/agent/walls/{eid}/heal` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Bygg én vegg på nytt fra sin payload (reparer skjøt). |
| `heal_walls` | `POST /sessions/{sid}/agent/walls/heal` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Lukk alle åpne vegger (ingen åpne kanter, også toppen når taket mangler eller er ødelagt). ids=[…] for bare noen. Ett angre-steg. |
| `corner_boards` | `POST /sessions/{sid}/facade/corner_boards` | innlogget | write | Hjørnekasser av/på. |
| `walls_to_roof` | `POST /sessions/{sid}/walls/to_roof` | innlogget | write | Yttervegger følger takets underside. |
| `get_wall_types` | `GET /sessions/{sid}/wall-types` | innlogget | read | Veggtype-biblioteket (tykkelse, lag, bindingsverk). |
| `set_wall_types` | `PUT /sessions/{sid}/wall-types` | innlogget | write | Erstatt veggtype-biblioteket; vegger av endret type følger. |
| `rebuild_entity` | `POST /sessions/{sid}/agent/entities/{eid}/rebuild` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Bygg ett element på nytt med endrede payload-felt (veggtype, takform, dørstil …). |
| `delete_entities` | `POST /sessions/{sid}/agent/delete` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Slett elementer etter id (åpninger lukker hullet). |
| `clear_model` | `POST /sessions/{sid}/agent/clear` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Slett alle BIM-elementer (for test/reset). |
| `batch` | `POST /sessions/{sid}/agent/batch` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Flere operasjoner i én forespørsel: walls, slab, roof, house, terrain, delete, clear … |
| `set_storeys` | `POST /sessions/{sid}/agent/storeys` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Lag/endre etasjer (navn, z, h) og knytt elementene til dem (alle, id-liste, eller etter høyde), kjør etasjemerking og revisjon, ett angresteg. Bruk når leveringssjekken sier «etg.uplassert» eller modellen mangler etasjer. Uten storeys lages én «1. etg» fra modellens høyde. |
| `tag_by_storey` | `POST /sessions/{sid}/agent/storeys/tag` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Reparer etasjemerking: merk ALLE elementer (vegger, dekker, tak, åpninger, trapper, rom, stendere, kledning, rekkverk) med etasjetagg ut fra etasjelisten og høyde. Bruk når «GET /tags» viser 0 elementer per etasje eller en 2D-/3D-etasjescene viser hele huset. Idempotent (i takt = ingen endring), ett angresteg. |
| `add_stair` | BuildChat | innlogget | write | Trapp fra aktiv etasje til neste, med trappehull i dekket (rett, L eller U; TEK17). |
| `stair_in_shape` | `POST /sessions/{sid}/agent/stairs/shape` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Trapp i form: en lukket form i plan (tegnet flate, trappehull, skannets fotavtrykk) og startkanten gir trappa som fyller formen. Rektangel -> rett løp, L-form -> kvartsvingt, U-form -> halvsvingt, med svingtrinn eller repos (innstillingen stair.corner). Antall opptrinn fra etasjehøyden (2R + G = 620 ± 20, SlimBim-reglene); lås tall med locks {riser_count, flight_tread_counts: [før, etter svingen], winder_count}. Hullet i etasjeskillet blir formen. dry_run=true viser tallene og røde varsler uten å endre modellen. |
| `move_walls` | `POST /sessions/{sid}/agent/walls/move` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Flytt vegger i planen (dx, dy meter): sammenhengende hjørner strekkes, åpninger følger. Samme kode som Flytt-verktøyet. |

### Innervegg / Inner wall

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `draw_inner_wall` | `POST /sessions/{sid}/agent/walls` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Innervegg: draw_walls med wall_type='inner_98' (eller annen innerveggtype), closed=false. |

### Åpning (dør/vindu/port) / Opening (door/window/gate)

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `place_opening` | `POST /sessions/{sid}/agent/openings` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Dør/vindu/port i vegg host_id: offset_m langs veggen, width_m, height_m, sill_m. Rundt vindu: shape='circle' (width_m = diameter); rundbue: shape='arch' (arch_rise_m = stikk, standard halvsirkel). Trekant-/gavlvindu: outer_loop_uv=[[u,z],...] (z absolutt). |
| `face_opening` | `POST /sessions/{sid}/selection/face-opening` | innlogget | write | Dør/vindu/åpning i valgt flate. |
| `delete_openings` | `POST /sessions/{sid}/selection/delete-openings` | innlogget | write | Slett valgte åpninger og lukk hullet. |
| `edit_opening` | `POST /sessions/{sid}/agent/openings/edit` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Flytt/endre dør eller vindu i en vegg: offset_m (langs veggen), width_m/height_m/sill_m (midten beholdes), flip (slagretning), delete, shape rect|circle|arch (rundt vindu / rundbue, arch_rise_m = stikk). Samme kode som håndtakene i planen. |

### Dekke og gulv / Slab & floor

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `fit_slab_to_walls` | `POST /sessions/{sid}/agent/slabs/{eid}/fit` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Legg omrisset til et dekke (terrassedekke) på ytterflatene til vegger (wall_ids; tomt = terrasse-bod-veggene ved dekket) pluss margin_m, behold id. follow (standard): dekket følger veggene når de flyttes eller får ny tykkelse. slab_type=terrasse + thickness_m 0,10-0,20 gjør det til lett terrassedekke. Danner veggene bare en åpen U (fjerde side er bygningsveggen), lukkes omrisset over åpningen og svaret har warnings + suggest_wall_id (veggen å legge til); faller arealet mer enn 50 % nektes det uten force=true. Ett angre-steg. |
| `add_slab` | `POST /sessions/{sid}/slab` | innlogget | write | Dekke/gulv fra en ring boundary=[[x,y],…] (eller fra veggene). |
| `slab_from_walls` | `POST /sessions/{sid}/slab_from_walls` | innlogget | write | Dekke på yttervegg-ringen: kind='sole' (såle under veggene, topp = veggenes z0) eller 'floor' (etasjeskille på veggtoppene, veggene under følger undersiden). Følger veggene når de flyttes. Neste etasje bygges ikke: next_storey_z0 sier hvor den starter. Ett angre-steg. |
| `slab_from_walls_status` | `GET /sessions/{sid}/slab_from_walls` | innlogget | read | Lukkede veggringer per etasje: har de såle / etasjeskille, og hva «Dekke» foreslår. |
| `heal_slab` | `POST /sessions/{sid}/agent/slabs/{eid}/heal` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Legg et dekke fra vegger tilbake på veggene: omriss på ringen, høyde på veggene, veggene under et etasjeskille følger det. Helse før/etter. Ett angre-steg. |

### Tak, ark og takvindu / Roof, dormer & roof window

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `add_roof` | `POST /sessions/{sid}/roof_from_walls` | innlogget | write | Tak over ytterveggene: form gable|hip|shed|flat. |
| `heal_roof` | `POST /sessions/{sid}/agent/roofs/{eid}/heal` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Reparer et tak og veggene under: omriss på veggene, saltak pr fløy, gavlvegger opp til taket, veggtopper. Helse før/etter. Ett angre-steg. |
| `join_roofs_as_t` | `POST /sessions/{sid}/agent/roofs/join_t` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Slå sammen to tak til ett T-tak med kehl (samme som leveringssjekk tak.sammenfoying). Største fotavtrykk = hovedtak. Ett angre-steg. |
| `list_roof_finishes` | `GET /sessions/{sid}/agent/roofs/finishes` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Lovlige verdier for taktekking og tilbehør: tekketyper med farger, vindski/renne/nedløp-brytere, trimfarger, og hvert taks nåværende finish. Gjett aldri nøkler. |
| `set_roof_finish` | `POST /sessions/{sid}/agent/roofs/finish` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Takshingel/takstein/falset, farge, vindski, takrenne, nedløp, israft, snøfanger på ett eller alle tak i ETT kall (samme vei som Tak-dialogen, ett angresteg). Bruk denne for «takshingel», «sort takstein», «vindski og takrenner»; ikke utforsk payload. downpipe_ends = nedløpets ende: samme|syd|nord|ost|vest|start|slutt|begge|ingen|auto, eller per langside {"vest": "syd"} («nedløp mot syd på begge sider» = downpipe_ends="syd"). |
| `roof` | `POST /sessions/{sid}/roof` | innlogget | write | Tak fra et eget omriss. |
| `building_roof` | `POST /sessions/{sid}/building_roof` | innlogget | write | Tak for en bygning (kanter: fall/gavl). |
| `dormer` | `POST /sessions/{sid}/dormer` | innlogget | write | Ark (kvist) i taket. |
| `roof_window` | `POST /sessions/{sid}/roof_window` | innlogget | write | Takvindu. |
| `roof_window_catalog` | `GET /roof_windows/catalog` | åpen, uten innlogging | read | Katalog over takvindustørrelser. |

### Terrasse, rekkverk, pergola / Deck, railing, pergola

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `deck` | `POST /sessions/{sid}/deck` | innlogget | write | Terrasse/platting. |
| `railing` | `POST /sessions/{sid}/railing` | innlogget | write | Rekkverk. |
| `roof_on_columns` | `POST /sessions/{sid}/roof_on_columns` | innlogget | write | Tak på søyler (pergola, carport). |

### Etasje / Storey

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `list_levels` | `GET /sessions/{sid}/levels` | sandkasse (anonym) eller innlogget | read | Etasjer (navn, z, høyde). |
| `ensure_levels` | `POST /sessions/{sid}/levels/ensure` | sandkasse (anonym) eller innlogget | write | Sørg for standard etasjeliste. |
| `set_active_level` | `POST /sessions/{sid}/levels/active` | sandkasse (anonym) eller innlogget | write | Aktiv etasje (der nye vegger tegnes). |
| `save_levels` | `POST /sessions/{sid}/levels/save` | innlogget | write | Lagre etasjelisten (rader: navn, z, høyde). |

### Rom og areal / Rooms & areas

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `list_rooms` | `GET /sessions/{sid}/agent/rooms` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Rom i modellen: id, navn, nummer, areal, etasje, farge. |
| `edit_room` | `POST /sessions/{sid}/agent/rooms/edit` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Gi ett eller flere rom navn (fra romlisten: Stue, Soverom …), nummer (unikt per etasje), farge eller bruksenhet; én angre. |
| `rebuild_rooms` | `POST /sessions/{sid}/agent/rooms/rebuild` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Legg rom (alle, eller ids) på veggflatene rundt dem etter at en vegg fikk ny tykkelse eller plass. Id, navn, nummer, enhet og farge beholdes; rom som ikke er lukket av vegger står urørt og svaret sier hvorfor (reason + missing: vegg-id-er, glipp i cm, sted). Skjøter som glipper opptil 12 cm lukkes (2/6/12 cm, som detect_rooms). Ett angre-steg. Rom følger også av seg selv når tykkelsen endres (opptil 0,3 m). |
| `set_terrace_shed` | `POST /sessions/{sid}/agent/rooms/{eid}/terrace_shed` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Gjør et rom (og veggene som bare omslutter det) til terrasse-bod: lett rom på en terrasse utenfor bygningskroppen, uten BRA, BTA og BYA (står under utebygg i measure_areas). on=false angrer. Ett angre-steg. |
| `detect_rooms` | `POST /sessions/{sid}/rooms/detect` | innlogget | write | Finn rom fra veggløkker og sett romnavn. Tåler glipper opptil 12 cm i skjøtene; count 0 forklares i report (løkker per toleranse, åpne skjøter med vegg-id og sted). |
| `measure_areas` | `GET /sessions/{sid}/composer/areas` | sandkasse (anonym) eller innlogget | read | BYA / BTA / BRA (NS 3940) for planen. |
| `areas_sheet` | `POST /sessions/{sid}/composer/areas/sheet` | innlogget | write | Arealtabell som ark. |

### Snitt / Section

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `list_sections` | `GET /sessions/{sid}/sections` | innlogget | read | Snittplan i modellen (uid, symbol, punkt, normal). |
| `create_section` | `POST /sessions/{sid}/sections` | innlogget | write | Nytt snittplan (punkt+normal) og snittscene. |
| `edit_section` | `POST /sessions/{sid}/sections/edit` | innlogget | write | Rediger snitt i plan: op=create (from,to) | drag (uid, part, from, to; ende = drei + forleng) | flip | symbol | activate | delete | extent (uid, extent=[a,b] m utenfor bygget, 0,5-20; tom = følg bygget). |
| `patch_section` | `PATCH /sessions/{sid}/sections/{uid}` | innlogget | write | Flytt/snu/omdøp et snittplan. |
| `delete_section` | `DELETE /sessions/{sid}/sections/{uid}` | innlogget | write | Slett et snittplan. |
| `move_section` | `POST /sessions/{sid}/agent/sections/move` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Flytt/drei/døp om et EKSISTERENDE snitt (aldri lag et nytt i stedet): section=«Snitt-AA»|«A»|uid, x/y (hvor linja skal stå), offset, axis, rotate_deg, extent, new_name, new_symbol. avoid_walls=true: ligger snittet langs en vegg, flyttes det til midten av nærmeste rom (svaret sier hvilken vegg og hvorfor). Samme vei som å dra snittlinja i planen: scenen, arkene og snittmerkene følger med. |
| `suggest_section_position` | `GET /sessions/{sid}/agent/sections/suggest` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Endrer ingenting: vegger snittet treffer nå, og hvor det kan stå uten å treffe en vegg (midt i nærmeste rom), med begrunnelse. |
| `section_display` | `PATCH /sessions/{sid}/sections/display` | innlogget | write | Vis/skjul snittplan og snittflater. |

### Terreng / Terrain

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `get_terrain` | `GET /sessions/{sid}/agent/terrain` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Tomteterreng: størrelse, fall %, høydepunkter, z-område, gjennomsnittlig terreng. |
| `set_terrain` | `POST /sessions/{sid}/agent/terrain` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Lag/endre terreng: width_m, depth_m, slope_x_pct/slope_y_pct, points=[[x,y,z]], fit_floor_over_m. |
| `fill_terrain_pit` | `POST /sessions/{sid}/agent/terrain/fill_pit` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Fyll byggegrop: fjern terrenghull (holes) så marken er kontinuerlig under bygget. Ett angre-steg. |

### Georeferanse, koordinatplan og plankrav / Georeference, coordinate plan and plan constraints

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `get_georef` | `GET /sessions/{sid}/agent/georef` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Prosjektets georeferanse (EUREF89 UTM): crs, origin {n, e, h} = verdenskoordinatene til modellens (0,0), rotation_deg (fra modellens +y til nord, med klokka), limits og plankrav (constraints), hjørnene A, B, C … i verdenskoordinater, fasadenavn etter sann nord og valglistene. georef null = ingen (nord = oppover i planen). |
| `set_georef` | `PUT /sessions/{sid}/agent/georef` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Sett georeferansen (ett angresteg): crs 25832|25833|25835 eller en annen EPSG, origin {n, e, h?}, rotation_deg, limits {ridge_max_m, gesims_max_m, min_distance_m, avg_terrain_h}, constraints [{kind plangrense|byggegrense|nabogrense|bygg, points [[N, E], …], keep ost|vest|nord|sor|venstre|hoyre, closed, ref fasadeliv|yttervegg|takutstikk, min_m, name}]. Bare feltene du gir endres; constraints erstatter listen; clear=true fjerner alt. Koordinater fra brukeren: [N, E] (x = nord). |
| `fit_georef` | `POST /sessions/{sid}/agent/georef/fit` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Tilpass georeferansen fra 2 eller flere kjente hjørner (rotasjon + forskyvning): corners [{model: [x, y], world: [N, E]}], eller bare [[N, E], …] for alle hjørnene i fasadelivet (rekkefølgen finnes selv). Svar: rotation_deg, origin, restavvik per hjørne, rms_m, max_m, warn (over georef.fit_warn_m, standard 0,05 m). apply=false regner bare. |
| `check_plan_constraints` | `GET /sessions/{sid}/agent/georef/check` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Bygget mot plankravene: plan-/byggegrense (hele bygget på riktig side), minsteavstand til nabogrense og andre bygg (georef.min_distance_m, standard 1,0 m), møne- og gesimshøyde over gjennomsnittlig terreng (limits). Margin i cm per krav og hvilken referanse avstanden er målt fra: ref fasadeliv (utvendig kledning, standard) | yttervegg (bindingsverk) | takutstikk (inkludert takutstikk). Endrer ingenting. |

### Mål / Dimension

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `list_dimensions` | `GET /sessions/{sid}/composer/sheets/{name}/cotas` | innlogget | read | Målsetting (cotas) på et ark: index, tekst, side, avstand, scene. |
| `move_dimension` | `POST /sessions/{sid}/composer/sheets/{name}/cotas/move` | innlogget | write | FLYTT mål: flytt målelinjen til ett (eller noen få) mål på arket: til annen side (over/under/høyre/venstre), lenger ut/inn (offset_mm / delta_mm) eller gjennom et punkt (x_mm/y_mm). Verdien, målepunktene og alle andre mål står urørt. clear=true skyver det ut av tegningen (balkong, terrasse, trapp). Bruk denne når brukeren sier «flytt målet/målene», IKKE tidy_cotas (som bygger alle om). |
| `set_dimension_extension` | `POST /sessions/{sid}/composer/sheets/{name}/cotas/extension` | innlogget | write | HJELPELINJER per mål: sett ext_gap_mm (avstand fra vegg/objekt til hjelpelinjestart, papir-mm) og/eller ext_over_mm (forbi målelinja) på ett eller flere mål. Flytter ikke målelinja og endrer ikke målepunktene. Bruk stor gap (f.eks. 26 mm ved 1:75) så hjelpelinjene starter utenfor balkong/terrasse foran fasaden. list_dimensions viser verdiene. |
| `add_dimension` | `POST /sessions/{sid}/composer/sheets/{name}/cota` | innlogget | write | Nytt mål på ark (papir-mm). |
| `edit_dimension` | `PATCH /sessions/{sid}/composer/sheets/{name}/cota/{index}` | innlogget | write | Endre ett mål på ark. |
| `delete_dimension` | `DELETE /sessions/{sid}/composer/sheets/{name}/cota/{index}` | innlogget | write | Slett ett mål på ark. |
| `resuggest_dimensions` | `POST /sessions/{sid}/composer/sheets/{name}/cotas/resuggest` | innlogget | write | Lag foreslåtte mål på nytt (målkjeder) på arket. |
| `check_sheet_dimensions` | `GET /sessions/{sid}/composer/sheets/{name}/cotas/check` | innlogget | read | MÅLKONTROLL for én side (endrer ingenting): mål som ikke henger på veggene, måler feil lengde mot modellen (også «rotert 90°»), ligger inne i bygget, overlapper tekst/andre mål, står ulikt langt fra bygget eller blander enheter. Per funn: id, severity, index, what, fix. Terskler: innstillingene delivery.dim_wall_mm, delivery.dim_length_mm, delivery.dim_offset_spread_mm. |
| `fix_sheet_dimensions` | `POST /sessions/{sid}/composer/sheets/{name}/cotas/fix` | innlogget | write | RETT målene på en side: fester målepunktene til veggene (totalmål til ytterlinjene) og flytter målelinjene like langt ut (offset_m meter i modellen; uten: medianen av dagens avstand). index = bare disse. Bare arket endres; svaret har kontrollen før og etter. |
| `regenerate_sheet_dimensions` | `POST /sessions/{sid}/composer/sheets/{name}/cotas/regenerate` | innlogget | write | LAG MÅLENE PÅ NYTT på en side der bygget faktisk er tegnet: foreslåtte mål bygges fra modellen, egne mål flyttes til festepunktene sine. Bruk den FØRST når brukeren sier at målene er feil, står skjevt eller ved siden av bygget (ett kall, ett angresteg). Svaret har kontrollen før og etter. |
| `sheet_dims` | `POST /sessions/{sid}/composer/sheets/{name}/dims` | innlogget | write | Slå mål på/av for én side i søknadssettet (dims=on|off|settings). |
| `rebuild_sheet_terrain` | `POST /sessions/{sid}/composer/sheets/{name}/terrain` | innlogget | write | Bygg terrenglinje og maske på fasade-/snittsiden på nytt (force=true tar også dine endringer). |
| `clear_dimensions` | `POST /sessions/{sid}/composer/sheets/{name}/cotas/clear` | innlogget | write | Fjern mål på arket. |
| `dim_units` | `GET /sessions/{sid}/composer/dim-units` | innlogget | read | Måleenheter på ark (les/sett). |
| `set_dim_units` | `PUT /sessions/{sid}/composer/dim-units` | innlogget | write | Sett måleenheter på ark. |

### Tekst og strek på ark / Text & lines on sheets

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `add_sheet_text` | `POST /sessions/{sid}/composer/sheets/{name}/text` | innlogget | write | Tekst på ark (papir-mm, Y opp fra arkets nederste kant: (x_mm, y_mm) er første linjes grunnlinje, flere linjer går nedover; size_pt i punkt; w_mm bryter linjene). Svar har warning hvis teksten går utenfor arket. |
| `edit_sheet_text` | `PATCH /sessions/{sid}/composer/sheets/{name}/text/{index}` | innlogget | write | Endre tekst på ark. |
| `add_sheet_line` | `POST /sessions/{sid}/composer/sheets/{name}/line` | innlogget | write | Strek/pil på ark (papir-mm, fra (x0_mm,y0_mm) til (x1_mm,y1_mm)). Kropp: x0_mm, y0_mm, x1_mm, y1_mm er påkrevd; valgfritt color, stroke_mm, dash solid|dashed|dotted|dashdot, kind linea|terreno|flecha, arrows none|start|end|both. Ukjent ark gir 404, manglende/ugyldige tall 422. |
| `plan_labels` | `POST /sessions/{sid}/composer/sheets/{name}/plan-labels` | innlogget | write | Romnavn/etiketter på ark. |
| `opening_marks` | `POST /sessions/{sid}/composer/sheets/{name}/opening-marks` | innlogget | write | Merk dører/vinduer på ark. |
| `list_sheet_annots` | `GET /sessions/{sid}/composer/sheets/{name}/annots` | innlogget | read | Tekster og streker (med indeks) på en side, og sidelagene. |
| `delete_sheet_annot` | `DELETE /sessions/{sid}/composer/sheets/{name}/annot/{kind}/{index}` | innlogget | write | Slett én tekst eller strek på en side (kind text|shape, index fra list_sheet_annots). |
| `edit_sheet_shape` | `PATCH /sessions/{sid}/composer/sheets/{name}/shape/{index}` | innlogget | write | Endre en strek/pil/figur på en side: x_mm, y_mm, w_mm, h_mm, pts_mm, color, stroke_mm, dash solid|dashed|dotted|dashdot, arrows none|start|end|both. |

### Scene, ark og side / Scene, sheet & page

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `delivery_check` | `GET /sessions/{sid}/agent/delivery-check` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Leveringssjekk av tegningssettet FØR det sendes til kunde/kommune: etasjer, kledning (bord, hjørner, åpninger), baksider/dobbeltflater/kantlinjetetthet, tak, Layout-sider (visninger, papir/målestokk, snittmerker, tittelfelt, dato), mål, spor av etterbehandling (maske kun i PDF, tvunget etasje, fjernede mål), rom, terreng og mot fasit. Endrer ingenting; en sjekk som kræsjer gir bare en info-linje. Svar per funn: id, severity (feil|advarsel|info), where, what (hverdagsnorsk), fix (hvor du retter for hånd), key. only/skip = sjekk-id eller prefiks (kommaseparert). Terskler = innstillinger i gruppen «Leveringssjekk» (get_prefs/set_prefs). |
| `accept_delivery_finding` | `POST /sessions/{sid}/agent/delivery-check/accept` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Merk ETT funn i leveringssjekken som «godtatt manuelt» (key står i funnet; «sjekk-id|*» godtar hele sjekken). Lagres i dokumentet (ett angresteg), kommer ikke igjen, og står under «Godtatt manuelt». undo=true tar det tilbake. Mennesket har siste ord når en sjekk tar feil. |
| `auto_fix_delivery_finding` | `POST /sessions/{sid}/agent/delivery-check/auto-fix` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Automatisk retting av utvalgte leveransefunn (ett angresteg). Nå: finding_id=kled.ytter_uten (sett standardkledning på yttervegger uten cladding.on). Valgfritt wall_ids. |
| `rename_scene` | `POST /sessions/{sid}/agent/scenes/rename` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Døp om en scene (arkene som viser den følger med) og/eller flytt den i lista (move=-1/+1). Ett angresteg. |
| `edit_sheet_viewport` | `POST /sessions/{sid}/agent/sheets/viewport` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Flytt/endre størrelse/målestokk på en visning på et ark (papir-mm): sheet, index, scale_n, x_mm, y_mm, w_mm, h_mm, locked. Ett angresteg. |
| `list_scenes` | `GET /sessions/{sid}/scenes` | innlogget | read | Lagrede scener (plan, fasader, snitt, 3D). |
| `capture_scene` | `POST /sessions/{sid}/scenes` | innlogget | write | Lagre nåværende kamera som scene. |
| `apply_scene` | `POST /sessions/{sid}/scenes/{index}/apply` | innlogget | write | Gå til scene (indeks). |
| `delete_scene_index` | `DELETE /sessions/{sid}/scenes/{index}` | innlogget | write | Slett scene etter indeks. |
| `patch_scene` | `PATCH /sessions/{sid}/scenes/{index}` | innlogget | write | Omdøp/flytt/oppdater scene. point_cloud=true/false: punktskyen av/på i DENNE scenen (de andre beholder sitt). |
| `bake_doors` | `POST /sessions/{sid}/scenes/{index}/bake_doors` | innlogget | write | Lagre dørstilling (åpen/lukket) i scenen. |
| `ensure_standard_scenes` | `POST /sessions/{sid}/scenes/ensure-building-standard` | innlogget | write | Standard scener + arkpakke for bygningen. |
| `land_3d` | `POST /sessions/{sid}/scenes/land-3d` | innlogget | write | 3D-scenen 3D-knappen lander i (lager 3D-Bygning med/uten terreng ved behov). |
| `plan_scene` | `POST /sessions/{sid}/composer/plan_scene` | innlogget | write | Planscene for en etasje. |
| `enter_plan` | `POST /sessions/{sid}/enter_plan` | innlogget | write | Gå inn i planen i ett kall: etasjer, lag (andre etasjer og tak skjult), planscene, scener, dører åpne, plandokument + stil, enheter og eventuelt verktøy. |
| `list_sheets` | `GET /sessions/{sid}/composer/sheets` | innlogget | read | Ark (navn, papir, visninger). Store sett: include_cotas=false&include_guides=false (kort svar), name_contains=/sheet_no=, fields=sheet_no,name,scene_name,scale_n. |
| `create_sheet` | `POST /sessions/{sid}/composer/sheets` | innlogget | write | Nytt ark. |
| `patch_sheet` | `PATCH /sessions/{sid}/composer/sheets/{name}` | innlogget | write | Endre ark (tittel, nummer …). |
| `sheet_paper` | `PUT /sessions/{sid}/composer/sheets/{name}/paper` | innlogget | write | Papirformat for ark. |
| `sheet_title_pos` | `PUT /sessions/{sid}/composer/sheets/{name}/title-pos` | innlogget | write | Plassering av tittelfeltet på ett ark: right, bottom, none eller auto. |
| `sheet_document` | `GET /sessions/{sid}/composer/sheets/{name}/document` | innlogget | read | Arket som dokument (elementer i papir-mm). |
| `sheet_svg` | `GET /sessions/{sid}/composer/sheet.svg` | innlogget | read | Arket som SVG. |
| `add_viewport` | `POST /sessions/{sid}/composer/sheets/{name}/frame` | innlogget | write | Ny visning (scene) på et ark. |
| `composer_add_page` | `POST /sessions/{sid}/composer/pages` | innlogget | write | Ny side i arksettet. |
| `composer_delete_page` | `DELETE /sessions/{sid}/composer/pages/{name}` | innlogget | write | Slett side. |
| `duplicate_page` | `POST /sessions/{sid}/composer/pages/{name}/duplicate` | innlogget | write | Dupliser side. |
| `list_layout_profiles` | `GET /layout/profiles` | åpen, uten innlogging | read | Firmaprofiler for tegningshodet: innebygde (tegnebua, tom) + mine + teamets. Velg id og bruk apply_layout_profile. |
| `get_layout_profile` | `GET /layout/profiles/{profile_id}` | åpen, uten innlogging | read | Én firmaprofil med alle felt. |
| `save_layout_profile` | `POST /layout/profiles` | innlogget | account | Lagre en firmaprofil (firm, web, address, poststed, email, tegnet_av, papir A4-A0, mal_i m|cm|mm, strip_order, logo_brand, logo_data_url, lang) for meg (scope=user) eller teamet (scope=team + team_id). Samme navn oppdaterer. |
| `delete_layout_profile` | `DELETE /layout/profiles/{profile_id}` | innlogget | account | Slett en egen firmaprofil (de innebygde kan ikke slettes). |
| `extract_vector_logo` | `POST /layout/logo/extract` | innlogget | read | Hent en linjelogo (vektor, ikke bilde) fra et område av en PDF-side: pdf_base64, page (0-basert), region_mm [x0,y0,x1,y1] fra øverste venstre hjørne (standard: nederste venstre 75 x 45 mm). Lagre svaret som logo_vector i en profil eller set_sheet_chrome. |
| `seed_layout_profile_from_pdf` | `POST /layout/profiles/seed-from-pdf` | innlogget | account | Teamadmin: lag/oppdater teamets firmaprofil fra firmaets egen LayOut-PDF (mal layout-stripe, E-1-numre, linjelogo, firmafelt lest fra PDF-en). dry_run viser profilen uten å lagre. |
| `apply_layout_profile` | `POST /sessions/{sid}/composer/chrome/profile` | innlogget | write | Bruk en firmaprofil i prosjektet: firmanavn, adresse, web, e-post, tegnet av, logo, papir og dokumentspråk settes på alle sider. |
| `get_sheet_chrome` | `GET /sessions/{sid}/composer/chrome` | innlogget | read | Tegningshodet (firma, adresse, logo, prosjektfelt) som gjelder alle sider. |
| `set_sheet_chrome` | `PUT /sessions/{sid}/composer/chrome` | innlogget | write | Sett felt i tegningshodet: firm, web, address, poststed, email, tiltakadresse, tiltaksted, tiltakshaver, tegnet_av, versjon, dato, gnr_bnr_snr, project_name, logo_data_url (data:image, maks ~300 KB; SVG tegnes som linjer), logo_vector (linjelogo, JSON/SVG), mal_i, bg_style, bg_grid_mm, template (building | layout-stripe = LayOut-tittelfelt), sheet_no_style (hyphen = E-1 | plain = E1). |
| `set_sheet_overlays` | `PATCH /sessions/{sid}/composer/sheets/{name}/overlays` | innlogget | write | Vis/skjul overlegg på en side: nivel (koter), pitch (takvinkel), norte, sheet_no, firm. |
| `edit_north_arrow` | `PATCH /sessions/{sid}/composer/sheets/{name}/norte/{index}` | innlogget | write | Nordpil på en side: posisjon, størrelse og vinkel (x_mm, y_mm, size_mm, angle_deg). |
| `list_page_layers` | `GET /sessions/{sid}/composer/page-layers` | innlogget | read | Sidelag (som LayOut-lag): navn på lagene og hvilke som er på hvilken side. |
| `set_sheet_page_layers` | `PUT /sessions/{sid}/composer/sheets/{name}/page-layers` | innlogget | write | Hvilke sidelag en side viser (layers: liste med lagnavn). |
| `set_sheet_annotations` | `PATCH /sessions/{sid}/composer/sheets/{name}/annotations` | innlogget | write | Kotemerker og takvinkel på en side: level {side auto|right|left|both, gap_mm, size_mm, show{storeys,terrain,roof}}, roof_angle {size_mm}, reset positions|all. |
| `edit_viewport` | `PATCH /sessions/{sid}/composer/sheets/{name}/frame/{index}` | innlogget | write | Endre en visning (viewport) på et ark: scale_n (1:N), x_mm, y_mm, w_mm, h_mm, locked, kamera (cam_yaw, cam_pitch, cam_distance, cam_fov, cam_target, clear_camera). |
| `lock_page` | `PUT /sessions/{sid}/composer/pages/{name}/lock` | innlogget | write | Lås/lås opp en side så «Bygg sett på nytt» ikke erstatter den. |
| `sheet_index` | `POST /sessions/{sid}/composer/sheet_index` | innlogget | write | Tegningsliste-ark. |
| `sheet_qa` | `GET /sessions/{sid}/composer/qa` | innlogget | read | Kvalitetssjekk av arkene. |
| `list_drawings` | `GET /sessions/{sid}/agent/drawings` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Scener (og arkene som viser dem), ark/sider, hva «+» kan legge til. |
| `add_scene` | `POST /sessions/{sid}/agent/drawings/add_scene` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Ny scene: kind plan|fasade|snitt|situasjon|tak|detalj|3d|ringmur (fundamentplan 2D-Ringmur). kind='3d' med storey='4. etg' (eller 'øverste') lager «3D-<etasje>»: en 3D-scene filtrert til ÉN etasje (de andre etasjene skjules i selve scenen, aldri globalt; tak og terreng av som standard, show_roof/show_terrain=true tar dem med). Foreslå ALDRI en global stilregel for å vise én etasje. 2D-<etasje> og 3D-<etasje> kan ligge på samme ark (add_view). name (og/eller copy_from = en eksisterende scene) lager ALLTID en NY scene med det navnet (kopi av copy_from, ellers av standardscenen av den typen); standardscenen røres ikke. |
| `set_scene_camera` | `POST /sessions/{sid}/agent/drawings/set_scene_camera` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Sett kameraet som er LAGRET i en scene (det scenen åpner med): target [x,y,z] m, distance, yaw/pitch (grader), perspective, ortho_extent (meter verden en parallell visning viser), view top|front|back|left|right|iso. Bare oppgitte felt endres. Ikke render-kameraet (set_camera). |
| `frame_scene` | `POST /sessions/{sid}/agent/drawings/frame_scene` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Sikt en scene på en del av modellen så den åpner der (lagres i scenen): zoom_to all|storey|layer|elements|bbox (storey=, layer=, ids=[…], bbox=[x0,y0,x1,y1] i meter), margin (1,1 = 10 % luft), view top|front|…, ortho. Plan, fasade og snitt forblir parallelle (ortografisk utsnitt). |
| `delete_scene` | `POST /sessions/{sid}/agent/drawings/delete_scene` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Slett scene etter navn. |
| `set_scene_discipline` | `POST /sessions/{sid}/agent/drawings/set_scene_discipline` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Legg scener i et fag (gruppe i scenepanelet): names=[…] (eller name), discipline Byggherre|ARK|RIB|RIV|RIE|RIBr|LARK|RIG|RIAku (også «Arkitekt», «elektro» …), et annet navn lager et eget fag i prosjektet, null/«Felles» = uten fag. Ett angresteg. |
| `delete_scenes` | `POST /sessions/{sid}/agent/drawings/delete_scenes` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Slett flere scener på én gang (ett angresteg), f.eks. alle scenene i ett fag. |
| `add_discipline` | `POST /sessions/{sid}/agent/drawings/add_discipline` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Eget fag (scenegruppe) i prosjektet, ved siden av Byggherre/ARK/RIB/RIV/RIE (maks 32 tegn). |
| `remove_discipline` | `POST /sessions/{sid}/agent/drawings/remove_discipline` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Fjern et eget fag; scenene i det går til «Felles» (ingen scene slettes). |
| `add_sheet` | `POST /sessions/{sid}/agent/drawings/add_sheet` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Nytt ark: kind plans|facades|view|empty. |
| `delete_sheet` | `POST /sessions/{sid}/agent/drawings/delete_sheet` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Slett ark. |
| `add_page` | `POST /sessions/{sid}/agent/drawings/add_page` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Ny side (tom eller med én scene). |
| `delete_page` | `POST /sessions/{sid}/agent/drawings/delete_page` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Slett side. |
| `add_view` | `POST /sessions/{sid}/agent/drawings/add_view` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Legg en scene på et ark (ny visning, f.eks. Snitt-AA ved siden av planen). |
| `delete_view` | `POST /sessions/{sid}/agent/drawings/delete_view` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Fjern en visning fra et ark. |
| `ensure_standard` | `POST /sessions/{sid}/agent/drawings/ensure_standard` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Standard scener/ark for det som faktisk er tegnet (pack: standard|presentasjon|soknad|full). |
| `add_sheet_set` | `POST /sessions/{sid}/agent/drawings/add_sheet_set` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Tegningssett: presentasjon, soknad eller konstruksjon, i fast rekkefølge E-serien (plan, snitt, fasader, perspektiver, vindu-/dørliste), D-serien (situasjonsplan …) og K-serien (ringmur, konstruksjonstegninger), nummer E1 …, D1 …, K1 … (eksisterende tegninger først). Innholdet per sett er innstillinger (sett.<sett>.<side>). Sider Dibrix ikke kan lage ennå står i «missing». Sletter aldri egne sider. |
| `rename_page` | `POST /sessions/{sid}/agent/drawings/rename_page` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Gi side nytt navn. |
| `set_page_number` | `POST /sessions/{sid}/agent/drawings/set_page_number` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Tegningsnummer på side (standard E1/D1/K1 via add_sheet_set; fritekst 1-16 tegn, f.eks. E-1). Beholdes ved ombygging. sheet.no_* styrer auto. |
| `move_page` | `POST /sessions/{sid}/agent/drawings/move_page` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Flytt side (to_index eller delta). |
| `copy_page` | `POST /sessions/{sid}/agent/drawings/duplicate_page` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Dupliser side (undo-steg). |
| `set_page_paper` | `POST /sessions/{sid}/agent/drawings/set_page_paper` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Papirformat og retning for side. |
| `set_view_scene` | `POST /sessions/{sid}/agent/drawings/set_view_scene` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Bytt scene i en visning på en side. |
| `set_view_scale` | `POST /sessions/{sid}/agent/drawings/set_view_scale` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Målestokk 1:N for en visning. |
| `set_scene_openings` | `POST /sessions/{sid}/agent/drawings/set_scene_openings` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Dører i en scene: closed|open|model (hver dør som satt)|auto (fasade/snitt/3D lukket som standard); med door = bare den døren i scenen. |
| `set_scene_layers` | `POST /sessions/{sid}/agent/drawings/set_scene_layers` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Lag en scene viser/skjuler når den velges (lagret i scenen): show=[…], hide=[…]. Navn fra list_tags eller lagpanelet («Reisverk» = Construction); ukjent navn gir «mente du …?». F.eks. «vis reisverk i scenen Reisverk 3D». Arkene følger med. |

### Plan, stil og presets / Plan, style & presets

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `get_plan` | `GET /sessions/{sid}/composer/plan` | sandkasse (anonym) eller innlogget | read | Editorens 2D-plan som JSON (vegger, åpninger, rom, mål) for en etasje. |
| `get_plan_svg` | `GET /sessions/{sid}/composer/plan.svg` | sandkasse (anonym) eller innlogget | read | 2D-planen som SVG (se den). |
| `style_document` | `GET /sessions/{sid}/composer/style` | sandkasse (anonym) eller innlogget | read | Ferdig løst tegnestil; preset=standard|presentasjon|byggeplass|faggruppe:… . |
| `get_style` | `GET /sessions/{sid}/style` | innlogget | read | Modellstilen: valgt stil, farge/linje/skravur per objekttype (vegg, dekke, tak, dør, vindu ...), overstyringer per scene/ark og stilbiblioteket. |
| `list_styles` | `GET /sessions/{sid}/style/catalog` | innlogget | read | Hva som kan stilsettes: objekttyper med egenskaper, fargepalett, linjevekter (0,05-1,0 mm), linjetyper, skravurer og navn på stiler (Arkitekt svart/hvit, Presentasjon farge, Søknad, Skisse). Les denne før set_style. |
| `set_style` | `POST /sessions/{sid}/style` | innlogget | write | Sett utseendet: preset=<stilnavn> velger en navngitt stil; type+prop+value setter én egenskap på én objekttype (face_color, opacity, edge_color, edge_width_mm, line_type, cut_color, hatch, text_color, visible), props={...} flere; scope=document|scene:<navn>|sheet:<navn>|frame:<uid>; reset (+type, prop) / reset_all tilbakestiller; copy_from+type kopierer; save_as/delete lagrer/sletter en stil i dokumentet. Virker i 3D, 2D-plan, snitt/fasade og på ark/PDF. |
| `get_style_mood` | `GET /sessions/{sid}/style/mood` | innlogget | read | Uttrykk: glidere som tone (lys-mørk), livlighet, varme, skisse-faktor, detaljnivå, linjetykkelse, fyll (white|colour|hatch|keep) og papir, og ferdige uttrykk (clean_architect, sketch, watercolour, pencil, presentation, playful). Les denne før set_style_mood / adjust_style. |
| `set_style_mood` | `POST /sessions/{sid}/style/mood` | innlogget | write | Sett uttrykket: preset=clean_architect|sketch|watercolour|pencil|presentation|playful og/eller values={tone, vividness, warmth, detail, line_weight: -1..1, sketch: 0..1, fill: keep|white|colour|hatch|watercolour|pencil, paper: keep|white|paper|warm|grey} og/eller palette=[hex fra fargelisten, opptil 5: vegg, tak, dør, terreng, kledning]. Reversibelt: 0 = grunnstilen. Til «gi meg samme uttrykk som dette bildet»: mål bildet med style_from_image og bruk forslaget (eller din tolkning) her. Forrige stil lagres (set_style undo=true). |
| `adjust_style` | `POST /sessions/{sid}/style/mood/adjust` | innlogget | write | Relativ justering av ett uttrykk: parameter=tone|vividness|warmth|sketch|detail|line_weight, direction=more|less, amount=little|some|much («litt mørkere» = tone more little; «mye mer sketchy» = sketch more much; «lysere» = tone less some); fill / paper: direction = valget (colour, warm ...). Forrige stil lagres. |
| `reset_style_mood` | `POST /sessions/{sid}/style/mood/reset` | innlogget | write | Tilbake til grunnstilen (alle uttrykksglidere til 0). |
| `style_from_image` | `POST /sessions/{sid}/style/mood/reference` | innlogget | read | Mål et referansebilde LOKALT (palett, tone, metning, varme, kontrast, linjepreg, støy) og få et FORSLAG til uttrykk + palett; ingenting brukes og bildet sendes ikke videre. image_b64 = bildet (jpg/png, under ca. 1,5 MB). Bruk forslaget med set_style_mood. |
| `list_style_rules` | `GET /sessions/{sid}/style/rules` | innlogget | read | Stilregler «filter -> stil» i kjørerekkefølge (en senere regel vinner), med antall elementer hver treffer, og valgene å filtrere på: ytter/inner, bærende (bearing|non_bearing|unknown), brannklasse (none|EI30|EI60|EI90), brannvegg, veggtype, materiale, etasje, lag/tagg, åpningstype (door|window), tykkelse, objekttype. |
| `add_style_rule` | `POST /sessions/{sid}/style/rules` | innlogget | write | Legg til en stilregel (op=add), eller update|remove|move|enable|clear. rule={name, combine:all|any, conds:[{prop:wall_position|bearing|fire_class|fire_wall|type|wall_type|material|storey|tag|opening_kind|thickness_mm, op:is|is_not|gte|lte, value}], style:{face_color, opacity, edge_color, edge_width_mm, line_type, cut_color, hatch}, dims:{edge_color, edge_width_mm, line_type}}. Eksempel «mål til yttervegger grønne»: conds=[{prop:wall_position,op:is,value:exterior}], dims={edge_color:green}. Farger er hex eller paletten fra list_styles; scope=document|scene:<navn>|ark:<navn> (regler kan gjelde ett ark). Virker i 3D, 2D-plan, Tegning og ark/PDF (også målene til elementene). |
| `remove_style_rule` | `DELETE /sessions/{sid}/style/rules/{rule_id}` | innlogget | write | Fjern en stilregel (id fra list_style_rules). |
| `add_style_legend` | `POST /sessions/{sid}/style/legend` | innlogget | write | Legg en tegnforklaring av stilreglene på et ark (erstatter en tidligere). |
| `schedules` | `GET /sessions/{sid}/composer/schedules` | innlogget | read | Lister (dører, vinduer, rom). |
| `schedules_sheet` | `POST /sessions/{sid}/composer/schedules/sheet` | innlogget | write | Lister som ark. |
| `public_plan_svg` | `GET /configurator/public/plan.svg` | åpen, uten innlogging | read | GET-inngang: 2D-planen til en konfigurasjon som SVG (samme parametre som quote). |

### Regelsjekk / Compliance check

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `compliance` | `GET /sessions/{sid}/agent/compliance` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Regelsjekk av modellen i økta (nasjonale regler + kommune); type=hus|hytte|garasje … |
| `sandbox_compliance` | `GET /configurator/sandbox/session/{sid}/compliance` | åpen, uten innlogging | read | Regelsjekk av sandkasseøktas modell (uten innlogging). |
| `public_compliance` | `POST /configurator/public/compliance` | åpen, uten innlogging | read | Regelsjekk av en konfigurasjon (samme felt som quote) + kommune og tomtefakta. |
| `public_compliance_get` | `GET /configurator/public/compliance` | åpen, uten innlogging | read | GET-inngang: regelsjekk fra query-parametre (type, width, depth, door, window, roof, kommune, full=1 og tomtedata: site_nabo_m, site_annen_bygning_m, site_vei_m, vei, site_sjo_m, gulv_over_terreng_m, bebygd_eiendom). |

### Energi (klimaskjerm og energiberegning) / Energy (building envelope and energy calculation)

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `energy_envelope` | `GET /sessions/{sid}/agent/energy/envelope` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Klimaskjermens arealgrunnlag fra modellen: yttervegg over/under terreng, vinduer og dører per himmelretning, tak, gulv mot grunn / det fri / uoppvarmet, oppvarmet BRA og luftvolum. MÅLT og ANTATT holdes fra hverandre (kilder). uoppvarmet=Loft,Kjeller; maalemetode=ytre|indre; nord_grader (standard: georef eller 0); sektorer=8|4 (retninger). |
| `energy_report` | `POST /sessions/{sid}/agent/energy/report` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Utkast til energirapport (TEK17 kap. 14, 12 deler, markdown) fra klimaskjermens arealer. Tall er merket (M) målt, (O) oppgitt, (B) beregnet, (A) antatt; det som mangler står som [ ]/[NAVN]. inndata: adresse, gnr, bnr, kommune, n50, kuldebro, u{yttervegg,fri_kjellervegg,kjellervegg,plate,tak,vindu,dor}. Avgjør ingenting selv: konklusjon, ventilasjon, energiforsyning og energibudsjett kommer fra Rockwool. |
| `export_energi_xlsx` | `GET /sessions/{sid}/export/energi.xlsx` | innlogget | read | Klimaskjermens arealer som Excel i Tegnebuas mal Underlag_Energiberegninger (arket Underlag, A2:G55, en blokk per oppvarmet plan, fire fasader) pluss arkene Kilder (MÅLT/ANTATT) og Rockwool (innleggingsark). uoppvarmet=Loft,Kjeller; maalemetode=ytre|indre; nord_grader; u_vindu og u_dor fyller U-verdi-kolonnen. |

### Pris og konfigurator / Price & configurator

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `configurator_link` | `GET /sessions/{sid}/agent/configurator-link` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Modellen som delelenke til konfiguratoren (/konfigurator/plan#c=…): omriss, innervegger, åpninger; not_carried = det som ikke følger med. Åpen bygning (carport): omrisset fra gulvplata/taket/veggene, assumed/notes sier hva som er antatt. |
| `public_catalog` | `GET /configurator/public/catalog` | åpen, uten innlogging | read | Konfiguratorkatalog: bygningstyper (inkl. matrikkelkoder), former, valg. |
| `public_quote` | `POST /configurator/public/quote` | åpen, uten innlogging | read | Bygg en konfigurasjon og få pris; plan=true gir 2D-planen, mesh=true 3D. |
| `public_quote_get` | `GET /configurator/public/quote` | åpen, uten innlogging | read | GET-inngang (bare nettsidehenting): pris + matrikkelkode + regelsjekk + lenker fra query-parametre. Tomtedata (site_nabo_m, site_annen_bygning_m, site_vei_m, vei, site_sjo_m, gulv_over_terreng_m, bebygd_eiendom, tomt_m2 ...) gjør ukjente funn kjente (se `still_unknown`); full=1 gir alle funn; svaret har `defaults` (standardmål), `price_includes`/`price_excludes` og `links.plan_page` (lim ordrett). |
| `public_describe` | `POST /configurator/public/describe` | åpen, uten innlogging | read | Fritekst → endringer i konfigurasjonen. |
| `public_layout` | `POST /configurator/public/layout` | åpen, uten innlogging | read | Automatiske åpninger for valgene. |
| `public_forms` | `GET /configurator/public/forms` | åpen, uten innlogging | read | Alle former (ringer) i én størrelse. |
| `public_modules` | `POST /configurator/public/modules` | åpen, uten innlogging | read | En form som redigerbare moduler. |
| `public_validate` | `POST /configurator/public/validate` | åpen, uten innlogging | read | Vegger og åpningsproblemer uten å bygge. |
| `public_summary` | `POST /configurator/public/summary` | åpen, uten innlogging | read | Kort sammendrag av konfigurasjonen. |
| `public_drawings` | `POST /configurator/public/drawings` | åpen, uten innlogging | write | Tegningssett (PDF) for en konfigurasjon; gir token. |
| `public_drawings_pdf` | `GET /configurator/public/drawings/{token}.pdf` | åpen, uten innlogging | read | Hent PDF-en fra public_drawings. |
| `public_request` | `POST /configurator/public/request` | åpen, uten innlogging | external | Send forespørsel (lead) til leverandør. SENDER til mennesker: spør brukeren først. |
| `sandbox_load_drawing` | `POST /configurator/sandbox/session/{sid}/drawing` | åpen, uten innlogging | write | Tegn i en TOM sandkasseøkt fra en konfigurasjon: boundary (ring), walls, openings. |
| `sandbox_get_drawing` | `GET /configurator/sandbox/session/{sid}/drawing` | åpen, uten innlogging | read | Sandkassetegningen som konfigurasjon (boundary, walls, openings). |
| `sandbox_price` | `POST /configurator/sandbox/session/{sid}/price` | åpen, uten innlogging | read | Pris på sandkassemodellen med valg (tak, veggtype, fundament …). |
| `session_price` | `GET /configurator/session/{sid}/price` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Pris på modellen i en editorøkt (eks. mva). |
| `session_price_detail` | `GET /configurator/session/{sid}/price/detail` | innlogget | read | Pris med artikkel- og NOBB-nummer per linje. |
| `configurator_catalog` | `GET /configurator/catalog` | innlogget | read | Full katalog (innlogget). |
| `configurator_quote` | `POST /configurator/quote` | innlogget | read | Pris med linjer (innlogget). |
| `configurator_open` | `POST /configurator/open` | innlogget | write | Åpne en konfigurasjon som editorøkt. |
| `configurator_my` | `GET /configurator/my` | innlogget | read | Mine konfigurasjoner. |
| `configurator_leads` | `GET /configurator/leads` | innlogget | read | Innkomne forespørsler (leverandør). |

### Konstruksjon (bindingsverk) / Construction (framing)

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `get_construction` | `GET /sessions/{sid}/construction` | innlogget | read | Bindingsverk-innstillinger. |
| `set_construction` | `PATCH /sessions/{sid}/construction` | innlogget | write | Endre bindingsverk-innstillinger. |
| `refresh_construction` | `POST /sessions/{sid}/construction/refresh` | innlogget | write | Regn ut bindingsverket på nytt. |
| `construction_drawings` | `POST /sessions/{sid}/construction/drawings` | innlogget | write | Konstruksjonsark (K): hver tegning er én viewport som følger reisverket; flytt/skaler/slett den med edit_sheet_viewport. Ny kjøring beholder plassering og slettede tegninger; reset=true lager settet på nytt. Standard skriver prosjektfila med en gang (saved_to_project); persist_project=false = bare økta (prøve/kontroll). |
| `cutlist` | `GET /sessions/{sid}/construction/cutlist` | innlogget | read | Kappliste (JSON). |
| `bearing_system` | `GET /sessions/{sid}/construction/bearing` | innlogget | read | Bæresystem: mønebjelke, overliggere, mønestolper og søyler med foreslått tverrsnitt (minste standardprofil som holder), styrende kontroll, utnyttelse, nedbøyning, opplagerkrefter og beregningen steg for steg (EC5, snølast per kommune). CSV: …/construction/bearing.csv. Arket lages med add_sheet_set('konstruksjon'). |
| `apply_bearing_system` | `POST /sessions/{sid}/construction/bearing/apply` | innlogget | write | Skriv de foreslåtte tverrsnittene inn i konstruksjonsmodellen (mønebjelke ridge_b/h + kvalitet, overligger og antall bærestendere per åpning), så bindingsverk og kappliste følger. only=[posisjoner] begrenser. |
| `snow_check` | `POST /sessions/{sid}/construction/snow` | innlogget | write | Snølastkontroll for byggestedet: kommune (navnet i NS-EN 1991-1-3 NA-tabellen) og høyde over havet settes i konstruksjonsinnstillingene, svaret er snølast på mark og tak, om mønebjelke, mønestolper og overliggere holder (minste profil og utnyttelse) og mønebjelken i modellen. Ukjent kommune: ok=false med forslag. Skriv forslaget inn med apply_bearing_system. |

### Eksport og import / Export & import

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `export_ifc` | `GET /sessions/{sid}/export/ifc` | innlogget | read | IFC4-eksport (nedlastingslenke). |
| `export_plan_pdf` | `GET /sessions/{sid}/export/plan.pdf` | innlogget | read | Plan som PDF (preset=…). |
| `export_plan_dxf` | `GET /sessions/{sid}/export/plan.dxf` | innlogget | read | Plan som DXF. |
| `export_sheets_pdf` | `GET /sessions/{sid}/export/sheets.pdf` | innlogget | read | Alle ark som PDF. ?sheet=<navn eller tegningsnr> gir bare det arket som egen PDF (én PDF per dokument, f.eks. til Smart Holte). |
| `export_sheets_dxf` | `GET /sessions/{sid}/export/sheets.dxf` | innlogget | read | Ark som DXF. |
| `export_sheets_dwg` | `GET /sessions/{sid}/export/sheets.dwg` | innlogget | read | Ark som DWG. |
| `export_skp` | `GET /sessions/{sid}/export/skp` | innlogget | read | SketchUp-fil. |
| `export_exchange` | `GET /sessions/{sid}/export/exchange.json` | innlogget | read | dibrix-exchange.json: nøytralt utvekslingsformat (schema v1) med elementer (uid, IFC-klasse, etasje, fag, type, mesh i mm), materialer, lag, scener, snitt og georef. Leses av SketchUp-extensionen «Hent fra Dibrix»; Revit/Archicad senere. textures=false utelater bildene. |
| `export_calc_elements` | `GET /sessions/{sid}/export/calc-elements` | innlogget | read | Elementliste for kalkyle. |
| `export_glb` | `GET /sessions/{sid}/glb` | innlogget | read | 3D-modell som GLB. |
| `export_igz` | `GET /sessions/{sid}/igz` | innlogget | read | Dokumentet (.igz). |
| `export_capabilities` | `GET /export/capabilities` | åpen, uten innlogging | read | Hvilke eksportformater serveren kan. |
| `import_igz` | `POST /sessions/{sid}/igz` | innlogget | write | Last inn .igz (multipart). |
| `import_ifc` | `POST /sessions/{sid}/import/ifc` | innlogget | write | Importer IFC (multipart). |
| `import_ifc_as_spec` | `POST /sessions/{sid}/import/ifc/spec` | innlogget | write | IFC (Revit/ArchiCAD-eksport) → hus-spec (multipart): vegger på aksen, åpninger på verten, etasjer, dekker, tak (form antatt), rom; meta.provenance per element. build=true bygger spec-en i økta (replace tømmer først). Rett det usikre og bygg med build_house_from_spec. |
| `import_skp` | `POST /sessions/{sid}/import/skp` | innlogget | write | Importer SketchUp (multipart). |
| `import_xdi` | `POST /sessions/{sid}/import/xdi` | innlogget | write | Importer XDI (multipart). |
| `import_underlay` | `POST /sessions/{sid}/import/underlay` | innlogget | write | Underlag (bilde/PDF) i planen. |
| `list_approved_drawings` | `GET /sessions/{sid}/agent/approved-drawings` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Sist godkjente tegninger i prosjektet: per side id, kind (plan|snitt|fasade|situasjon|perspektiv|annet), storey/view, scale_n (1:N) og scale_src (pdf_text|default|user|calibrated), rotation, page_mm, size_m, underlay {on, opacity, locked, center, angle_deg}, sheet {on, soknad}, sheet_name; pluss valglistene storeys, facades, sections, scales. |
| `import_approved_drawings` | `POST /sessions/{sid}/agent/approved-drawings/import-json` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Importer sist godkjente tegninger (PDF med alle sider, eller bilde; multipart «file»): hver side blir underlag i riktig målestokk under plan/fasade/snitt OG en egen side «Sist godkjent – …» i Tegning, merket «Sist godkjent situasjon» og med i søknadssettet (også til nabovarsel). Type, etasje/visning og 1:N gjettes fra teksten på siden og filnavnet; tekstretning (PDF) eller lokal OCR snur sider. Felt: kind, storey, view, scale_n, rotation (0/90/180/270), approved_date, sheets, in_soknad, ocr. Ett angresteg. Filen sendes som data_b64 (JSON) eller path til en lokal fil (MCP-klienten leser den). Vanlig opplasting i nettleseren er ÉN dialog «Last opp tegninger / bilder…» (se import_drawings_job). |
| `update_approved_drawing` | `POST /sessions/{sid}/agent/approved-drawings/{pid}` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Endre én godkjent side (ett angresteg): kind, storey (plan), view (fasade-/snittscene), scale_n, rotation (bildet snus), approved_date, title, opacity 0-1, underlay av/på, locked, sheet av/på, soknad (med i søknadssettet), center [x,y(,z)] eller offset_m [dx,dy] (flytt underlaget, meter), angle_deg (drei). |
| `calibrate_approved_drawing` | `POST /sessions/{sid}/agent/approved-drawings/{pid}/calibrate` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Kalibrer målestokken på et godkjent underlag: to punkt på underlaget (verdenskoordinater i meter, slik de ble klikket) og den virkelige avstanden. p1 ligger fast. |
| `delete_approved_drawing` | `DELETE /sessions/{sid}/agent/approved-drawings/{pid}` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Fjern én godkjent side med underlaget og siden i Tegning (ett angresteg). |
| `import_drawings_job` | `POST /sessions/{sid}/agent/import-drawings/json` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Start en importjobb for tegninger (PDF/bilder som base64 i JSON: files:[{name, data_b64}], mode build|approved|both, approved_date). Jobben klassifiserer sidene (plan/snitt/fasade/situasjon/annet, etasje, retning, målestokk, dreiing; kode først, Claude bare for usikre sider) og STOPPER i waiting_for_user. Se get_import_job, rett med edit_import_pages, bekreft med confirm_import_job. Én jobb per opplasting; ingenting slettes. Bare eier/redigerer (ikke visningslenke eller propose-kopi). |
| `import_drawings_upload` | `POST /sessions/{sid}/agent/import-drawings` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Samme som import_drawings_job, men som skjema-opplasting (multipart: files, mode, approved_date). Web-menyen Fil > Importer > Tegninger (PDF / bilde) bruker denne. Agenter: curl -F files=@fil.pdf -H 'Authorization: Bearer dk_…' (ikke BuildChat-vedlegg — den krever ekte klikk). |
| `import_drawings_vector` | `POST /sessions/{sid}/agent/import-vector` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Import av tegninger UTEN KI (gratis, ca. 10-60 s): last opp PDF/bilder (multipart: files, replace, name, declared_bra_m2, declared_storeys). Leser plantegninger (tittel, etasje, målestokk, veggstreker, åpninger, romtekst + areal), snitt (etasjehøyde, takvinkel), bygger hus-spec med kilde og sikkerhet per element (meta.provenance), legger modellen i økta, legger originalsidene inn som underlag per etasje i riktig målestokk, og lagrer kontrollark + jobbmappe. Skannede sider, fasader og trapper leses ikke (bruk import_drawings_job). Svaret har report (antatt, avvik, mål mot tegningen). |
| `get_import_vector` | `GET /sessions/{sid}/agent/import-vector/{rid}` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Et lagret importresultat uten KI: jobb + rapport (GET .../import-vector/{id}), spec (/spec) og kontrollark (/control/{etasje}.png). |
| `get_import_vector_spec` | `GET /sessions/{sid}/agent/import-vector/{rid}/spec` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | hus-spec fra et lagret import uten KI (med meta.provenance per element). |
| `get_import_vector_control` | `GET /sessions/{sid}/agent/import-vector/{rid}/control/{name}.png` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Kontrollark (PNG) fra import uten KI: originalsiden for etasjen med modellen tegnet oppå. {name} = etasje (kjeller, 1_etasje, loft …). |
| `list_import_jobs` | `GET /sessions/{sid}/agent/import-drawings` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Importjobbene til økta og prosjektet (id, state, mode, kostnad), nyeste først. «Hva trenger deg»: needs_count, blocking_count, first_need (kode, side, handling) og waiting_on (aldri tom i waiting_for_user: blokkerende behov og første side). |
| `get_import_job` | `GET /sessions/{sid}/agent/import-drawings/{jid}` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Én importjobb: state (uploaded, classifying, waiting_for_user, building, done, failed, cancelled), pages (kind, storey, view, scale_n, rotation, kind_conf, ask = hva koden er usikker på), estimate (tokens/kostnad før bygging, tak), usage (faktisk), pause (waiting_for_user etter klassifisering eller kostnadstak), result.report (rapporten: usikre punkter, mål mot tegningen, kostnad), pages[].needs (konkrete behov per side: scale_missing, kind_uncertain, storey_missing, view_missing, region_unconfirmed, no_measure …; blocking, action) og waiting_on. |
| `tolk_status` | `GET /sessions/{sid}/agent/import-drawings/{jid}/tolk` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | «Tolk»: status per side i en importjobb: rotasjon (deg 0/90/180/270 + skew_deg, forslaget og kilden), skala (scale_n, kilde, nærmeste vanlige og avvik i %), hjelpemål (antall linjer forslag/godkjent, tegningen godkjent) og missing (rotation/scale). ready = alt satt og jobben venter. Start flyten med import_drawings_upload, rett med edit_import_pages / tolk_scale_from_known, avslutt med confirm_import_job. |
| `tolk_scale_from_known` | `POST /sessions/{sid}/agent/import-drawings/{jid}/tolk/scale` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | «Mål et kjent mål»: idx, to punkter p0/p1 på siden (andeler 0-1 i sidens egen, udreide ramme, som hjelpelinjene) og known_mm (den kjente lengden i mm) gir målestokken 1:N, nærmeste vanlige og avvik_pct. apply=true (standard) setter scale_n på siden som brukerens valg; apply=false regner bare ut. |
| `import_drawings_capabilities` | `GET /sessions/{sid}/agent/import-drawings/capabilities` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Hva importen kan nå: er KI tilgjengelig (nøkkelen er prøvd mot leverandøren; ai.reason = key_rejected hvis den er avvist), OCR, kostnadstak, terskler og forslag til valgene (suggest.approved / suggest.ai) fra brukerens innstillinger. |
| `edit_import_pages` | `POST /sessions/{sid}/agent/import-drawings/{jid}/pages` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Rett klassifiseringen mens jobben er waiting_for_user: edits:[{idx, kind, storey, view (Nord|Øst|Syd|Vest), scale_n, rotation (0/90/180/270 med klokka), skew_deg (fri dreiing -45..45 med klokka i tillegg; skjevt skann rettes opp før tolken leser), skip, title, building (''|garasje|annet bygg), region:{id, kind, storey, view, scale_n, building, role: drawing|titleblock, confirmed: true}}]. Dine valg vinner over alle gjetninger. |
| `confirm_import_job` | `POST /sessions/{sid}/agent/import-drawings/{jid}/confirm` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Bekreft listen og velg: approved=true (legg inn sidene som underlag og sist godkjente; lokalt, ingen KI) og/eller ai=true (la KI tolke og bygge modell); eller mode build|approved|both. Uten valg beholdes jobbens egen mode. Sidene legges alltid inn først og blir stående selv om KI-delen feiler (da blir jobben done med result.partial; prøv igjen med retry_import_ai). Valgfritt: ceiling_usd (kostnadstak), continue_over_ceiling (etter stopp på taket), replace_model (bytt ut en modell med innhold; en versjon lagres først), approved_date. Jobben går til building; følg med get_import_job. |
| `retry_import_ai` | `POST /sessions/{sid}/agent/import-drawings/{jid}/retry-ai` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | «Prøv KI-tolking på nytt» for en jobb der sidene er lagt inn, men modellen ikke ble bygget (result.partial, f.eks. KI utilgjengelig). Kjører bare KI-delen; sidene legges aldri inn to ganger. |
| `apply_import_job` | `POST /sessions/{sid}/agent/import-drawings/{jid}/apply` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Legg et ferdig bygd resultat inn i økta etterpå (når modellen hadde innhold og replace_model ikke var satt). En versjon lagres først. |
| `cancel_import_job` | `POST /sessions/{sid}/agent/import-drawings/{jid}/cancel` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Stopp en importjobb (ingenting slettes: kilder, klassifisering og delresultater blir liggende). |
| `retry_import_job` | `POST /sessions/{sid}/agent/import-drawings/{jid}/retry` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Prøv en feilet importjobb igjen (til listen hvis sidene er klassifisert, ellers fra start). |
| `rerun_import_job` | `POST /sessions/{sid}/agent/import-drawings/{jid}/rerun` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Åpne en ferdig importjobb for en ny kjøring med andre valg (forrige kjøring beholdes). |
| `add_import_files` | `POST /sessions/{sid}/agent/import-drawings/{jid}/files/json` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | «Legg til fil»: flere PDF-er/bilder i en importjobb som venter på deg (waiting_for_user), f.eks. situasjonskartet i en egen fil. Sidene klassifiseres inn i SAMME jobb (én tolking; sidene teller én gang mot sidetelleren og dagsgrensen); sidene og valgene som alt er gjort blir stående. 409 not_waiting når jobben går eller er ferdig. Samme tilgang og grenser som import_drawings_job (base64 i JSON: files:[{name, data_b64}]). |
| `add_import_files_upload` | `POST /sessions/{sid}/agent/import-drawings/{jid}/files` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Samme som add_import_files, men som skjema-opplasting (multipart: files). BuildChat og Konverteringer bruker denne. |
| `rename_import_job` | `POST /sessions/{sid}/agent/import-drawings/{jid}/name` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Prosjektnavnet til en importjobb (project_name). Er økta ikke lagret som prosjekt, lagres den som prosjekt med dette navnet ved bekreft og når modellen er bygget (eier = brukeren eller økta sitt team). Bare før jobben er ferdig; tomt navn = forslaget fra tittelfeltet eller filnavnet. |
| `import_storage` | `GET /sessions/{sid}/agent/import-drawings/storage` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Alt som er lagret for økta og prosjektet fra importer: kildefiler (innholdsadressert), jobber, kjøringer (spec, rapport, versjon), tokens og kostnad. Bare lesing; Dibrix sletter aldri noe her. |

### Angre / gjør om / Undo / redo

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `undo` | `POST /sessions/{sid}/undo` | sandkasse (anonym) eller innlogget | write | Angre siste endring. |
| `redo` | `POST /sessions/{sid}/redo` | sandkasse (anonym) eller innlogget | write | Gjør om. |

### Versjoner og godkjenning / Versions & approval

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `list_baselines` | `GET /sessions/{sid}/baselines` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Sist godkjent av KOMMUNEN (ikke eierens «godkjent»): gjeldende referanse og historikk med saksnummer, vedtaksdato, kilde og versjon. |
| `set_municipal_baseline` | `POST /sessions/{sid}/baselines` | innlogget | write | Registrer en lagret versjon som godkjent av kommunen: version (id/nummer/latest), case_ref (saksnummer/vedtaksreferanse), decided_at ÅÅÅÅ-MM-DD, source (godkjent tegning), note. Uforanderlig og kan ikke overskrives; flere gir historikk, siste vedtak er gjeldende. Bare innlogget eier/admin, aldri med nøkkel. |
| `baseline_changes` | `GET /sessions/{sid}/baselines/changes` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | «Endret siden sist godkjent»: elementer lagt til, fjernet og endret (vegger, åpninger, dekker, tak, mål) i den levende modellen mot gjeldende (eller valgt) kommune-godkjenning, med tegn på om det krever søknad om endring av tillatelse. |
| `mark_phases_from_baseline` | `POST /sessions/{sid}/baselines/mark-phases` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Merk den levende modellen fra «endret siden sist godkjent»: uendret = eksisterende, endret = endres, nytt = ny (fasefarger slås på). Fjernede elementer finnes ikke i modellen og listes i svaret. Ett angresteg. |
| `save_version` | `POST /sessions/{sid}/versions` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Lagre økta som en NY uforanderlig versjon (igz + hus-spec + forhåndsvisning + tall). comment = hva er endret. Samme innhold som siste versjon lagres ikke to ganger (created=false). Prosjektets lagring (Ctrl+S) lager også versjon; 2-minutters autolagring gjør det ikke. phases/plan er reservert for faser og 5D (lagres med versjonen). |
| `list_versions` | `GET /sessions/{sid}/versions` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | List versjonene (nyeste først): nummer, tid, forfatter, kommentar, størrelse, hash, status (utkast/til gjennomgang/godkjent) og siste godkjente. |
| `open_info` | `GET /sessions/{sid}/open-info` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Hva en lenke trenger for å åpne «klart til test»: prosjektet økta hører til (navn til tittelen), siste versjon og om en nyere lagret versjon enn prosjektfila finnes (newer_version; åpne den med POST /projects/{id}/sessions?version=latest). Lenker kan ta ?scene=<navn> og ?version=latest|vN. |
| `get_version` | `GET /sessions/{sid}/versions/{vref}` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Hent én versjon (id, nummer 3 / v3 eller latest) med tall (elementer per type, areal, volum, bbox) og historikk. Selve filene: /igz, /spec, /preview.png. |
| `version_igz` | `GET /sessions/{sid}/versions/{vref}/igz` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Last ned versjonen som .igz (byte for byte som den ble lagret). |
| `version_spec` | `GET /sessions/{sid}/versions/{vref}/spec` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Hus-spec (JSON) som versjonen bar: les, rediger og bygg med build_house_from_spec. |
| `version_preview` | `GET /sessions/{sid}/versions/{vref}/preview.png` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Liten forhåndsvisning (PNG, iso) av versjonen. |
| `compare_versions` | `GET /sessions/{sid}/versions/{a}/compare/{b}` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Sammenlign to versjoner: elementer per type, bbox, areal, volum og hva som er lagt til/fjernet per spec-liste (vegger, åpninger, dekker, tak ...). |
| `approve_version` | `POST /sessions/{sid}/versions/{vref}/approve` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Godkjenn en versjon = «Sist godkjent» (BARE eier/admin). source (godkjenningskilde) er PÅKREVD: hva godkjenningen bygger på (saksnummer, signert tegning, e-post fra kunden, befaring). comment = notatet med underlaget for kilden (hvor dokumentet ligger). Lagrer hvem og når. Delelenker (viewer, standard) viser sist godkjente versjon. Den siste godkjente versjonen kan aldri trekkes tilbake, bare avløses av å godkjenne en nyere (med kilde). En endring etter godkjenning er en ny versjon (utkast) som må godkjennes på nytt. |
| `mark_as_built` | `POST /sessions/{sid}/versions/{vref}/as-built` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Merk en versjon «Som bygget» (BARE eier/admin). source er PÅKREVD: hva som-bygget-tilstanden bygger på (oppmåling, iGUIDE-tur, bilder, kontrollrapport). note = underlaget for kilden. Den nyeste merkingen er gjeldende; tidligere merker blir stående i historikken, og et merke kan ikke fjernes. Versjonen kan ikke slettes. |
| `set_version_status` | `POST /sessions/{sid}/versions/{vref}/status` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Sett status draft / review / approved: send til gjennomgang (redigeringsrett), avvis eller trekk tilbake godkjenning (eier; ikke den siste godkjente). Godkjenning krever source. Alt skrives til historikken. |
| `approved_overview` | `GET /sessions/{sid}/approved` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Siste godkjente versjon, «Som bygget», nyeste versjon, hvor mange som kom etter godkjenningen (needs_approval), hva som er til gjennomgang, hvilke versjoner som er beskyttet (kan ikke slettes) og statushistorikken (hvem/når). |
| `restore_version` | `POST /sessions/{sid}/versions/{vref}/restore` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | Gjenopprett en gammel versjon SOM NY versjon øverst (aldri overskriv). Den levende økta får innholdet (load=true). Den gamle versjonen er uendret. |
| `geometry_rules` | `GET /sessions/{sid}/geometry/rules` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Hvilke geometriregler modellen er lagret med mot dagens (vegg til tak o.l.): saved, now, older. En eldre modell bygges ikke om bak brukerens rygg; geometry_rules_update gjør det som ett angresteg. |
| `geometry_rules_update` | `POST /sessions/{sid}/geometry/update` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | write | «Oppdater til dagens regler»: bygg vegger som følger tak/dekke på nytt med dagens regler og stempl modellen, ett angresteg. Svaret viser vegger over tak før/etter og hvilke veggtopper som flyttet seg. Spør brukeren først. |

### Konto og prosjekt / Account & projects

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `project_storage` | `GET /projects/{project_id}/storage` | innlogget | read | Lagrede importdata per prosjekt (som import_storage, men for et prosjekt-id; krever lese-rett). |
| `list_conversions` | `GET /conversions` | innlogget | read | Status på konverteringene dine (tegninger/PDF, bilder, punktskyer) i alle prosjektene du kan se: én rad per opplasting med status (queued, interpreting, needs_decision, ready_to_accept, accepted, failed, cancelled, stored), forklaringskode, det tolkingen fant, needs (hva som trenger deg: needs_count, blocking_count, sidene, waiting_on med første side) og lovlige handlinger. |
| `project_conversions` | `GET /projects/{project_id}/conversions` | innlogget | read | Som list_conversions, men for ett prosjekt (krever lese-rett). |
| `conversion_action` | `POST /conversions/{jid}/action` | innlogget | write | Handling på en konvertering (krever redigeringsrett i prosjektet): accept (bekrefter listen og bygger modellen; ai_ack=true kreves når sidene tolkes av Claude; replace_model=true hvis modellen har innhold), rescan (reason: scale|storey_page|missing_walls|missing_openings|other; note kreves ved other; årsaken lagres som notat), ai_suggest (ai_ack=true: ETT KI-kall for hele dokumentet som foreslår svar på det uklare; du bekrefter), retolk (report_id = en rapport fra BuildChat i radens reports; teksten blir en brukerretting som går foran gjetninger, og jobben tolkes på nytt fra den lagrede originalen; ai_ack=true), feedback (reason: også rooms|roof|dimensions; note, page = sidens idx; lagres som notat; rerun=true tolker på nytt med teksten som retting, ai_ack=true), answer (point_id fra found.uncertain, answer: right|wrong|unsure, note = «Riktig er: …»), retolk_answers (alle svarene og egne mål som fasit til tolken; ai_ack=true), measure_add («Mål selv»: measure = {page, region?, kind: length|angle, a: [x, y], b: [x, y] i andeler 0-1 av siden i sidens egen ramme, value_mm (lengde) eller deg (vinkel; tom = regnet fra punktene og dreiingen), label: facade_length|wall|height|roof_pitch|ridge_height, rot}; går til tolken som FASIT FRA BRUKEREN; en lengde gir scale_hint = foreslått målestokk), measure_delete (measure_id), measure_label (measure_id + measure = {label}: bytt etiketten på et lagret mål), rename (project_name: prosjektnavnet økta lagres som prosjekt med; også på accept), cancel, delete (skjuler raden; modeller og versjoner slettes aldri). |
| `conversion_archive` | `POST /conversions/{jid}/archive` | innlogget | write | «Fjern fra lista»: flytter en konvertering til Arkiv (archived: true; krever redigeringsrett; ikke mens den går). Bare raden skjules: modellen, prosjektet, versjonene og kildefilene røres aldri. list_conversions med archived=only viser arkivet. |
| `conversion_unarchive` | `POST /conversions/{jid}/unarchive` | innlogget | write | Legg en arkivert konvertering tilbake i lista (archived: false). |
| `conversion_pages` | `GET /conversions/{jid}/pages` | innlogget | read | Sidene i en konvertering som venter på deg: type, etasje, retning, målestokk, dreiing, regionene (tegningene på hver side, med boks 0-1 i miniatyrens ramme), hva som er uklart (ask) og hva som bare er et forslag (suggested). Les-rett holder. |
| `conversion_edit_pages` | `POST /conversions/{jid}/pages` | innlogget | write | Rett sidene og regionene rett fra Konverteringer-raden (krever redigeringsrett; bare mens jobben venter på deg): edits:[{idx, kind, storey, view, scale_n, rotation, skew_deg, skip, building, region:{id, kind, storey, view, scale_n, building, role: drawing|titleblock, confirmed: true}}]. Dine valg vinner over gjetninger; ingen ny import trengs. |
| `conversion_page_view` | `GET /conversions/{jid}/pages/{idx}/view.jpg` | innlogget | read | En side i en konvertering i høy oppløsning (JPEG, 200 dpi, lengste side høyst px) til zoom; udreid som miniatyren. |
| `conversion_guides` | `GET /conversions/{jid}/guides` | innlogget | read | «Avklar mål»: hjelpelinjene per tegning (type, p0/p1 i sidens ramme 0-1, verdi_mm eller verdi_grader, kilde ai|kode|bruker|anker, sikkerhet, status forslag|godkjent|avvist), objektene som er de samme i plan, fasade og snitt (vegg:<Nord|Ost|Syd|Vest>:<ute|inne>[@etasje], apning:<ref> …), målekjedene med måltype (yttermaal|innemaal|aksemaal|senter_vegg) og regnestykket til ytre mål, og todo = «Hva skal tolkes» (objekter uten godkjent tall). Dagens «Mål selv»-mål står i legacy. Les-rett holder. |
| `conversion_guide_action` | `POST /conversions/{jid}/guides` | innlogget | write | Én handling i «Avklar mål» (krever redigeringsrett): guide_add (line = {bilde: {side, region?}, type: vegg_ute|vegg_inne|apning|uk_kledning|undertak_gesims|undertak_mone|takfot|mone|takvinkel|terreng|gulv|akse, objekt, p0, p1, verdi_mm | verdi_grader, lest_som paaskrevet|skalert, kilde ai|kode|bruker, sikkerhet}; ai/kode blir alltid forslag), guide_move (line_id, p0, p1, verdi_mm?), guide_set (line_id, verdi_mm | verdi_grader, approve?), guide_approve (line_id), guide_delete (line_id; et KI-forslag blir avvist og beholdes for læring), chain_add (chain = {bilde, retning x|y, sum_mm | deler_mm, maaltype?, fra?, til?, kilde}), chain_type (chain_id, maaltype: bekrefter med ett trykk), chain_set, chain_delete, object_set (objekt, verdi_mm …), drawing_approve (side, region?: alle forslag på tegningen godkjennes), guides_build (bygg modellen på nytt fra siste spec med de godkjente målene, uten KI-kall). Rettingene lagres som par KI sa / tegneren sa. |
| `conversion_findings` | `GET /conversions/{jid}/findings` | innlogget | read | Funnlisten i «Avklar mål»: hva tolkeren faktisk fant, lest fra det som er lagret (spec + provenance, hjelpelinjer, brukerens mål): items [{id, kind length|room|door|window|stair|wall|furniture, text, source vector|ai|tool|user, page, region, box (0-1 i sidens ramme, ellers null), conf, assumed, how, level, side, answer}], added (det brukeren sier mangler), facts (tall brukeren vet mot det tolkeren fant: {kind, count, level, side, found, ok}), counts, pages, gaps (hva som ikke er lagret). Skrivebeskyttet mot tolkingen. Les-rett holder. |
| `conversion_finding_action` | `POST /conversions/{jid}/findings` | innlogget | write | Én handling i funnlisten (krever redigeringsrett; konverteringen må ha bygget en modell): finding_answer (finding_id, answer right|wrong, note = «Riktig er …»), finding_add (finding = {kind, text, page?, region?, box?: [x0, y0, x1, y1] i sidens ramme}: det tolkeren ikke fant), finding_fact (fact = {kind, count, level?, side? Nord|Ost|Syd|Vest}: et tall du vet, f.eks. 6 vinduer på Syd i 1. etasje), finding_comment (finding_id, note: kommentar på en åpning/et funn), finding_delete (finding_id). Alt går til tolkeren som FASIT FRA BRUKEREN ved «Tolk på nytt» (retolk_answers). |
| `conversion_north` | `POST /conversions/{jid}/north` | innlogget | write | Retning (nord) som tolkningsdiskusjon (krever redigeringsrett): north_choose (deg = hvor nord peker på planen, grader med klokka fra opp på siden: 0 = opp, 90 = mot høyre), north_clear, north_address (address: slås opp hos Kartverket og et offentlig kart-API; krever innstillingen import.address_lookup, av som standard, ellers 409 lookup_off). Kildene (nordpil, fasadenavn, situasjonsplan, adresse), forslaget med sikkerhet og konflikt står i `north` i conversion_pages. Valget går til tolkeren som FASIT FRA BRUKEREN. Målestokk per tegning velges med conversion_pages (scale_n på regionen). |
| `conversion_thumb` | `GET /conversions/{jid}/pages/{idx}/thumb.png` | innlogget | read | Miniatyr (PNG) av en side i en konvertering. |
| `login` | `POST /auth/login` | åpen, uten innlogging | account | Logg inn (e-post + passord fra brukeren; aldri i chat-logg). |
| `logout` | `POST /auth/logout` | innlogget | account | Logg ut. |
| `whoami` | `GET /auth/me` | åpen, uten innlogging | read | Hvem er innlogget. |
| `list_prefs` | `GET /prefs/schema` | åpen, uten innlogging | read | Alle brukerinnstillinger: grupper, typer, områder, standarder og norsk/engelsk tekst (åpen). Se dem før du tegner: veggtype, snap, mål-tetthet, scener, BuildChat. |
| `get_prefs` | `GET /prefs` | innlogget | read | Brukerens gjeldende innstillinger (standard fylt inn) og det brukeren selv har endret. project_id gir prosjektets overstyringer. |
| `set_prefs` | `PUT /prefs` | innlogget | account | Endre brukerinnstillinger (values: {nøkkel: verdi}, reset: [nøkler], reset_groups: [grupper], project_id for prosjekt-overstyring). Varig: spør brukeren «skal jeg lagre dette som din standard?» først. Ugyldige verdier avvises enkeltvis i errors. |
| `key_info` | `GET /key/self` | innlogget | read | Hvem er denne API-nøkkelen (DIBRIX_API_KEY): nivå (read/propose/write), omfang (én økt eller prosjekter), utløp, bruk og om eieren fortsatt har tilgang. Aldri selve nøkkelen. Nøkkelen kan ikke godkjenne versjoner, lage delelenker eller nøkler, eller røre konto. |
| `api_keys_list` | `GET /api-keys` | innlogget | account | List eierens API-nøkler (uten selve nøkkelen): navn, nivå, omfang, utløp, sist brukt, antall bruk, aktiv. Krever innlogging (e-post + passord), ikke en nøkkel. Nye nøkler lages bare av et menneske i Konto → API-nøkler. |
| `api_key_revoke` | `DELETE /api-keys/{key_id}` | innlogget | account | Trekk en API-nøkkel tilbake med en gang (key_id fra api_keys_list). Krever innlogging, ikke en nøkkel. |
| `list_teams` | MCP | innlogget | read | Team for innlogget bruker (id, navn, slug, rolle). Bruk navnet i set_project_team. |
| `set_project_team` | MCP | innlogget | account | Legg et prosjekt i et team («lagre prosjektet i team Tegnebua»): team = navn, slug eller id fra list_teams. MCP: project_id = prosjektet som flyttes (PATCH /projects/{id} med owner_type=team). BuildChat: project_id kan utelates, da gjelder øktas prosjekt; er økta ikke lagret ennå, lagres den som nytt team-prosjekt med name (adressen). Eieren må være medlem av teamet. Vises under teamet i Mine prosjekter. |
| `list_projects` | MCP | innlogget | read | Prosjekter. |
| `create_project` | `POST /projects` | innlogget | account | Lag et nytt, tomt prosjekt (innlogget, ikke med API-nøkkel). owner_type=user (standard, eier = deg) eller team + owner_id (se list_teams); kind og template (fra GET /projects/templates) er valgfrie. Åpne det med bind_session(project=<id>). |
| `save_project` | MCP | innlogget | account | Lagre økta som prosjekt (Lagre som). |
| `save_into_project` | `POST /projects/{project_id}/save/{sid}` | innlogget | write | Lagre den bundne økta INN i et eksisterende prosjekt (Ctrl+S / POST /projects/{id}/save/{sid}). Ikke «Lagre som» (det er save_project). project_id fra list_projects/bind_session; sid = økt (standard: bundet). Lager også en versjon (comment valgfri). 409 stale_session = prosjektet har nyere versjon: åpne den, eller save_version bevisst. |
| `set_project_folder` | MCP | innlogget | account | Flytt et prosjekt til en mappe inne i Dibrix (feltet folder; vises i Prosjekter). Mappenavn = adressen, f.eks. «Marikloppa 9». Tom streng legger prosjektet i roten. Krever innlogging og tilgang til prosjektet. |
| `talk_message` | `POST /talk/message` | åpen, uten innlogging | write | Talebeskjed fra /talk (multipart, bare metadata): draft (lydbitene fra /talk/chunk og bildene fra /talk/photo), photos_expected (bilder siden tok), segments (JSON [{t, text}]), stt (browser|none), address, project_id, team_id, duration_s, position; team-lenke i X-Talk-Token eller feltet t. Eldre sider kan også sende audio og photos[] med photo_t/photo_geo: for store bilder gjøres mindre eller tas bort, men beskjeden avvises aldri for størrelsen. Teksten deles per bilde, og teamets admin(er) får e-post (bilder som ikke kom fram, står der). Er utkastet sendt, ettersendes nye bilder; ellers 409. |
| `talk_info` | `GET /talk/info` | åpen, uten innlogging | read | Det /talk-siden trenger: team, grenser (talk.max_minutes/max_photos/max_mb/remind_photo_s) og for innloggede teamene og teamets prosjekter. |
| `talk_messages` | `GET /talk/messages` | innlogget | read | Talebeskjeder til et team (medlem), nyeste først: adresse, avsender, transkripsjon, bilder med tekst og lenker til lyd/bilder. |
| `talk_audio` | `GET /talk/messages/{mid}/audio` | innlogget | read | Lyden til en talebeskjed (teammedlem). |
| `talk_audio_part` | `GET /talk/messages/{mid}/audio/{part}` | innlogget | read | Lyddel nr. part (0, 1, …) av en talebeskjed når lyden ble startet igjen underveis (teammedlem). |
| `talk_start` | `POST /talk/start` | åpen, uten innlogging | write | Et /talk-opptak begynner (lenke eller innlogget): gir draft-id for lydbitene som lastes opp underveis og for beskjeden til slutt. |
| `talk_chunk` | `POST /talk/chunk` | åpen, uten innlogging | write | Én lydbit under /talk-opptaket (multipart: audio, draft, seg, seq, start_s, at). Sendes hvert ~5 s, så en stopp eller et krasj ikke mister lyden; omsending av samme bit gir 200. |
| `talk_photo_upload` | `POST /talk/photo` | åpen, uten innlogging | write | Ett bilde under /talk-opptaket, med en gang det er tatt (multipart: photo, draft, idx, at = tid i s, geo = JSON {lat, lon, acc}). Siden gjør bildet mindre først (talk.photo_max_px, talk.photo_quality); er det over talk.max_mb samlet, gjør serveren det mindre, ellers 413. Omsending av samme idx gir 200; etter at beskjeden er sendt lagres bildet for ettersending. |
| `talk_drafts` | `GET /talk/drafts` | innlogget | read | Opptak til teamet som ble startet, men aldri sendt (team_admin): avsender, antall lydbiter, lydens lengde, bilder, størrelse. |
| `talk_draft_finish` | `POST /talk/drafts/{did}/finish` | innlogget | write | Fullfør et /talk-opptak som aldri ble sendt (team_admin): lyden settes sammen, bildene som kom fram tas med, og teamets admin(er) får e-posten som om avsenderen hadde trykket «Stopp og send». Et sendt utkast med nye bilder gir ettersending; ellers 409. |
| `talk_photo` | `GET /talk/messages/{mid}/photos/{i}` | innlogget | read | Bilde nr. i i en talebeskjed (teammedlem). |
| `talk_skann_upload` | `POST /talk/skann/upload` | åpen, uten innlogging | write | Last opp et skann per etasje (multipart: fil = Scaniverse .ply eller .glb, navn, project_id, team_id; team-lenke i X-Talk-Token eller feltet t). Serveren finner gulv og himling, retter mot veggaksene, måler hver vegg i 110-snittet, takkontrollen og loddrette snitt hver meter, og svarer planen: rom med hjørner, mål per vegg (median over snittene, spredning, antall snitt, status sjekk/skann/gronn/laser), takhøyde per rom, lukkefeil, vinkler og «x av y grønne». Tersklene: skann.plan.* (get_prefs). |
| `talk_skann_del` | `POST /talk/skann/del` | åpen, uten innlogging | write | «Del til Dibrix» fra en iOS-snarvei (Del-arket i Scaniverse): multipart med fila (fil eller file = .ply/.glb) og eventuelt navn, lang; team-lenke-tokenet BARE i headeren X-Talk-Token (token i adressen gir 400, uten token 401). Samme tilgang som /talk-lenken (bare innsending). Svarer kort tekst snarveien kan vise: «Mottatt …: planen er klar … Åpne planen: <lenke>». |
| `talk_skann_list` | `GET /talk/skann/list` | innlogget | read | Teamets skann fra /talk/skann (teammedlem). |
| `talk_skann_get` | `GET /talk/skann/{skann_id}` | åpen, uten innlogging | read | Planen fra ett skann med rettingene lagt inn og statusen regnet med dagens terskler (teammedlem, eller lenken som lastet det opp). |
| `talk_skann_veggbilde` | `GET /talk/skann/{skann_id}/vegg/{key}.png` | åpen, uten innlogging | read | Fargebilde rett inn mot én vegg fra skannet (ortofoto 1 cm/piksel, 8 cm bak til 0,9 m foran flaten, nærmeste punkt øverst): key = «<etasje>-<rom>-<vegg>», lenken står i vegg.bilde i planen. Samme tilgang som talk_skann_get. |
| `talk_skann_retting` | `POST /talk/skann/{skann_id}/retting` | åpen, uten innlogging | write | Rett ett mål med laser: {etasje, rom, vegg, lengde_m} (naboveggene flyttes parallelt, de andre veggene minst mulig) eller {etasje, rom, takhoyde_m}, eller en åpning (vindu/dør): {etasje, rom, apning, bredde_m, hoyde_m, fra_hjorne_m, over_gulv_m} eller {…, apning, fjern: true} (ikke en åpning). Åpningen er grønn når bredde og høyde er målt. lengde_m = 0/null fjerner laser-målet. Lagres som logg (hvem, når, fra, til) så tolken kan lære. |
| `talk_skann_modell` | `POST /talk/skann/{skann_id}/modell` | innlogget | write | Lag modell fra skann: den godkjente skannplanen (med laser-rettingene) blir et NYTT Dibrix-prosjekt i teamet, lagret som en ny versjon (aldri overskriving). Innervegger fra to flater (tykkelse = avstanden, senterlinje midt mellom), yttervegger som lukket ring med antatt tykkelse (oransje til den er rettet), dekke per etasje, rom med navn og areal, vinduer og dører på riktig vegg (laser-mål = grønn, ellers standardmål og rød «bekreft mål»), trapp og sanitær fra skyen (infrastruktur=true). fra_sky (standard true, T-1699): bygg via spec_fra_sky fra råskann (vegger/etasjer/åpninger/rom); false = skannplan; kun_utside for fasade. Status rød/oransje/grønn står i Objektinfo; retter du målet i modellen, blir den grønn. Svarer prosjektet, økta, versjonen, BRA/BTA/BYA og antall per status. Innstillinger: skann.modell.* (get_prefs). Bare innlogget teammedlem. |
| `talk_link_create` | `POST /talk/links` | innlogget | account | Lag en hemmelig team-lenke til /talk (team_admin): team_id, label (hvem den er til), ttl_days (standard 90, høyst 365). Tokenet vises bare i svaret; serveren lagrer bare hashen. Lenken kan bare sende inn beskjeder. |
| `talk_link_list` | `GET /talk/links` | innlogget | read | Teamets /talk-lenker (team_admin), uten token. |
| `talk_link_revoke` | `DELETE /talk/links/{lid}` | innlogget | account | Trekk tilbake en /talk-lenke med en gang (team_admin). |
| `retolk_laering` | `GET /retolk/laering` | innlogget | read | Læringsdata for tolkebenken: rettingene brukerne har meldt til tolken (tekst uten navn og adresse, jobb-id, kategori: apninger, vegger, etasjer, terreng, tak, scener, annet) og antall per kategori. Bare systemadmin eller retolk-nøkkelen. |
| `intake_access` | `GET /intake/me/access` | innlogget | read | Min tilgang til KI-tolking av tegninger via Dibrix-maskinen (teamets Claude-abonnement): tillatt, grunn hvis ikke, dagsgrense og brukt siste døgn, testperiode, og hvilken leverandør «auto» gir meg. |
| `intake_team_get` | `GET /teams/{team_id}/intake` | innlogget | read | Teamets valg for KI-tolking via Dibrix-maskinen: hvem (intake.cli_members: owner|selected|all + selected_members), dagsgrense, tidsavbrudd, hvor lenge originalen ligger, testperiode (intake.test_until). Medlemmer kan lese. |
| `intake_team_set` | `PUT /teams/{team_id}/intake` | innlogget | account | Teameier/team_admin endrer valgene (bare valg fra listen i options). platform_enabled kan bare en systemadmin slå på. Krever innlogging, ikke en nøkkel. |
| `intake_team_usage` | `GET /teams/{team_id}/intake/usage` | innlogget | read | Bruksoversikt for teameier siste 30 døgn: jobber, sider og siste tidspunkt per bruker. Bare tellere, ingen innhold. |
| `intake_status` | `GET /intake/status` | innlogget | read | Synlig status for Dibrix-maskinen (Alt B): state (working|idle|offline|paused), sist sett, kø og anslått ventetid. Teameier/systemadmin får også arbeidere, siste jobber og et eierpanel per team (sider og kall per medlem mot dagsgrensen). Vanlige teammedlemmer får bare den korte statusen. Terskelen er innstillingen intake.offline_after_s. |
| `intake_agent_tool` | `POST /intake/{qid}/tool` | innlogget | write | Agent-tolk (innstillingen import.mode_agent): ett verktøykall fra Claude på Dibrix-maskinen mot en arbeidskopi av tolkingen (side/utsnitt, bygg, render, tellere, areal, leveringssjekk, maal, utkast, budsjett; «_list» gir listen). Bare med intake-nøkkel og bare for en agent-forespørsel som er utleid til arbeideren. Grenser: import.agent_max_tools, import.agent_max_heavy, import.agent_max_min; hvert kall logges på forespørselen. |

### BuildChat (KI i appen) / BuildChat (in-app AI)

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `build_chat` | `POST /sessions/{sid}/build-chat` | innlogget | write | Én BuildChat-tur (KI-en i appen kjører Python i økta). |
| `build_chat_stream` | `POST /sessions/{sid}/build-chat/stream` | innlogget | write | Samme tur som build_chat, men som SSE med framdrift per runde (progress ... done). |
| `build_chat_smart` | MCP | innlogget | write | BuildChat-tur med modellbrief lagt til (bedre tolkning). |
| `build_chat_status` | `GET /sessions/{sid}/build-chat/status` | innlogget | read | Er BuildChat konfigurert / opptatt? |
| `build_chat_stop` | `POST /sessions/{sid}/build-chat/stop` | innlogget | write | Stopp en pågående BuildChat-tur (clear_queue=true tømmer også køen; ellers kjøres beskjedene i kø etterpå). |
| `build_chat_inbox_add` | `POST /sessions/{sid}/build-chat/inbox` | innlogget | write | Beskjed underveis: legg en melding i BuildChat-køen mens en tur kjører. Innstillingen «Nye beskjeder under kjøring» avgjør om den leses inn mellom stegene (styr) eller kjøres som neste tur (kø). running=false: ingen tur tar den, start med build_chat_stream {from_inbox: true}. |
| `build_chat_inbox_list` | `GET /sessions/{sid}/build-chat/inbox` | innlogget | read | BuildChat-køen: meldinger i kø og lest (status queued|read), om en tur kjører. |
| `build_chat_inbox_edit` | `PUT /sessions/{sid}/build-chat/inbox/{item_id}` | innlogget | write | Endre en melding som fortsatt ligger i BuildChat-køen (409 når den er lest). |
| `build_chat_inbox_delete` | `DELETE /sessions/{sid}/build-chat/inbox/{item_id}` | innlogget | write | Fjern en melding som fortsatt ligger i BuildChat-køen (409 når den er lest). |
| `build_chat_clear` | `POST /sessions/{sid}/build-chat/clear` | innlogget | write | Tøm BuildChat-historikken. |

### Drift og feilsøking (bare systemadmin) / Operations & debugging (system admin only)

| Verktøy | Rute | Tilgang | Effekt | Hva |
|---|---|---|---|---|
| `report_to_developer` | `POST /sessions/{sid}/dev-feedback` | innlogget | write | Meld til utviklerne fra en økt (samme som BuildChat-verktøyet): kind feil | ønske | tolkefeil | mangler (utelatt = gjettes), text, entity_ids, render=true legger ved et lite bilde. Endrer ikke modellen. Følger med: økt, bruker, app-rev, de siste BuildChat-rundene. |
| `request_capability` | `POST /sessions/{sid}/dev-feedback` | innlogget | write | Be utviklerne om et manglende verktøy/parameter (kind=mangler): goal, attempted_tool, expected_params (JSON-skjema), error_response, registry_version, workaround_tried. Standard: innlogging (eier). Delenøkkel/sandkasse bare når DIBRIX_MANGLES_SHARE=1. Svar: id + poll GET /agent/requests/{id}?t=… (status, notat, midlertidig løsning; bare oppretteren). Dedupes på verktøy+mål+feilkode. Ukjent op / 404 / 422 får how_to_request automatisk. |
| `get_capability_request` | `GET /agent/requests/{mid}` | åpen, uten innlogging | read | Les status på din egen mangler-forespørsel (poll_token fra request_capability). Returnerer status, notat og midlertidig løsning. |
| `list_developer_messages` | `GET /dev-feedback` | innlogget | read | Meldinger til utviklerne fra BuildChat og API, nyeste først: id, type, tekst, økt, prosjekt, bruker, rev, element-id-er, samtale (siste runder), bilde_url, status. status = apen (standard) | under_arbeid | lukket | avvist | alle. Systemadmin, X-Ops-Token, feedback_reader eller feedback-nøkkel ser alle; team_admin ser meldinger fra teamets medlemmer og prosjekter. |
| `close_developer_message` | `POST /dev-feedback/{mid}/status` | innlogget | write | Sett status på en melding til utviklerne: lukket (standard; note = PR/rev som løste den), under_arbeid eller avvist (note = grunn). Logges med hvem og tid. Samme tilgang som list_developer_messages (team_admin bare for teamets meldinger). |
| `ops_errors` | `GET /ops/errors` | innlogget | read | Feilgrupper fra nettleser, Skall og serverens egne 500-feil: fingeravtrykk, antall, første/siste gang, rev, rute, stakk, siste handlinger. Alt er renset (ingen e-post, nøkler, modellinnhold). Bare systemadmin (innlogget) eller X-Ops-Token; aldri med API-nøkkel. |
| `ops_input_log` | `GET /ops/input-log` | innlogget | read | Inndata-opptak fra nettlesere med opptak på (?debug=input eller innstillingen debug.input_log): per anonym fane trykk, pekertype, hjul, valg-treff, scenebytter med siste inndata før (årsaken), lag og visning. Renset, ingen tekst eller modellinnhold. Bare systemadmin eller X-Ops-Token. |
| `recording_timeline` | `GET /ops/recordings` | innlogget | read | Opptak for feilsøking per bruker i et tidsvindu: fanene (økt, nettleser, skjerm, modus) og én tidslinje der inndata (klikk, trykk, tekst i Dibrix-felt med etikett, pause/fortsetter), BuildChat-meldinger, øktenes operasjonsjournal, feilgrupper fra de samme fanene, importjobbenes hendelser og WARNING/ERROR fra dibrix-web.log er flettet. user = bruker-id eller e-post (tom = alle), since/until = ISO, epoch eller relativt (2h, 30m, 1d; standard siste døgn, maks 7 døgn), sources = kommaliste input,buildchat,oplog,error,job,log. Maskert (e-post, telefon, nøkler). Bare systemadmin eller X-Ops-Token. |
| `client_input` | `POST /client-input` | åpen, uten innlogging | write | Nettleseren sender en bunke opptakslinjer (bare når inndata-opptak er slått på). Åpen, begrenset og renset. |
| `ops_logs` | `GET /ops/logs` | innlogget | read | Siste linjer av dibrix-web.log, maskert (e-post, nøkler, lange id-er, IP, URL-spørring). lines (maks 1000), q = tekstsøk, level = WARNING|ERROR, file 0-3 = roterte filer. Bare systemadmin eller X-Ops-Token. |
| `ops_status` | `GET /ops/status` | innlogget | read | Serverstatus nå: rev, oppetid, økter, minne, disk, alder på siste sikkerhetskopi, loggstørrelse, feil siste døgn. Bare systemadmin eller X-Ops-Token. |
| `session_oplog` | `GET /sessions/{sid}/oplog` | innlogget: eier, admin, redigerer i prosjektet — eller wr_-nøkkel (?share=) OPPÅ innlogging/dk_ | read | Journal over de siste skrivende operasjonene i økta (renset: ingen hemmeligheter, ingen lange tekster). Spill dem mot en ny økt med scripts/replay_oplog.py for å gjenskape en feil. |

### Bare i BuildChat (Python i økta)

| Verktøy | Kall | Hva |
|---|---|---|
| `create_wall` | `create_wall((0,0), (6,0))` | Én vegg a→b (BuildChat). Bruk walls_closed for en ring. |
| `join_plan_walls` | `join_plan_walls()` | Skjøt overlappende / T / L-vegger i plan (som UI). |
| `create_railing` | `create_railing([(0,0),(4,0)], z0=0, style='liggende', height=0.9)` | Parametrisk rekkverk langs en sti (liggende|spiler|glass|massiv), avkortes mot tak (BuildChat). |
| `create_column` | `create_column((3.0, 0.07), size=(0.14, 0.14))` | Søyle i (x, y); høyde utelatt = opp til bjelken eller takundersiden over (BuildChat). |
| `create_beam` | `create_beam((0, 0.07), (6, 0.07), width_m=0.14, depth_m=0.36, name='Limtrebjelke GL30c 140x360')` | Bjelke a→b; z0 utelatt = bærer taket: toppen mot sperrene, følger taket, søylene under følger (BuildChat). |
| `create_chimney` | `create_chimney((2,1), shape='rect', size=(0.52,0.63), z0=0, z1=6, above_ridge_m=0.8)` | Parametrisk skorstein (rect|round, seksjoner, røykløp, hatt) med topp over møne (BuildChat). |
| `set_cladding` | `set_cladding(type='liggende')` | Parametrisk kledning på ytterveggene (motoren lager bordene). |
| `define_spilevegg` | `define_spilevegg(stud_h=0.148, stud_cc=0.6, slat_w=0.07, slat_t=0.028, gap=0.025, sides='outside')` | Veggtype «spilevegg»: åpent stenderverk (48x148 / 48x98, c/c) med åpne liggende spiler (bredde, tykkelse, luft, side). |
| `set_cladding_sides` | `set_cladding_sides('both', wall_ids=[...])` | Kledning/spiler per vegg: ute, inne eller begge sider (resten av stilen beholdes). |
| `set_slab_boundary` | `set_slab_boundary(slab_id, [(0,0),(8,0),(8,6),(0,6)])` | Endre omrisset til et dekke (beholder id). |
| `build_drawing_set` | `build_drawing_set(replace=False)` | Nytt tegnesett fra scratch (BuildChat). |
| `be_om_retolking` | `be_om_retolking('Stua er 5,2 m, ikke 4,2 m; mangler vindu i soverommet', side=1)` | Meld fra til tolken: bestill ny tolking når kunden sier at tolkingen av tegningen er feil. Kobles til konverteringen modellen kom fra (originalen ligger der), vises i Konverteringer med «Tolk på nytt med denne rettingen», og svaret har lenke og neste steg (BuildChat; «meld fra til tolken» går dit uten LLM-runde). |
| `retolk_status` | `retolk_status()` | Status og svar på bestillinger om ny tolking fra denne økta (apen|under_arbeid|ferdig|avvist) (BuildChat). |
| `report_to_developer` | `report_to_developer('ønske', 'Kledningen kuttes ikke rundt et rundt vindu, og rund karm finnes ikke', ['w12'])` | Meld til utviklerne (ikke tolken): kind = feil | ønske | tolkefeil | mangler, text = hva som mangler eller er feil, entity_ids valgfritt. Lagres med økt, bruker, app-rev, de siste BuildChat-rundene og et lite bilde. «si ifra til utvikler», «meld feil», «dere bør lage» går dit uten LLM-runde. Si aldri «meldt» uten svar ok. For strukturert verktøyhull: bruk request_capability (kind=mangler). |
| `request_capability` | `request_capability(user_asked='endre vindusbredde med skyveknapp', proposed_tool='set_opening_width', expected_params={'opening_id':'o1','width_m':1.2}, nearest_tools=['edit_opening','set_element_props'], why_not='edit_opening mangler bredde-håndtak i UI', expected_result='vindu får ny bredde', example='set_opening_width(o1, 1.2)')` | Når BuildChat ikke kan utføre brukerens forespørsel (verktøy/parameter/tilstand mangler): lag strukturert utviklerforespørsel. user_asked (én setning), proposed_tool (foreslått navn), expected_params, nearest_tools, why_not, expected_result, example. Dedupes. |
| `ui_help_upload` | `ui_help_upload()` | Hvor brukeren laster opp PDF/bilder i BuildChat (📎 ved Send, hint på mobil) og alternativet Fil ▸ Last opp tegninger. Kall når brukeren spør «hvor laster jeg opp» / «finner ikke vedlegg» — ikke request_capability. |


## Ordbok og hurtigoppslag

Generert fra koden (bim/ordbok.py + levende konstanter); ingen repo trengs.

## Typer (levende)

dørtyper (style.type): slett, speil, glass, helglass, garage, dobbel, skyve, skyve_vegg, lomme · vindustyper: fast, 1-floy, 2-floy · takbelegg: shingel_rett, shingel_skra, shingel_drape, shingel_kuttet, shingel_swing, stein_dobbelkrum, stein_flat, falset_stal, torv_sedum, stein_tegl, stal_trapes, papp, skifer · falsetfarger: Rød, Sort, Antrasitt, Grå, Grønn, Brun · kledning: liggende, stående

## Ord → kode

| Norsk | English | Kode / bruk |
|---|---|---|
| yttervegg / ytterring | exterior wall ring | create_wall_path(corners, closed=True, thickness_m=…): lukket ring bygges innover (auto_align_closed) |
| innervegg | interior wall | create_wall / create_wall_path (åpen); navn «Innervegg a.b» |
| tak: saltak, valmtak, pulttak, flatt | gable, hip, shed, flat roof | create_roof_from_walls(form='gable'|'hip'|'shed'|'flat', slope_deg, overhang_m, covering) |
| møne, raft, gavl | ridge, eave, gable end | edge_roles per kant: 'slope' (raftside) / 'gable' (gavlside); møne ligger parallelt med slope-kantene |
| T-tak, L-tak, tverrgavl | cross gable | tegn yttervegg-ringen som T/L → ett sammenføyd tak, hvert fløymøne. På rektangel: T-ring med 2 cm stamme + eksplisitte edge_roles. ALDRI to tak oppå hverandre |
| kvist / ark | dormer | add_roof_opening(kind='ark'), kun små; stor tverrgavl = T-tak |
| takvindu | roof window / skylight | POST /roof_window eller BuildChat takvindu() (VELUX series/size) → glass+karm; roofs[].openings kind='takvindu' er bare hullet (cut i én takflate). Ikke det samme som kind='takopplett' |
| takbelegg (belegning) | roof covering | covering={'type': …, 'color': …}; se typer under |
| falset / stående falset | standing seam | covering type 'falset_stal'; farger se under |
| torvtak / sedumtak / grønt tak / gress på taket | green roof / sedum roof | covering type 'torv_sedum' (farger Sedum, Gress, Torv, Høstsedum); aldri bare en grønn farge |
| teglstein / bølgeblikk / takpapp / skifer | clay tile / corrugated sheet / roofing felt / slate | covering type 'stein_tegl' / 'stal_trapes' / 'papp' / 'skifer'; anbefalt takvinkel: list_roof_finishes() pitch_deg |
| takutstikk | overhang | overhang_m, per kant edge_overhangs |
| kledning: stående / liggende | cladding: vertical / horizontal | set_cladding(on=True, type='stående'|'liggende', cover, utlekting, t, material). Ligger UTENPÅ kjernen (+0,042 m: utlekting 0,023 + bord 0,019): kjernen blir tynnere |
| kjernetykkelse under kledning | core thickness under cladding | normalize_cladding_thickness(viewport): kjerne = målt total - kledningsoffset (0,042), ytterflaten av kledningen uendret, etasjeskille/dekke inset mot kledd ytterflate. Murvegger (navn mur/ringmur/sokkel/fundament, kjeller) er unntatt: de har ikke kledning og beholder målt tykkelse |
| vegg opp til taket | walls to roof | set_walls_to_roof(True): følger taket (høyeste underside ved flere tak) |
| dør | door | place_opening(host_id, kind='door', offset_m, width_m, height_m, hinge, style={type: …}) |
| ytterdør med glass | glazed door | style={'type':'glass','glass_w':0.52,'glass_z0':0.16,'glass_z1':1.91} (glassets egen størrelse, høyder fra dørfot) |
| vindu | window | place_opening(host_id, kind='window', sill_m, width_m, height_m, style={type: …}) |
| fastkarm (én ramme) | fixed window | style.type='fast' |
| åpningsvindu (karm + ramme, to rammer) | casement window | style.type='1-floy' (standard); to ruter med midtpost = '2-floy' |
| karm / ramme | frame / sash | style.karm_w (karm) / style.sash_w (ramme i åpningsvindu), frame_width_m |
| gerikt / omramming | casing / trim | style.trim_out + trim_out_w (utvendig), trim_in* (innvendig); utforing = lysningsbord karm→kledning |
| delt gerikt | shared casing | åpninger nærmere enn to gerikter får ÉN gerikt mellom seg (venstre tegner den, høyre ingen): style trim_out_wl/trim_out_wr settes automatisk av bim.api |
| takopplett / innskåret tverrgavl | roof notch | create_roof / build_roof(openings=[{'kind':'takopplett','boundary':[…],'cut':'perpendicular'|'plumb'}]): kutt gjennom taket; takopplettet selv er et eget pulttak |
| ulik takfot | eave rises | build_roof(edge_rises=[m per kant]): takfot over z_eave per kant; del ikke taket i flere pulttak |
| rekkverk | railing | agent_ops.create_railing(path, z0=, style='liggende'|'spiler'|'glass'|'massiv', height=, clip_roofs=[…]) (bim/railing_paths.py); veranda/terrasse: bim/railings.py |
| skorstein / pipe | chimney | agent_ops.create_chimney((x, y), shape='rect'|'round', size=, z0=, z1=, sections=[…], above_ridge_m=0.8, cap=True) |
| vannbrett / sålbenk | sill flashing / sill | vannbrett*, salbenk i vindusstilen |
| rundt vindu / rundbue / køyevindu | round window / arched window | place_opening(host_id, kind='window', shape='circle', width_m=diameter) | shape='arch' (arch_rise_m = stikk, ellers innstillingen opening.arch_rise); edit_opening(id, shape='circle'|'arch'|'rect'). Hullet, kledningen, karmen, rammen og gerikten følger formen |
| åpning som ikke er firkant (vinklet loftsvindu) | non-rectangular opening | outer_loop_uv=[[u, z], …] på place_opening (z absolutt); veggens hull følger omrisset |
| hull / åpning uten karm | void | place_opening(kind='opening') |
| hengsel / slå | hinge / swing | hinge='left'|'right', style.swing |
| dekke / etasjeskille / såle | slab / floor | kind 'slab' (z_top, thickness_m); to_slab lar vegger stoppe under dekket |
| glass | glass | undergruppe window_glass med opasitet 0,35 (gjennomsiktig også på Web) |
| bilde av modellen / se | picture of the model / look | GET /sessions/{sid}/render.png?view=iso|front|back|left|right|top&hide=SKP-import&focus=<id>&section=z:2.4 (MCP: render); uten nettleser |
| oversikt uten å bygge mesh | light overview | GET /sessions/{sid}/scene-summary (antall per type, boks per element, lag, etasjer, referanse); id-ene virker i focus/hide |
| original mot tolket | original vs interpreted | GET /sessions/{sid}/compare?with=<sid2> (tall) eller render.png?side_by_side=<sid2> (ett bilde, samme kamera) |
| møbler / komponent / seng / sofa / toalett / servant / dusj | furniture / component / bed / sofa / toilet / washbasin / shower | find_component(q) søker i komponentbiblioteket: bare Dibrix' parametriske typer (dibrix-furn-seng, -sofa, -toalett, -servant, -dusj; params med område), ingen mesh-katalog (fjernet 2026-11-06; trær, biler og mennesker finnes ikke der). insert_component(id, x, y, z, rot, size_m=[b, d, h]) setter inn en instans av en DELT prototype bygget i de målene (midten av bunnen i x,y,z, meter), ett angresteg. I hus-spec: furniture=[{ref: id, at: [x,y,z], rot_deg, params: {width_m, …}}]. Miniatyr (SVG): GET /library/{id}/thumb |
| høyt under taket / hvor langt ut / litt større | everyday words | hverdagsord -> tall: se «Hverdagsord» under. bim.hverdag.tolk(tekst) gir verktøykall; draft_from_description(tekst) gjør det og bygger |
| hus-spec / hele huset fra én JSON | house spec | build_house_from_spec(spec, replace=False) bygger etasjer, vegger, åpninger, dekker, tak, trapper, søyler, bjelker, rekkverk, skorstein og terreng på sekunder (ett angresteg); get_house_spec() leser ut. Skjema + eksempel: GET /spec/schema. Navn som i agent_ops (height_m, thickness_m, offset_m, slope_pct, edge_roles) |
| fase / eksisterende / rivning / nybygg / tilbygg | phase / existing / demolition / new / extension | add_phase_presets(), create_phase(name, kind), assign_phase(phase, element_ids | kind='wall'); element uten fase er i «ny». Eksisterende vises grå og koster 0, rivning koster rivepris. hus-spec: phases + phase på elementet |
| tidsplan / Gantt / kritisk sti / 4D | schedule / Gantt / critical path / 4D | suggest_plan(start) lager tasks fra mengder; set_task({name, phase, duration_d, deps}); plan_summary() gir Gantt, kritisk sti, kost og S-kurve; plan_visible_at(dato) viser byggefremdrift |
| kost / 5D / budsjett / S-kurve | cost / 5D / budget / S-curve | set_plan_settings(unit_prices={'wall': {'unit': 'm2', 'nok': 1200}}, budget={'total': ...}); cost_summary() per fase, kind og måned; compare_cost(before) gir kostnad før/etter |

## Hverdagsord (Enkel) ↔ verktøy (Proff)

Samme data og verktøy: «Enkel» og «Proff» er en innstilling som styrer ordvalg og felt, ikke to produkter. Verdiene er innstillinger (`bim.hverdag.DEFAULT_PREFS`).

| Du sier | Verktøy | Argumenter |
|---|---|---|
| høyt under taket | `set_dimensions` | `{'height_m': 2.7}` |
| litt større | `set_dimensions` | `{'scale': 1.15}` |
| mye mindre | `set_dimensions` | `{'scale': 0.667}` |
| 6 x 4 | `set_dimensions` | `{'length_m': 6.0, 'width_m': 4.0}` |
| 20 kvadrat | `set_dimensions` | `{'area_m2': 20.0}` |
| saltak | `set_roof_style` | `{'form': 'gable'}` |
| brattere tak | `set_roof_style` | `{'slope_pct': 50.0}` |
| stort takutstikk | `set_roof_style` | `{'overhang_m': 0.8}` |
| stående panel | `set_cladding_style` | `{'direction': 'stående'}` |
| sort tak | `set_colors` | `{'tak': 'sort'}` |
| hvitt hus | `set_colors` | `{'kledning': 'hvit'}` |
| svalgang | `add_overbygg` | `{'kind': 'svalgang', 'wall_side': 'front', 'depth_m': 1.5}` |
| takoverbygg | `add_overbygg` | `{'kind': 'overbygg', 'wall_side': 'front', 'depth_m': 1.2}` |
| to rom | `add_rooms` | `{'count': 2, 'layout': 'jevnt'}` |
| nordveggen er 8,03 m | `add_anchor` | `{'kind': 'ytterlengde', 'side': 'nord', 'value_m': 8.03}` |
| vindu mot sør | `place_openings` | `{'kind': 'window', 'count': 1, 'wall_side': 'sor', 'distribution': 'senter'}` |
| vindu midt på sørveggen | `place_openings` | `{'kind': 'window', 'count': 1, 'wall_side': 'sor', 'distribution': 'senter'}` |
| to vinduer mot hagen | `place_openings` | `{'kind': 'window', 'count': 2, 'wall_side': 'bak', 'distribution': 'jevnt'}` |
| dør i hjørnet | `place_openings` | `{'kind': 'door', 'count': 1, 'wall_side': 'front', 'distribution': 'hjorne_hoyre'}` |
| døra ved hjørnet | `place_openings` | `{'kind': 'door', 'count': 1, 'wall_side': 'front', 'distribution': 'hjorne_hoyre'}` |

Plassering i ord går til `bim.plassering.place_openings`: vinduer midt på eller jevnt fordelt, dør 0,9 m, minst 0,3 m fra hjørnet, aldri oppå hverandre. Planen har +y = nord; «front» = sør; «hagen» er en antakelse (nord) som sies høyt.

## Oppskrifter

- Faser og plan (T56): add_phase_presets() → assign_phase('eksisterende', kind='wall') for det som står, assign_phase('tilbygg', element_ids=[…]) for det nye → set_plan_settings(start='2027-03-01', unit_prices={…}) → suggest_plan() → plan_summary() (Gantt, kritisk sti, kost per fase og måned) → set_phase_visibility(hidden=['rivning']). Alt er ett angresteg hver. Hus-spec bærer phases, plan og phase per element.
- Hus fra spec (raskest, alt i ett kall): hent eksemplet fra GET /spec/schema (eller get_house_spec() på en eksisterende modell), endre tallene, bygg med build_house_from_spec(spec). Vegger har id (w1…), åpninger refererer med host='w1', tak har boundary (ytre veggflate-ring) og edge_roles per kant. Svaret har warnings (hva som ble hoppet over) og timing. Rett opp i spec-en og bygg på nytt med replace=True, ikke legg til flere kall.
- Møblere: find_component('seng') gir dibrix-furn-seng (parametrisk, params width_m/depth_m/height_m med område); insert_component('dibrix-furn-seng', x, y, 0, rot=90, size_m=[1.8, None, None]) plasserer (hundrevis av like møbler er hundrevis av matriser over én prototype). Med hus-spec: legg furniture=[{ref, at, rot_deg, params}] i samme spec som veggene. get_house_spec() leser plasserte møbler tilbake som furniture. Finnes ingen type (stol, bord, skap): si det, ikke finn på en id.
- Hus fra mål: create_wall_path(ring, closed=True, thickness_m=0.2) → create_roof_from_walls(form='gable', slope_deg=…, covering=…) → set_walls_to_roof(True) → place_opening per åpning → set_cladding(…).
- SKP/importert modell → BIM: plan fra veggbunnene (tykkelse = avstand mellom de to store parallelle flatene) → høyder fra dekke og tak → tak (form, T-ring, belegg) → åpninger fra hullgeometrien (outer_loop_uv for vinklede) → dørtype/vindustype fra de nestede omrissene → kledning fra tekstur (uvw gir retningen). Skjul referanselaget «SKP-import» og se på resultatet.
- Åpning med vinklet topp: hent hjørnene fra flaten, regn om til (u, z) langs veggen, outer_loop_uv.
- Sjekk alltid: plan/areal etter hver endring, og se på modellen. Tall alene sier ikke at det ser riktig ut.
- Se på modellen uten nettleser: scene-summary først (ids, lag, referanse), så render.png med view=iso og view=front; skjul referanselaget med hide=SKP-import; sammenlign original og tolket med side_by_side.

## Fallgruver

- To overlappende tak er ikke et sammenføyd tak. Bruk T-/L-ring med eksplisitte edge_roles.
- Lukket ring: yttervegg (kropp innover). For innvendige mål, auto_align_closed=False og motsatt alignment.
- Hullet i veggen er ikke rektangel når åpningen har outer_loop_uv.
- Window default type er '1-floy' (to rammer): fastkarm må settes eksplisitt. trim_out (gerikt/belistning utenpå) er AV som standard: sett det bare når tegningen viser gerikt (trim_out=true + trim_out_w/trim_out_t, casing_source=lest|antatt); vet du ikke, la det stå av. Karm har karm_w/karm_d (frame_source=lest|antatt|ukjent). Eldre modeller beholder gammel standard til de bygges om med trim_v=2 / opening_std=2.
- Dørbladet kan være et eget element ved siden av karmen: glass i bladet avgjør dørtypen.
- Kledning vokser huset 4,2 cm hvis kjernen ikke gjøres tynnere.
- Kledning leses fra FLATENES materialer i originalen (scripts/skp_batch/cladding_areas.py), ikke fra laget: E2-vegger kan ligge på innervegg-laget og likevel være kledd; kjeller (0-Walls_Exterior) er mur uten kledning; etasjeskille-kanter med kledningsmateriale gir kledningsbånd.
- SketchUp roterer ofte kledningsteksturen 90°: vannrette spor i bildet kan være STÅENDE bord. Bruk uvw, ikke bildet.
- Ikke lag vegg/tak/kledning/dør med mesh (wall()/board()/extrude()): bruk BIM-verktøyene. Ett board per kledningsbord er forbudt.
- Skråvindu (outer_loop_uv): kledningen kuttes etter omrisset, og gerikten følger omrisset (ikke boksen).
- Rundt vindu er shape='circle', ikke et firkantvindu 1x1: «rundt vindu på 1 m» = width_m=1 (høyden blir lik). Bordene kuttes langs sirkelen (cut_pieces_by_outlines).
- `to_roof=True` beviser ingenting: mål veggtopp mot taket (mål < 5 mm). Vegg under to tak: laveste underside vinner.
- Hull i importflater ligger i `Face.holes` (ikke `hole_loops`); ikke svelg feil rundt geometri-uthenting.
- Ikke slett alle BIM-element i en fylt live-modell (kan krasje Desktop); bygg på fersk app og lagre .igz først.
- Alt er meter og grader; én operasjon = ett angre-steg.


## Regler

- Ikke lag mesh-hacks for vegg/tak/kledning: bruk BIM-verktøyene.
- `external`-verktøy (f.eks. `public_request`) sender til mennesker: spør brukeren først.
- Svar på brukerens språk; UI-et er norsk.
- Feil 401/403 på `agent/*`: be om delelenke eller innlogging; 403 «sandbox»: ruten er ikke åpen i sandkassen.
