Fire prompts, fjorten agenter og én aften: sådan genopbyggede AI-agenter umage.ai på Optimizely CMS 13 med Visual Builder, med en tom mappe som udgangspunkt. Hvad det kostede, hvilke værktøjer agenterne faktisk brugte, hvilke faldgruber i CMS 13.5.1 de løb ind i, og hvilke forbehold der skal med, så de fire timer ikke bliver misvisende.
I mandags stod jeg på scenen på Villa Copenhagen til Optimizely Copenhagen Developer Meetup. Hristo Bakalov, Lead Solution Architect for Norden hos Optimizely, var vært, og Piotr Nowak fra Rockwool holdt sit første oplæg på meetuppet: en ærlig gennemgang af, hvordan Rockwool flyttede fra egne servere til Optimizely DXP. Mit oplæg hed “Brilliant and ignorant” og handlede om, hvad agenter skal have på plads, før de er til nogen nytte på et Optimizely-projekt.
Omdrejningspunktet var noget, jeg havde lavet torsdagen før. Jeg åbnede en tom mappe, skrev én lang brief og bad et hold agenter om at genopbygge vores eget site, umage.ai, på Optimizely CMS 13 med Visual Builder.
Fire timer og elleve minutter senere var det færdigt. Jeg havde skrevet fire prompts.
Migreringer var engang store projekter
En platformsmigrering var noget, man planlagde. Der skulle holdes en workshop om indholdsmodellen, et designsystem skulle overføres, templates skulle bygges om, og indholdet skulle flyttes i hånden eller med et script, som nogen skrev to gange. For et site på omkring halvtreds sider var det flere ugers arbejde for et lille team, og ingen blev overrasket, når det blev til måneder.
Lad mig lige præcisere, hvad jeg påstår, for forbeholdet vejer lige så tungt som tallet. umage.ai er et ukompliceret site. Det er statisk HTML bygget med Astro, og der er intet bag et login, ingen integrationer, ingen komplekse formularer og ingen personalisering. En rigtig kundemigrering har alt det, og det er netop dér, tiden går.
Men den del, der før udgjorde hovedparten af estimatet, er ikke længere den svære: at omsætte et eksisterende site til indholdstyper, templates og importeret indhold.
Fra tom mappe til kørende CMS på under syv minutter
Briefen bad agenterne samle de Optimizely-skills, vi allerede havde, og hente viden hos to andre agenter (vores agent med API-referencen til NuGet og den agent, der vedligeholder EditorPowertools). Så skulle agenterne starte et CMS 13-site, få det til at køre og derefter:
I also want you to see if you can recreate our umage.ai site on Optimizely CMS … I want you to work autonomously doing this. Install editorpowertools on it. Make sure everything works. Use dynamic workflows where it makes sense, with the cheapest models appropiate for the tasks.
Stavefejlen er min, og den bliver stående.
Tidsstemplerne i sessionsloggen viser, hvad der skete i de følgende 6 minutter og 50 sekunder:
- 20:25 Orkestratoren læste vores fælles videnbase, kopierede fire Optimizely-skills ind i projektet og skrev til de to andre agenter.
- 20:26
dotnet new epi-alloy-mvc. Indtil da havde mappen været tom. - 20:27 To research-subagenter gik i gang parallelt. Den ene skulle finde ud af CMS’ets REST API og MCP-pakkerne, den anden skulle crawle umage.ai og omsætte sitet til en indholdsmodel.
- 20:27 Orkestratoren installerede Editor Power Tools, vores add-on til CMS’et, og rettede undervejs en namespace-fejl i startguiden. Den guide har jeg selv skrevet.
- 20:28 Den styrede en rigtig browser gennem opsætningsskærmen ved første opstart og oprettede en administrator, så den bagefter var logget ind i edit mode.
- 20:29 Den tilføjede Optimizelys officielle MCP-server og en fra communityet.
- 20:31 Den satte OAuth op til CMS REST API’et, hentede tokens og skrev konfigurationen til CLI- og MCP-værktøjerne.
- 20:32 Første commit. Femogfyrre sekunder senere var CLI’en registreret mod sitet.
Ingen klikkede på noget. Og det var bare opvarmningen.
Fire prompts og to ord
Hele den menneskelige del af aftenen fylder ikke mere end en sms:
- 20:25 Briefen.
- 21:22 “Ok. Skip Context7 for now. Let me know if I need to restart the session for the MCP servers or if I can just approve them.” Beskeden skrev jeg kl. 20:42, men den lå i køen i fyrre minutter, fordi orkestratoren havde travlt.
- 21:31 “Could we make it all work with visual builder?”
- 21:31 “Including design?”
De to sidste ord var det dyreste, jeg skrev hele aftenen.
På det tidspunkt havde agenterne bygget en helt fornuftig klassisk model: sider med content areas, fyldt med blokke til hero-sektioner, kortgrids, FAQ’er og nøgletal. “Including design?” betød, at alt det røg ud. I stedet kom der seks Experience-sidetyper, én Section-type og 21 flade Element-typer. Section-typens display templates rummer 23 layoutvarianter, og de er nu selve designsystemet.
Ombygningen måtte være så drastisk på grund af den ene ting ved Visual Builder, som alle Optimizely-udviklere bør kende, før de går i gang. Elementer kan kun bruge de property-typer, Visual Builder understøtter, og lister, content areas og indlejrede blokke er ikke iblandt dem. En række med tre nøgletal er altså ikke én blok med en liste på tre punkter, men tre elementer. Hver eneste liste på det gamle site blev til ét element per punkt eller til et tekstfelt med flere linjer.
Kunsten er ikke at prompte, men at vide, hvilke to ord der ændrer arkitekturen, og at sige dem, mens den stadig er billig at lave om.
Holdet bag
Fjorten agenter var med: én orkestrator og tretten subagenter. En af subagenterne opstod, fordi jeg skrev /statusline midt i byggeriet. Den kostede fire cent og byggede ingenting.
Orkestratoren kørte på Opus, og det gjorde præcis én subagent også, nemlig den, der stod for konverteringen til Visual Builder. Alt andet kørte på Sonnet, fordi briefen bad om den billigste model, der kunne løse opgaven, og det tog orkestratoren helt bogstaveligt. Sonnet skrev 68 % af output-tokens for 53 % af pengene.
Hele aftenen kostede 83,38 dollar til Anthropics listepriser, regnet ud fra vores egne token-tal, så læs det som et estimat og ikke som en faktura. Af de 302 millioner tokens var 98,6 % læsninger fra cachen. Nyt input udgjorde 2.682 tokens. Den fordeling er grunden til, at en session på fire timer med fjorten agenter koster mindre end en ordentlig middag.
Efter 21:31 kørte det hele uden opsyn. Det er tre timer og fem minutter, eller 74 % af sessionen, og i det tidsrum lå hele ombygningen til Visual Builder, importen af indhold, to runder visuel sammenligning med det live site og et code review.
Agenterne ville have øjne, ikke værktøjer
Jeg havde regnet med, at MCP-serverne ville blive hovedhistorien. Jeg havde trods alt installeret dem begge.
Af de omkring 1.540 tool calls gik 325 til at styre en browser. Optimizelys officielle MCP-server blev kaldt omkring 18 gange, og da jeg gik loggene igennem, viste det sig, at de fleste kald bare gik ud på, at agenten listede serverens værktøjer for at se, hvad serveren kunne. Kun tre af dem lavede egentligt arbejde. Det skal dog siges, at agenten kaldte serveren over almindelig HTTP i stedet for at indlæse den som MCP-server, fordi en ny MCP-server krævede, at sessionen blev genstartet. Det bøvl er i sig selv en del af historien.
Alt indhold kom ind gennem det officielle CMS REST API: 58 sider, 57 mediefiler og syv Visual Builder-blueprints, skrevet af et importer-script, der kunne køres igen og igen. Husreglen var, at man retter importeren og aldrig indholdet i hånden. Men det var browseren, der fortalte agenterne, om noget af det virkede.
Og det var vigtigt, for fire af de fejl, agenterne fandt, kompilerede uden problemer og så fine ud i koden:
- Hvid tekst i heroen på hvid baggrund.
- Kort, der aldrig dukkede op, fordi reveal-klassen aldrig blev sat på.
- Styles kopieret fra Astros
:global()-selektorer, som browsere stiltiende ignorerer. - Et telefonlink, der kom ud som
tel:tel:.
En agent, der kun læser sin egen kode, vil med stor selvsikkerhed fortælle jer, at den er færdig. En agent, der tager screenshots i 1440 og 390 pixels bredde og sammenligner dem med det live site, slipper ikke så let. Den endelige sammenligningsrapport viser, at næsten alle sider matcher. Det, der mangler, er de animerede canvas-baggrunde og RSS-linkene.
Giv jeres agent øjne, før I giver den værktøjer.
Det, der kommer til at drille jer i CMS 13.5.1
Vi ramte selv alle faldgruberne herunder i løbet af aftenen, og de står nu i projektets noter, så næste session ikke skal finde dem igen:
Skrivekald via REST giver 403 uden forklaring. OAuth-klienter dukker op som “API keys” under Settings › Access Rights, og det er dér, de skal have rettigheder. Rolle- og claim-mapping på sitet når ikke ud til API’et. Vi var igennem tre forkerte teorier, før det viste sig at handle om et flueben.
Property-værdier i REST er pakket ind. Skriv {"Title":{"value":"…"}}, ikke {"Title":"…"}. Rich text i en composition er {"value":{"html":"…"}}, referencer er cms://content/<guid>. Når I opretter noget, får I 201 tilbage, og den nye nøgle står kun i Location-headeren.
I kan ikke lave en eksisterende sidetype om til en Experience. CMS’et nægter at skifte basisklasse ved opstart, så længe typen findes. Fjern typen, og tilføj den så igen med samme GUID.
Valgnøgler i display templates skal være mindst to tegn lange. "2" fejler. "two" virker.
Dropdowns i Settings ignorerer automatiserede klik. Hvis I styrer admin-brugerfladen fra Playwright, så send mouse-events fra et script i selve siden.
Og så er der to, som jeg vil kalde bugs:
Upload af en SVG over cirka 4 KB via REST API’et giver en 500. CMS’et scanner uploadede SVG- og HTML-filer for scripts, og scanneren læser indholdet af requesten synkront, hvilket ASP.NET Core ikke tillader, når indholdet fylder mere end det, der allerede ligger i bufferen. Alle 27 SVG’er fejlede. Et favicon på 1,6 KB og en PNG på 3,2 MB gik igennem. Upload via CLI’en virker.
Når I ændrer en Style i Visual Builder, bliver visningen i preview ikke opdateret. Selve ændringen bliver gemt, men det event, visningen lytter efter, bliver aldrig sendt. Agenten brugte 28 minutter og 149 tool calls på at finde fejlen ved at dekompilere 13.5.1 og sammenligne websocket-trafikken med og uden en rettelse. Vores rettelse er 40 linjers middleware, og den skal tjekkes ved hver eneste opgradering.
Ingen af de to bugs har jeg meldt ind gennem Optimizelys bugproces, for den er så besværlig, at det ville have taget længere tid end at finde dem. Til gengæld gav jeg dem videre til Hristo på meetuppet, og det er det næstbedste.
Man peger, agenten retter
Sitet var færdigt, men når en agent siger “færdigt”, skal et menneske stadig kigge på det. Derfor satte vi Redline, vores open source-overlay til review, på CMS 13-sitet.
Tryk Alt+Shift+R på en hvilken som helst side, så kan I sætte en kommentar fast på et element, rette dets tekst eller tegne hen over det. Hver note bliver gemt med et screenshot, Razor-filen med linjenummer og præcis det CMS-indhold, den hører til. På en Visual Builder-side peger den på selve composition-noden, helt ned til element og property, så agenten ikke skal gætte, hvilket af tre ens nøgletalselementer I mente. Tekstrettelser bliver gemt som en draft i CMS’et under jeres egen konto og bliver aldrig publiceret.
Om eftermiddagen på meetup-dagen lagde jeg to noter på forsiden: “make the hero subtitle larger” og en ring om et af nøgletallene, hvor jeg havde skrevet “remove this”. Agenten lavede CSS-ændringen, fjernede elementet fra compositionen og fra importerens data, så det ikke dukkede op igen, satte flueben ved begge noter og svarede på dem.
Mine råd, hvis I planlægger en migrering til CMS 13
Beslut jer for Visual Builder, før I modellerer noget. De flade elementer ændrer indholdsmodellen fra grunden. Vi besluttede os først bagefter, og det kostede en komplet ombygning af modellen. Ombygningen var billig, fordi agenterne klarede den på 48 minutter, men med et team af mennesker koster den en uge.
Giv agenterne en browser, og få dem til at kigge. Screenshots sammenlignet med det live site fangede de fejl, som compileren ikke opdagede. MCP-servere er nyttige, men det er en browser, agenten selv kan styre og kigge i, der viser den, om arbejdet holder.
Ret importeren, ikke indholdet. Når hver side kommer fra et script, I kan køre igen, er hver mappingfejl en rettelse på én linje og en ny import i stedet for en jagt rundt i editoren.
Lad den dyre model beslutte og den billige udføre. Én Opus-orkestrator og én Opus-subagent på det sværeste problem. Resten klarede den billigere model, og det gik fint.
Skriv faldgruberne ned. Hver session, der ikke kender til fluebenet ved API keys, bruger en halv time på at finde det igen. Vores står nu i projektets noter, og det er begyndelsen på en meget større idé og emnet for mit næste indlæg.
Hvis I planlægger at flytte til Optimizely CMS 13, at flytte væk fra det eller at opgradere fra 11 eller 12, så tag fat i os. Jeres site har sikkert de integrationer, logins og den personalisering, som vores ikke havde, og den slags kræver stadig et ordentligt stykke arbejde. Men når vores agenter står for ombygningen, ser estimatet helt anderledes ud end det, I ville få i et almindeligt migreringsprojekt. Til opgraderinger har vi en ydelse for sig, og Optimizely er vores speciale.
De fire timer er ikke det interessante tal. Det er de fire prompts. Det, vi mennesker skal stå for, er at vide, hvad vi skal bede om, og at kigge ordentligt efter i det, vi får.