One binary: the lint and the trainer are commands of portal
Test / test (pull_request) Successful in 1m7s

portal serve runs a site; portal lint is what iris was; portal plan,
build, report and the rest are what portal-trainer was. One source at
one version, so the three never disagree about what content means.
Both histories are merged in (subtree). The release attaches the bare
binary for a content repo's CI. The trainer's plans, intakes, engines
and reference prompt come along; its runs stay in the old repo.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GT37Z1Xtfd9pUuQtMTg6Yt
This commit is contained in:
Bendik Aagaard Lynghaug
2026-09-30 15:29:30 +02:00
co-authored by Claude Fable 5.1
parent d0d1cbf23d
commit 96b3746643
1733 changed files with 183 additions and 150652 deletions
+28
View File
@@ -0,0 +1,28 @@
# Held out from every model that writes words. Each is one real person
# arriving with one real thing, in their own register: a homeowner who
# has never read a regulation, a firm that files for a living, an
# inspector on a roof in the wind, a politician reading a bundle.
personas:
- { id: garage-owner, need: pre-application-meeting, text: "We want to put a double garage where the old shed is. Before I pay an architect I'd like to know whether you'll even allow it, because the neighbour says it's too close to the road." }
- { id: shop-to-flats, need: pre-application-meeting, text: "I own the old grocery on Torget and want to make four flats out of it. There are a lot of questions - parking, fire, the facade is listed. Can we sit down with someone?" }
- { id: firm-files-extension, need: permit-application, text: "We are the responsible applicant for an extension at Bjorkeveien 14. Drawings, site plan and the neighbour notices are all ready. We file maybe forty of these a year." }
- { id: owner-small-window, need: permit-application, text: "I want to put a dormer window in my roof. The man at the counter said I have to apply even though it's small." }
- { id: missing-drawings, need: permit-application, text: "You wrote that our section drawing is missing and the case is on hold. I've got it here now, where do I send it so the clock starts again?" }
- { id: too-close-to-boundary, need: exemption-request, text: "The garage ends up one and a half metres from the boundary and the plan says four. We are asking you to allow it anyway - the ground falls away steeply everywhere else on the plot." }
- { id: neighbour-view, need: objection, text: "I got a notice about the extension at number 14. It takes the afternoon sun off my entire terrace and I want that on the record before you decide anything." }
- { id: neighbour-parking, need: objection, text: "The flats they want to build in the old grocery have four parking places for four flats and everyone here already parks on the street. I object." }
- { id: road-authority, need: hearing-answer, text: "Regarding your case 2026/418: the access onto the county road is within the sight line and we cannot accept it as drawn. Our formal reply is attached." }
- { id: fire-service, need: hearing-answer, text: "We have looked at the conversion on Torget. We have no objection provided the stairwell is upgraded. Reference your case 2026/501." }
- { id: refused-applicant, need: appeal, text: "You refused our exemption on the ninth. We don't accept the reasoning - you've allowed the same thing twice in the same street. We're appealing." }
- { id: neighbour-appeals, need: appeal, text: "You approved the extension next door even though I objected. I'm appealing the decision. What do I need to send?" }
- { id: board-member, need: appeal, text: "I sit on the appeals board. I need the case, our own decision, and what the neighbours wrote, before Tuesday." }
- { id: inspector-on-roof, need: inspection-finding, text: "I'm up on the scaffold at Bjorkeveien. The fire wall isn't built to the drawing at all. I've got gloves on and it's blowing. I want this logged before I climb down." }
- { id: inspector-all-good, need: inspection-finding, text: "Been out at Torget. Everything is as approved. Nothing to report but I have to record that I was there." }
- { id: firm-wants-certificate, need: completion-request, text: "The work at Bjorkeveien 14 is finished and inspected. We're asking for the completion certificate so the owners can get their mortgage released." }
- { id: wants-to-move-in, need: completion-request, text: "The house is done apart from the outside steps, which we can't pour until spring. The family has sold their flat. Can we get a temporary permission to move in?" }
- { id: something-behind-fence, need: illegal-building-report, text: "There's a large structure going up behind the fence at Solbakken 7. Nobody has had a notice about it and it's been going on for two weeks." }
- { id: owner-explains, need: illegal-building-report, text: "I got your letter about the terrace. I genuinely did not know it needed an application, it's been there since we moved in. What happens now?" }
- { id: new-firm, need: firm-approval, text: "We are a three-person architecture firm that has just started. We want to be approved so we can file applications for our clients in your municipality." }
- { id: firm-insurance-lapsed, need: firm-approval, text: "You wrote that our liability insurance certificate has expired. We have renewed it, here it is." }
- { id: counter-phone-call, need: log-counter-enquiry, text: "A woman rang about the case behind her house. Wants to know where it stands. I'm at the counter and there's a queue - I need to write it down and send it to whoever has that case." }
- { id: where-is-my-case, need: case-status-enquiry, text: "I sent in my application five weeks ago and I've heard nothing. Is anyone looking at it? Is it in the six weeks with the neighbours or is it waiting on me?" }
+91
View File
@@ -0,0 +1,91 @@
# A building authority's intake: the hardest sector the trainer has
# been given. Cases that pause and resume, cases that belong to other
# cases, a decision two roles sign, a deadline nobody in the building
# controls, and an appeal that reopens something already finished.
# Written the way the department head would write it, in plain words.
business: Vestmark kommune - Building and Planning
contact: { name: Solveig Hauge, email: byggesak@vestmark.example }
language: en
what_we_do: >
We are the building authority for a municipality of twenty-one
thousand people. Anyone who wants to build, demolish, divide a
property or change what a building is used for has to come to us
first. We check the drawings against the zoning map and the building
regulations, we let the neighbours and the other authorities have
their say, and then we approve or refuse. We also decide exemptions
from the zoning rules, we inspect what is actually built, we sign off
finished work, and we deal with building that was never applied for.
who_comes_to_us: >
Homeowners who want a garage, an extension or a new window, and who
have never read a regulation in their life. Architects and
engineering firms who file on behalf of owners; they have to be
approved by us before they may file anything. Neighbours who got a
notice in the post and do not agree with what is planned next door.
The other authorities we are obliged to ask: the road authority, the
fire service, the heritage office, the county. People who ring to say
something is going up behind their fence without permission. And
anyone who wants to sit down with us before they spend eighty
thousand on drawings.
what_we_keep_track_of: >
Pre-application meetings: someone asks for one, we find a time, we
meet, and we write down what we told them so they can hold us to it.
Applications: they arrive, someone checks whether the papers are all
there, and if something is missing we write and ask for it, and the
twelve-week clock stops until they answer. Often we have to ask
twice. When it is complete we send it out to the neighbours and to
the agencies and wait six weeks. Then a case officer writes a
recommendation, and the head of section signs the decision: approved,
approved with conditions, or refused. People can withdraw at any
point, and quite a few do once they hear from the neighbours.
Exemptions: if what someone wants breaks the zoning rules they can
ask for an exemption. It rides along with the application but it is a
decision of its own, and we are not allowed to grant one before the
county has been asked.
Objections: a neighbour who got a notice writes to us within the
hearing period. Each objection belongs to an application. We register
it, the applicant gets to answer it, and the case officer has to
address every single one in the decision, by name.
Hearing answers: we ask an agency, they answer, or they do not, and
when the deadline has passed we go on without them.
Appeals: for three weeks after a decision anyone with an interest can
appeal it. We go through it ourselves first, and if we change our own
mind that is the end of it. If we do not, it goes to the appeals
board, who meet once a month and either uphold us or overturn us.
Inspections: we pick cases and go and look, on site. Either it is as
approved, or we write up what is wrong and set a date for it to be
put right, and then we go back.
Finishing: when the work is done the firm asks for a completion
certificate. If they want to move in before everything is done they
can ask for a temporary permission instead. We check what was
inspected and what is still outstanding before we sign anything.
Illegal building: someone reports it, we go and look, we write to the
owner and they have to explain themselves, and then they either apply
for it properly, take it down, or we fine them weekly until they do.
Approved firms: a firm sends us their registration, their insurance
and what they are qualified for, we check it, and then they are on
the list and may file applications.
who_is_involved: >
The front desk logs what comes in over the counter and on the phone,
and keeps the archive. Four case officers carry the cases. The head
of section signs every decision and every exemption; a case officer
may not sign their own. Two inspectors are out on site most of the
week and write up what they find on a phone in a cold wind. The
appeals board is seven elected politicians who meet on the third
Tuesday of the month and read what we send them. The agencies are
outside the building altogether and only ever answer hearings. The
approved firms file applications and answer objections on behalf of
their clients.
what_slows_us_down: >
The twelve-week clock, and the fact that stopping it and starting it
again is done by hand in a spreadsheet. Applications that arrive
missing half the drawings. Objections that come in on paper and get
stapled to the wrong case. Neighbours ringing to ask what is
happening with the case behind their house, which we are obliged to
tell them and which takes ten minutes every time. Agencies that never
answer at all. And nobody outside this building can see a case
without asking us for it.
+44
View File
@@ -0,0 +1,44 @@
# An intake as the owner of a small building contractor would fill it
# in: plain words, no portal vocabulary. These are the fields the
# onboarding site asks for.
business: Nordvik Bygg
contact: { name: Ingrid Nordvik, email: ingrid@nordvikbygg.example }
language: en
what_we_do: >
We are twelve people. We survey old buildings, draw up rehabilitation
plans, handle the permit application, and do the building work with
our own carpenters plus subcontractors for electrical, plumbing and
scaffolding.
who_comes_to_us: >
Housing boards and private owners who have a problem with a building
and want someone to look at it. Owners who already know what they
want built and need drawings, a permit and a price. Trade firms who
want to be on our list of subcontractors. Carpenters and apprentices
asking if we are hiring.
what_we_keep_track_of: >
Enquiries: they come in, we go and look at the building, we send a
quote, and then we either win it or lose it. Sometimes it is simply
not for us and we say so straight away.
Subcontractors: they apply, we check their company registration,
trade approval and insurance. Often papers are missing and we have to
ask again. Then they are approved or turned down.
Job applications: we read them, invite some to an interview, and hire
or decline.
Things that go wrong on site: a hazard, a near miss, wrong materials
delivered. Someone reports it, the safety officer decides what is
done about it, and closes it when it is fixed.
who_is_involved: >
Two project managers handle enquiries, subcontractors and hiring.
One safety officer handles everything reported from site.
The crew, ours and the subcontractors' people, are the ones on site
who report things. They are on their phones, with gloves on, and
will not fill in a long form.
what_slows_us_down: >
Enquiries arrive by phone, email and text and get lost. We never know
which subcontractors have valid papers. Site problems get mentioned
at lunch and forgotten.
+38
View File
@@ -0,0 +1,38 @@
# Slik lederen i en fotballgruppe ville fylt det ut.
business: Lia IL Fotball
contact: { name: Kari Lien, email: kari@liail.example }
language: no
what_we_do: >
Fotballgruppa i et idrettslag på bygda. Rundt hundre og tjue unger
fra seks til sekstenår, fordelt på lag etter årskull. Alt drives av
foreldre på fritida: trenere, lagledere, en kasserer og et styre.
who_comes_to_us: >
Foreldre som vil ha ungen med på et lag. Foreldre som sliter med
treningsavgiften og vil dele den opp eller slippe. Folk som vil
hjelpe til, som trener, lagleder, sjåfør eller på dugnad. Bedrifter
i bygda som vil sponse.
what_we_keep_track_of: >
Innmeldinger: en forelder melder inn, treneren på årskullet
godkjenner at det er plass, kassereren ser at avgiften er betalt.
Noen trekker seg underveis.
Avgiftssaker: noen ber om å dele opp eller slippe avgiften; styret
vurderer og sier ja eller nei.
Frivillige: noen tilbyr seg, styret tar kontakt og plasserer dem der
det trengs, eller takker nei.
Sponsorer: en bedrift melder interesse, vi tar en prat, og det blir
en avtale eller ikke.
Ting på banen: lys som ikke virker, mål som er ødelagt, drakter som
mangler. Trenerne melder fra, styret tar tak i det og ordner det.
who_is_involved: >
Trenerne godkjenner innmeldinger på sitt årskull og melder fra om
banen. Kassereren følger opp betaling. Styret tar frivillige,
sponsorer, avgiftssaker og alt som gjelder anlegget.
what_slows_us_down: >
Alt går i en gruppechat og et regneark. Trenerne vet ikke hvem som
har betalt, kassereren vet ikke hvem som er godkjent, og en som
tilbød seg å kjøre i høst fikk aldri svar.
+38
View File
@@ -0,0 +1,38 @@
# An intake as the owner of a machine hire yard would fill it in.
business: Fjellstad Hire
contact: { name: Ola Fjellstad, email: ola@fjellstadhire.example }
language: en
what_we_do: >
We hire out machines: mini diggers, lifts, compactors, generators,
that kind of thing. A counter with two people, a yard with three who
deliver, collect and fix, and me in the office doing accounts and
the business customers.
who_comes_to_us: >
Private people who need a machine for a weekend and have often never
driven one. Building and landscaping firms who need something on a
site from a date for a period. Anyone whose hired machine has
stopped working while they have it. Firms who hire often and want
an account so they can send anyone to collect and get one invoice a
month.
what_we_keep_track_of: >
Hires: someone asks, the counter reserves it, the yard hands it out
or delivers it, and the yard takes it back. Some are cancelled
before they go out.
Breakdowns: a machine stops during a hire; the yard takes it on and
either fixes it on site or swaps it.
Account applications: a firm applies, I check the company and its
credit, and it is approved or turned down.
Damage on return: the yard finds damage when a machine comes back; I
either invoice the customer or write it off.
who_is_involved: >
The counter handles hires. The yard handles breakdowns and the
handing out and taking back. The office does accounts and damage.
what_slows_us_down: >
The yard finds out about breakdowns from whoever picks up the phone.
Damage found on return is written on a whiteboard and half of it is
never invoiced.
+42
View File
@@ -0,0 +1,42 @@
# An intake as the manager of a physiotherapy clinic would fill it in.
business: Bakken Fysioterapi
contact: { name: Marit Bakken, email: marit@bakkenfysio.example }
language: en
what_we_do: >
Six physiotherapists and a receptionist. People come to us with
pain, injuries and after operations; we assess them and treat them
over a course of sessions. Some come on their own, some are sent by
a GP or a hospital, and some have insurance that pays if the insurer
approves the course first.
who_comes_to_us: >
People with something that hurts who want to see the right
therapist. Patients who already have a time and need to move or
drop it. GPs and hospital wards sending us someone, who want to
hear how it went. Insurers, through us, when a course has to be
approved before it starts.
what_we_keep_track_of: >
Requests for a first appointment: they come in, we offer a time with
a therapist who suits, and it is either booked or they go elsewhere.
Cancellations: someone can't come; we either find them a new time or
give the slot to someone waiting.
Referrals: a doctor sends someone, we accept it, book them in, treat
them, and send the doctor a report at the end. Sometimes we send it
back because it isn't something we treat.
Insurance approvals: for some patients we have to ask the insurer
before we start; we send the request and it comes back approved or
refused.
No-shows: someone doesn't turn up and doesn't call. The receptionist
rings them and either rebooks or, after a couple of times, closes it.
who_is_involved: >
The receptionist handles every request, cancellation, referral and
approval. The therapists treat and write the report back to the
doctor, and they are the ones who notice a no-show.
what_slows_us_down: >
Referrals, cancellations and insurance approvals all go through one
inbox that only the receptionist understands. Therapists tell her
about no-shows in the corridor and they get forgotten.
+48
View File
@@ -0,0 +1,48 @@
# En fiktiv norsk rehabiliteringsentreprenør, inspirert av hva
# Klingenberg Bygg driver med: tilstandsrapporter, prosjektering,
# byggesøknader og utførelse på eldre murgårder. Skrevet slik eieren
# ville sagt det, uten portal-ord.
business: Åsrud Bygg og Rehabilitering AS
contact: { name: Marte Åsrud, email: marte@asrudbygg.example }
language: "no"
what_we_do: >
Vi er fjorten ansatte og jobber mest med eldre murgårder og
trehus. Vi lager tilstandsrapporter, prosjekterer rehabilitering,
sender byggesøknad med ansvarsrett, og utfører arbeidet med egne
tømrere og murere. Elektriker, rørlegger, stillas og blikkenslager
leier vi inn som underentreprenører.
who_comes_to_us: >
Styreledere i borettslag og sameier, og private huseiere, som har
et problem med bygget og vil at noen skal se på det. Eiere som
allerede vet hva de vil bygge eller endre, og trenger tegninger,
søknad til kommunen og en pris. Håndverksfirmaer som vil stå på
lista vår over underentreprenører. Tømrere, murere og lærlinger som
lurer på om vi trenger folk.
what_we_keep_track_of: >
Henvendelser: de kommer inn, vi avtaler og drar på befaring, vi
sender tilbud, og så vinner vi jobben eller taper den. Noen ganger
er det rett og slett ikke noe for oss, og da sier vi det med en gang.
Underentreprenører: de melder seg, vi sjekker organisasjonsnummer,
sentral godkjenning, forsikring og at folka har HMS-kort. Ofte
mangler det papirer og vi må etterlyse dem. Så blir de godkjent
eller avslått.
Jobbsøknader: vi leser dem, kaller inn noen til intervju, og
ansetter eller takker nei.
Avvik og uønskede hendelser på byggeplass: løse rekkverk,
nestenulykker, feil materialer levert. Noen melder fra, HMS-ansvarlig
bestemmer tiltak, og lukker saken når det er utbedret.
who_is_involved: >
To prosjektledere tar seg av henvendelser, underentreprenører og
ansettelser. En HMS-ansvarlig tar alt som meldes fra byggeplass.
Mannskapet, både våre egne og underentreprenørenes folk, er de som
står på plassen og melder fra. De sitter med telefonen, har hansker
på, og fyller ikke ut lange skjemaer.
what_slows_us_down: >
Henvendelser kommer på telefon, e-post og SMS og blir borte. Vi vet
aldri sikkert hvilke underentreprenører som har papirene i orden.
Avvik blir nevnt i lunsjen og glemt.
+62
View File
@@ -0,0 +1,62 @@
# Tomter Vel, slik en i styret ville fylt det ut. Det som står om
# velet er hentet fra tomtervel.no (komiteer, kontingent, medlemstall,
# arrangementer); det som står om deling av utstyr er et forslag til
# en ny tjeneste.
business: Tomter Vel
contact: { name: Styret i Tomter Vel, email: post@tomtervel.no }
language: no
what_we_do: >
Velforeningen for Tomter, stiftet i 1947. Vi er et styre på sju og
sju komiteer som alle drives av folk på fritida: arrangementer
(17. mai-frokost, juletregranstenning, skøytedag), elvestien langs
Hobølelva, to lekeplasser vi holder i stand og får kontrollert hvert
år, høringssvar til kommunen, miljøgata i sentrum, pendlerforhold
mot Ruter, og trafikkforhold. 157 husstander betaler kontingent på
250 kroner i året.
who_comes_to_us: >
Husstander som vil bli medlem, eller som har flyttet eller byttet
e-post og vil at vi skal ha det riktig. Folk som har sett noe i
nabolaget som ikke er som det skal: en farlig sving, en huske som
henger i én kjetting, en råtten planke på stien. Beboere som vil
si sin mening om en sak kommunen har på høring. Folk som vil hjelpe
til på et arrangement eller en dugnad, eller sitte i en komité.
Og naboer som har en tilhenger, en stige eller en hekksaks som står
ubrukt, og naboer som trenger å låne en. Eldre og nyopererte som
trenger en hånd med snømåking, handling eller en skyss, og naboer
som gjerne stiller opp hvis noen spør.
what_we_keep_track_of: >
Medlemskap: en husstand melder seg inn, kassereren ser at
kontingenten er betalt, og noen melder seg ut når de flytter.
Meldinger om trafikk: noen melder fra, trafikkomiteen tar det opp
med kommunen eller veieier, og det blir ordnet eller avvist.
Feil på lekeplass og sti: noen melder fra, komiteen tar tak i det
og utbedrer det.
Høringsinnspill: en beboer sender inn, styret tar det med i svaret
eller lar være.
Frivillige: noen tilbyr seg, arrangementskomiteen tar kontakt og
setter dem opp, eller takker nei.
Komitésøknader: noen vil være med, styret plasserer dem eller sier
nei.
Utlegg: en i en komité har lagt ut for noe, kassereren godkjenner og
betaler ut, eller avviser.
Nabohjelp: noen ber om en hånd, nabohjelpsgruppa finner en som kan,
og den som fikk hjelp sier fra når det er ordnet. Naboer som vil
hjelpe melder seg, og kan trekke seg igjen.
Deling av utstyr: en nabo melder at de har noe å låne ut, eller
trenger å låne noe; styret legger det ut på oppslagstavla og tar
det ned når det er gjort.
who_is_involved: >
Kassereren har medlemskap og utlegg. Trafikkomiteen har
trafikkmeldinger, lekeplasskomiteen har feil på anlegg,
arrangementskomiteen har frivillige. Styret har høringsinnspill,
komitésøknader og oppslagstavla. Nabohjelpsgruppa kobler dem som
trenger hjelp med dem som kan. Komiteene leverer utlegg.
what_slows_us_down: >
Medlemslista er en bankutskrift og et regneark. Ting som meldes på
Facebook eller i butikken blir husket av den som hørte det. Folk
som tilbyr seg å hjelpe får svar sent eller aldri.