En samarbeidsvennlig sandkasse for hackathon og utforskning av moderne innbyggerdialog i kommunal sektor.
Målet er å gjøre det enkelt for interne og eksterne utviklingsteam å prototype kommunale tjenester med syntetiske data, tydelige API-er, sporbarhet og mockede integrasjoner. Hvilken form tjenesten får - dialog, skjema, oversikt, varsling eller noe annet - er teamets valg.
Alle seksjonene
- Før du begynner
- Hva sandkassen er
- Designprinsipp for hackathon
- Status
- Hva som logges
- Hvordan starte den
- Hvordan stoppe den
- Oversikt over tjenester og porter
- Demo-brukere
- Demo-flyt
- Eksempel på API-kall
- Sjekker du kan kjøre
- Hvor syntetiske data ligger
- Hvordan legge til nye prosesser
- Hvordan legge til nye syntetiske datasett
- Samarbeid
- Kjente begrensninger
- Viktige filer
Dette må du ha installert på maskinen din:
| Hva | Trengs til | Hent den |
|---|---|---|
| Docker, installert og startet | å kjøre sandkassen. Det eneste kravet for ./start.sh --mock |
docs.docker.com |
| git | å hente repoet | git-scm.com |
| Node 22.18 eller nyere | å hente et token (node scripts/token.ts), og å kjøre testskriptene. Nesten alle API-kall krever token, så i praksis trenger du Node så snart du gjør noe selv |
nodejs.org |
| pnpm | å kjøre pnpm <skript> i det hele tatt. pnpm install i tillegg bare til pnpm lint, live reload på Windows, og Bedrock-provideren - verken sandkassen eller de andre testskriptene trenger et pnpm install |
pnpm.io |
| Homebrew (bare macOS) | at skriptet kan installere Ollama for deg. Ikke nødvendig med --mock |
brew.sh |
Har du allerede Node, er corepack enable som regel nok til å få pnpm - package.json
sier hvilken versjon som skal brukes. Følger ikke Corepack med din Node-versjon, tar
lenken over de andre veiene.
Sjekk at du har det:
docker --version && node --version && git --versionPortene 3000, 3001 og 8080–8088 må være ledige. Med modell trengs også
11434 til Ollama. Er en av dem
opptatt, står det i docs/feilsoking.md hvordan du finner ut hvilken.
Sett av tid første gang: 4-7 minutter med ./start.sh --mock, 12–25 minutter
med språkmodell, og vesentlig mer på delt konferansenett. Språkmodellen er fra 400 MB
til 9 GB avhengig av hvor mye minne maskinen har. Senere oppstarter tar sekunder.
På Windows: kjør fra Git Bash (følger med Git for Windows) eller WSL - se «På Windows» lenger ned.
Note
Deltaker på hackathon? Denne filen er ikke inngangen din. Tre sider, i rekkefølge:
docs/oppdraget.md- hva dere skal lage, og hva som er frittdocs/deltakerstart.md- én kommando, URL-ene, hvilken demobruker som hører til hvilken case, første eget API-kall, og feilsøkingdocs/bygg-selv.md- egen frontend på egen port, egne tjenester, og hva som er frosset
Og før du begynner: CODE_OF_CONDUCT.md gjelder alle, i lokalet og i repoet.
Kom tilbake hit når du vil ha hele bildet: alle flagg, porter og kjente begrensninger.
docs/README.md er kartet over all dokumentasjonen.
Sandkassen er en lokal utviklingsarena for å utforske hvordan innbyggere kan møte kommunen. Demoene her er dialogbaserte fordi en samtale var raskeste vei til å ta i bruk alle API-ene samtidig - ikke fordi dialog er svaret. Se docs/oppdraget.md.
Sju demo-case er publisert; Redusert foreldrebetaling i barnehage er
flaggskipet og det eneste som er dekket av en informasjonsmodell. Casene og hvilken
testbruker som hører til hver, står i docs/deltakerstart.md.
Arkitekturen er lagt opp for samarbeid mellom flere team, med tydelige grenser mellom frontend, backend, simulatorer, policyer og datasett.
Høy autonomi, og nok støtte til at teamene faktisk rekker å levere: felles API-er og enkle integrasjonsflater, uten å låse noen til én bestemt frontend, ett bestemt prosessformat eller ett bestemt verktøy. Referanseimplementasjonene i repoet, som process-builder og demo-gui, er hjelpemidler og eksempler - ikke tvungne måter å bygge løsningene på.
Elleve kjørende tjenester, én valgfri avhengighet i kjøretid, sju komplette demo-case. På plass:
- samtykkeflyt med sperre på inntektsdata uten samtykke, håndhevet ett sted
- revisjonslogg over all datatilgang
- deterministisk vilkårsvurdering mot satser (
SJEKK) - utenfor modellen, med vilje - syntetiske data forankret i Folkeregisterets informasjonsmodell og KS Fiks beregnings-API
- KI-spor: hvert modellkall lagres med prompt og svar, lesbart på
GET /trace - evals av KI-laget:
pnpm test:eval - OpenAPI for alle ni API-tjenestene, komplett og holdt i takt med koden av
pnpm test:openapi: hver rute dokumentert, medsecurity:per rute
Loggene sier hva sandkassen gjorde, ikke hvem som kjørte den. Ingen brukerkonto,
ingen tilgangslogg, ingen bruksmålinger, og ingenting sendes til KS Digital. To ting
lagres med vilje, begge i state/ på din egen maskin:
- Revisjonsloggen (
state/revisjonslogg.json) - én hendelse hver gang sandkassen leser data, endrer et samtykke, tar et prosessteg eller kaller modellen. - KI-sporet (
state/ai-trace.jsonl) - full prompt og fullt svar per modellkall.
Kjører du mot en KI-provider som ikke er lokal, går hele prompten ut av maskinen. Og
./start.sh --reset legger en kopi av state/ i _backup/ før den sletter.
docs/hva-logges.md har hele bildet.
Kravene til maskinen står under «Før du begynner».
Vil du bare se noe kjøre? Start her:
./start.sh --mockFire til sju minutter. Alt fungerer bortsett fra at KI-svarene er maltekst i stedet for modellgenerert - flyten, samtykkesperren, revisjonsloggen og alle API-ene er de samme. Dette er den riktige veien inn første gang, og den eneste som ikke krever nedlasting av flere gigabyte.
Når du vil ha den ekte modellen:
./start.shSkriptet finner ut hvilken plattform du er på, velger modell ut fra minnet i maskinen, starter tjenestene, og verifiserer at modellen faktisk svarer før den melder klar.
Tidsbruken første gang står under «Før du begynner»; en stor modell
legger seg i overkant av det. Skriptet spør før det laster ned. På macOS spør det i tillegg før det installerer Ollama, siden den kjører nativt der; på Linux og WSL kjører Ollama i container og installeres ikke. ./start.sh -y hopper over alle spørsmål.
Stopp med ./start.sh -d.
Kjør skriptet fra Git Bash eller WSL. Da får du plattformdeteksjon, automatisk modellvalg basert på minnet i maskinen, og verifisering av at modellen faktisk svarer.
start.bat og stop.bat finnes i repoet, men de er et nødløsningsalternativ, ikke en
ekvivalent. start.bat sjekker portene, lager .env hvis den mangler, og venter til alle
elleve tjenestene svarer på /helse. Den tar --reset, --reload, -d, --down og
--help, men ingen modellflagg. Den kjører alltid uten
språkmodell - den laster verken ned eller velger modell, så alt annet enn maltekst
ville vært en tom lovnad. Vil du ha en ekte modell, bruk Git Bash eller WSL og
./start.sh. Foretrekk uansett den veien hvis du har valget.
Du skal normalt ikke trenge noen av disse.
| Flagg | |
|---|---|
-m, --model MODEL |
Bruk en bestemt modell i stedet for den automatisk valgte |
-y, --yes |
Ikke spør før installasjon eller nedlasting |
--mock |
Kjør uten språkmodell. Raskeste vei inn, og redningen når nedlasting ikke er mulig |
--reload |
Gjenskap Node-containerne, også når konfigurasjonen er uendret. Tar inn kode og Compose-endringer uten å slette state/ |
--reset |
Stopp Node-tjenestene, kopier state/ til _backup/, tøm den, og gjenskap containerne fra kildedataene |
-d, --down |
Stopp alt |
-h, --help |
Hjelp |
Warning
--reset er ikke bare en reset. Den tømmer state/ og starter deretter alt på
vanlig måte - inkludert modellnedlasting. Kjørte du --mock, skriv
./start.sh --mock --reset, ellers begynner den å laste ned flere gigabyte.
Ta også med --mock ved omlasting: ./start.sh --mock --reload. --reset,
--reload og --down er separate operasjoner og kan ikke kombineres.
Et lagret valg i KI-admin overstyrer fortsatt miljøvariabler. Dersom det hindrer
mock-modus, stopper skriptet med en forklaring i stedet for å melde at alt er klart.
Plattform oppdages automatisk:
| Plattform | Hvordan Ollama kjøres |
|---|---|
| macOS | Nativt på verten. Docker Desktop når ikke Metal på Apple Silicon, så Ollama i container ville blitt ren CPU-inferens. |
| Linux med NVIDIA-GPU | I container, med docker-compose.gpu.yml |
| Linux og WSL ellers | I container, uten GPU |
Modell velges ut fra minnet på maskinen: 32 GB RAM eller mer gir qwen2.5:14b, 12 GB eller mer gir qwen2.5:7b, under det qwen2.5:0.5b.
Har du et NVIDIA-kort, leses også VRAM, og det mest restriktive av de to avgjør - en modell som får plass i RAM men ikke i VRAM blir splittet mot CPU og går tregt. Apple Silicon har unified memory, så der er RAM riktig tall.
Har du satt OLLAMA_MODEL i miljøet eller i .env, brukes den i stedet. .env opprettes fra .env.example hvis den mangler.
Til slutt bekreftes det at modellen svarer. Sier skriptet ⚠️ The model is NOT connected, virker sandkassen fortsatt - men AI-svarene er maler. Vanligste årsak er at Ollama har stoppet.
data/ er kildedata og skrives aldri til. Alt tjenestene endrer under kjøring havner i state/, som er gitignorert. En demokjøring skitner derfor ikke til arbeidstreet - kjører du en flyt og deretter git status, skal den være ren.
./start.sh --reset stopper først alle Node-tjenestene, tar en sikkerhetskopi uten
signeringsnøkkelen og sletter så state/. Feiler stopp eller kopiering, slettes
ingenting. Containerne gjenskapes etterpå, slik at lagret KI-valg, tokenbuffer og
agentøkter i minnet også nullstilles. Ollama på macOS og nedlastede modeller beholdes.
Stopp eventuelle tjenester du har startet utenfor Compose selv før du nullstiller.
Se docs/syntetiske-data.md, også for hvordan du deler en prosess du har laget i byggeren.
Kontroller at modellen er koblet på:
curl -s http://localhost:8082/helse"modellNaaBar": true betyr at provideren svarer og modellen er lastet ned. Er den false, følger et feil-felt som sier hvorfor. Merk at status alltid er 200 - tjenesten lever selv om modellen ikke gjør det, så det er modellNaaBar du skal lese.
Er modellen nede, faller ai-gateway tilbake til maltekst og setter et advarsel-felt. /chat og /agent viser en gul stripe når det skjer, og ./start.sh advarer ved oppstart - men svarene i seg selv ser normale ut, så det er verdt å vite hvor du sjekker.
Kontroller at alle tjenestene kjører:
docker compose psAlle skal stå som healthy.
Alt annet - 401 på alt, «fetch failed» på matrikkel-oppslag, maltekst du ikke ba
om, port opptatt, en container som ikke blir healthy, treg modellnedlasting og
hvordan du nullstiller - står i docs/feilsoking.md: ett symptom per avsnitt, med
årsak og løsning.
http://localhost:8082/trace
Ett kall per linje, nyeste øverst, med full prompt og fullt svar før heuristikk og validering har vært innom - pluss varighet, modell og om det feilet. Samme data som JSON på GET /trace.json, med ?sporingsId=, ?task= og ?limit=.
Sporet ligger i state/ai-trace.jsonl og nullstilles av ./start.sh --reset.
Logger: docker compose logs -f ai-gateway.
Kommandoene, per plattform
./start.sh gjør dette for deg. Les skriptet hvis du vil se detaljene - det er kommentert.
macOS, med Ollama nativt på verten:
brew services start ollama # ikke "ollama serve" - den dør når terminalen lukkes
ollama pull qwen2.5:14b
cp .env.example .env # OLLAMA_BASE_URL=http://host.docker.internal:11434
docker compose up -d --no-deps sandbox-backend fiks-simulator ai-gateway \
tools-api process-agent matrikkel-mock digdir-mock pasientjournal-mock \
politiattest-mock demo-gui process-builderHele listen må med - særlig digdir-mock og matrikkel-mock, som svikter stille
når de mangler. Hvordan de feiler står i punktlisten under
tjenesteoversikten.
--no-deps er nødvendig for å hoppe over depends_on: ollama i ai-gateway, som
ellers drar opp container-Ollama - men det er også grunnen til at listen må være
komplett: --no-deps slår av depends_on for alle tjenestene, digdir-mock
inkludert.
Linux og WSL, alt i Docker:
./start.sh --mock # uten modell
# eller, med modellvalg, nedlasting og verifisering:
./start.sh -yBruk skriptet også her. En ren kopi av .env.example peker på macOS-verten, ikke
på Ollama-containeren, og docker compose up -d laster ikke ned noen modell.
Skriptet lager riktig .env når den mangler. Har du allerede kopiert eksempelfilen
på Linux/WSL, rett OLLAMA_BASE_URL til http://ollama:11434 før du starter;
en eksisterende .env blir ikke overskrevet.
Med NVIDIA-GPU velger skriptet GPU-overlegget når Docker har NVIDIA-støtte.
Verifiser GPU-tilgangen med docker run --rm --gpus all nvidia/cuda:12.4.1-base-ubuntu22.04 nvidia-smi - feiler den, mangler NVIDIA Container Toolkit.
Forhåndslast alle anbefalte modeller, for eksempel før en workshop med dårlig nett:
docker compose --profile models up ollama-pull-allModellene er qwen2.5:0.5b (raskest), qwen2.5:7b (balansert), qwen2.5:14b (best av Qwen-variantene), llama3.1:8b og mistral-nemo.
./start.sh -dEller direkte med docker compose down. På macOS kjører Ollama utenfor Docker og stoppes med brew services stop ollama hvis du vil frigjøre minnet.
./start.sh starter alle sammen, så du trenger ikke velge.
Tjenestene, portene og rollene deres ligger i apps/shared/tjenester.json, og
http://localhost:3001 viser dem med levende helsestatus og en lenke rett inn i
API-utforskeren for hver.
To ting tabellen ikke sier, og som er verdt å vite før noe feiler:
digdir-mock(8086) utsteder alle tokens. Er den nede, svarer hvert autentisert kall 401 mensdocker compose psser helt frisk ut, fordi tokenfeilen svelges i klienten. Den skal alltid med når du starter tjenester manuelt.matrikkel-mock(8085) er kjerne, selv om den ser valgfri ut. Uten den feiler allematrikkel_*-verktøy og helefartsdempende-tiltak-casen med «fetch failed», mens alt annet ser normalt ut.
Hver API-tjeneste serverer sin egen spesifikasjon på /openapi.yaml, samme spesifikasjon
lest som JSON på /openapi-ruter.json, og en lesbar side på /docs. Den midterste er det
API-utforskeren rendrer, og pnpm test:openapi holder alle tre i takt med koden.
Det finnes ikke én demo-bruker som passer alle casene - velg bruker etter case i
tabellen i docs/deltakerstart.md §3, som er pinnet i data/deltakercaser.json.
Til flaggskipcaset Redusert foreldrebetaling (barnehage) passer person-001
Maja Solberg; i flere av de andre casene gir hun korrekt avslag, så der velger
du bruker fra tabellen.
Data finnes i data/personer.json. docs/testpersoner.md er den genererte
oversikten over hele befolkningen - 394 personer med alder, status, husstand og
en kolonne som sier om personen kan logge inn, bare være part, eller ingen av
delene. docs/syntetiske-data.md forklarer datagrunnlaget.
Flaggskipcaset Redusert foreldrebetaling (barnehage) kjører hele kjeden i én økt: husstanden hentes og vises, samtykke innhentes før inntektsdata leses, vilkårene vurderes deterministisk i backend, KI-laget oppsummerer i klarspråk, innbyggeren bekrefter, søknaden sendes inn og oppretter en oppgave i Fiks-simulatoren - og revisjonsloggen viser hver datatilgang underveis.
Demo-GUI-en er prosessdrevet: stegene leses fra valgt prosessdefinisjon, og flyten
kjøres via prosessøkt-API-et i backend. Alle sju casene, og hvilken testbruker som
hører til hver, står i tabellen i docs/deltakerstart.md §3, pinnet i
data/deltakercaser.json.
Kall krever token. AUTH_ENFORCE er på som standard, og alt som ikke er uttrykkelig
åpent svarer 401 uten Authorization-header.
export TOKEN=$(node scripts/token.ts --innbygger person-001)
curl -s -H "Authorization: Bearer $TOKEN" \
http://localhost:8080/api/personer/person-001/husstandEtt token er én person: person-001s token åpner ikke person-031s data - det gir
403. pnpm token treffer pnpms egen innebygde kommando, så kall skriptet direkte.
Åpne ruter trenger ingenting: /helse, /docs, /openapi.yaml, /api/prosesser,
/api/katalog/*, /api/regler/satser. GET /api/katalog/ressurser oppgir tilgang og
kreverSamtykke per rute, så du kan lese ut av API-et selv hva som krever hva.
Videre:
- http://localhost:3001/utforsker - hver rute med skjema, riktig token valgt
automatisk, og en
curlsom virker når den limes inn. Raskeste vei til et enkeltkall. examples/curl/README.md- flytene: hele barnehagesøknaden i rekkefølge, og de tre ulike svarene samme URL gir avhengig av token og samtykke.pnpm test:kokebokkjører hvert kall i filen, så et eksempel som ikke virker er en reell feil.
Disse krever ingen kjørende tjenester og ingen modell:
pnpm lint # tsc --noEmit
pnpm test # referanseintegritet og scenariodekning i datasettene
pnpm test:kontrakt # starter egen backend + fiks og skriver en deterministisk dumppnpm test:kontrakt normaliserer id-er og tidsstempler, så to kjøringer av samme
kode gir bit-identisk resultat. Bruk den som regresjonsport rundt refaktoreringer:
pnpm test:kontrakt --ut state/foer.json
# ...endre noe...
pnpm test:kontrakt --ut state/etter.json
diff state/foer.json state/etter.jsonEndrer du en prompt, kjør evalene. pnpm test:eval scorer KI-laget mot
datasettene i evals/, med terskel per datasett og exit≠0 under. Den krever en
kjørende modell og nekter å score maltekst. Ta en baseline før du endrer, og
sammenlign etterpå - se evals/README.md.
Disse krever at stacken kjører: pnpm test:agent, test:agent:nl og
test:bergen-matrikkel. test:agent:dialog starter egne tjenester med KI-mock
og kjører de to agenttestene helt til lagret søknad. test:matrikkel-mock,
test:tools-matrikkel og test:agent:matrikkel starter også sine egne tjenester.
Bulk-smoketesten mot matrikkel-mocken sampler 40 gater og 25 adresser fra seed-datasettet:
pnpm test:bergen-matrikkelDen krever nett: adresser som bommer i seed-filen slår over på live Geonorge-oppslag, og uten nett svarer matrikkel-mock 500.
Syntetiske data ligger under data/:
data/personer.json- 394 personerdata/husstander.json- 200 husstanderdata/tenor/- rå uttrekk fra Tenor, kilden importen bygger pådata/forventet-utfall.json- hva hver husstand er ment å demonstrere, pinnet forpnpm testdata/inntekter.jsondata/barnehageplasser.jsondata/sfoplasser.jsondata/satser.jsondata/fritidsaktiviteter.jsonogdata/fritidsdeltakelse.json- grunnlaget for fritidskortdata/tjenestetilbud.json- kommunale tilbud med målgruppe og kapasitet, grunnlaget for støttekontaktdata/legeerklaeringer.json- legeerklæringer til TT-kort, lest avpasientjournal-mockdata/politiattester.json- politiattester til vandelskontroll, lest avpolitiattest-mockdata/matrikkel.json- 388 gater og 18 349 eiendommer i 97 kommuner, lest avmatrikkel-mockdata/eierforhold.json- tinglyst eierskap per matrikkelenhet, slått sammen avmatrikkel-mockved innlastingdata/matrikkel.seed.json- liten firegaters fixture for mockens egne testerdata/prosessdefinisjoner.jsondata/informasjonsmodeller.json
matrikkel-mock er eneste leser av matrikkeldataene. sandbox-backend kaller den over
HTTP, så det finnes bare én matrikkel i sandkassen - den som også snakker SOAP.
Søknader, samtykker, oppgaver, meldinger, prosessøkter og revisjonslogg har ingen
fil i data/. De oppstår først under kjøring og finnes bare i state/, som er
gitignorert. Se docs/syntetiske-data.md.
- Legg ny prosessdefinisjon i
data/prosessdefinisjoner.json - Eller opprett den direkte i prosessbyggeren på
http://localhost:3000 - Oppdater eksempel eller dokumentasjon i
examples/demoprosesser/ - Dokumenter nødvendig API-bruk i
docs/prosessmodell.md - Hvis prosessen krever nye regler, oppdater relevante filer i
policies/
- Legg til ny JSON-fil i
data/ - Beskriv datasettet i
docs/syntetiske-data.md - Oppdater katalog- eller API-dokumentasjon i
docs/api-oversikt.md - Marker alle poster med
syntetisk: trueder det er relevant - Lagre filer som UTF-8 (Unicode) slik at norske tegn bevares korrekt
Dette repoet er lagt opp for flere team. Se:
CODE_OF_CONDUCT.mdCONTRIBUTING.mdopenapi/README.mddocs/architecture.mddocs/api-oversikt.mddocs/designsystem.md
- Tjenestene er bygget som en enkel MVP uten byggesteg, ikke som produksjonsklar
applikasjon. Én avhengighet finnes i kjøretid - AWS-SDK-en
ai-gatewaybruker til Bedrock - og den lastes først når den provideren brukes, sådocker compose upklarer seg utenpnpm install - CI kjører sjekkene som verken trenger modell eller kjørende stack. Listen står i
.github/workflows/ci.yml, med en kommentar per steg om hva det fanger - den er kilden, ogpnpm test:docsfeiler hvis en doc gjengir den feil. Evalene og stack-testene er bevisst utenfor: de krever en modell eller en oppe stack - Ingen persistensstrategi utover flate JSON-filer.
process-agentholder sesjoner i minnet og mister dem ved restart - Datasett og policyer er laget for demo og hackathon, ikke produksjon
- Ingen ekte integrasjoner mot Altinn eller Fiks. ID-porten og Maskinporten er
mocket i
digdir-mock, og håndhevingen er ekte:AUTH_ENFORCEer på, tokener verifiseres mot utstederens nøkler, og pid-bindingen holder. Det som er forenklet er klientassertionen - den valideres på form, ikke signatur. Seapps/digdir-mock/README.md
docs/README.md- kartet over all dokumentasjonendocs/deltakerstart.md- start her hvis du er deltakerdocs/ordliste.md- forvaltningstermene forklart slik de brukes i sandkassenapps/shared/tjenester.json- tjenestene, portene, rollene. Sannhetskildendata/- de syntetiske datasettene.docs/syntetiske-data.mdforklarer demopenapi/- én spesifikasjon per API-tjeneste, holdt i takt avpnpm test:openapipolicies/- datapolicy, KI-policy, tilgangspolicydocker-compose.yml,package.json,tsconfig.json
