Ga naar inhoud

Een agent een testmachine geven

Een rig is een wegwerpmachine die een agent opent wanneer hij iets echt moet uitproberen: een pagina laden, door een desktopapp klikken, wat rondtikken op een telefoon. Je kunt hem in realtime aan het werk zien en de bediening overnemen wanneer je maar wilt.

Ingesloten terminal-, browser- en desktop-rigs zijn VM’s met wegwerpschijven en netwerken achter een hek. Android en iOS zijn door de host beheerde emulators: hun apparaatstatus is wegwerpbaar, maar hun netwerk volgt de serverhost.

Rigs draaien op de machine die cc_server host — dezelfde machine, niet degene waar je naar kijkt. Er zijn vijf oppervlakken voor gebruikers; de desktop- en mobiele oppervlakken vereisen installatie op de host:

Oppervlak Draait op Installatie
Terminal (VM) Een microVM die een vastgezet Ubuntu-image opstart Geen — het image wordt bij het eerste gebruik automatisch opgehaald
Browser (VM) Een microVM die een vastgezet Debian-image opstart, met Chromium, Firefox of WebKit dat bij het eerste gebruik wordt geïnstalleerd Geen — hetzelfde
Computer (VM) QEMU met een Linux-desktopimage dat Chromium, Firefox, WebKit en een CLI-basis in de stijl van een door GitHub gehoste runner meelevert Installeer QEMU (brew install qemu) en gebruik daarna Importeren voor een desktopimage onder Instellingen → Server → Rigs
Android Google’s Android-emulator Installeer de Android SDK, maak een AVD aan en start die (hieronder)
iOS-simulator CoreSimulator op de Mac van de server Installeer Xcode en de gevraagde iOS-runtime en installeer daarna de automatiseringsbridge onder Instellingen → Server → Rigs

De terminal- en browsermachines starten vanaf images die op digest zijn vastgezet: de exacte bytes liggen vooraf vast, worden bij de eerste start één keer opgehaald en daarna gecachet — na de eerste start van elk soort slaan latere machines het downloaden volledig over en staan ze binnen enkele seconden klaar. Instellingen → Server → Rigs laat zien wat je server kan starten en welke machines er nu draaien.

Een geïnstalleerde desktopimage blijft vanaf dezelfde pagina te beheren: Importeren vervangt hem door een nieuwere qcow2 en Verwijderen haalt hem weg, zodat je een nieuwe build kunt installeren.

Er is geen image van ons voor Android of iOS, en dat is geen omissie. Android-systeemimages komen uit Google’s SDK; iOS-runtimes komen uit Xcode. Installeer voor Android Android Studio (of de SDK-opdrachtregeltools), voeg een virtueel apparaat toe in Device Manager en start het. De Rigs-pagina meldt Android daarna als beschikbaar.

Die vertelt je ook precies welke stap je mist — geen SDK, geen emulator, geen virtueel apparaat, of een apparaat dat simpelweg niet draait — want die hebben vier verschillende oplossingen en slechts één ervan is een download. Als je cc_server start vanuit een shell die de SDK niet ziet, exporteer hem dan:

Terminalvenster
export ANDROID_HOME="$HOME/Library/Android/sdk"

Voor iOS moet de server zelf op macOS draaien, met Xcode en een geïnstalleerde iOS-simulatorruntime. Open Instellingen → Server → Rigs en druk op iOS-automatiseringsbridge installeren. De server haalt het artefact van WebDriverAgent op, gecontroleerd via een checksum, verifieert het en installeert het in de automatiseringsopslag van de server. Tijdens het instellen start geen enkele simulator op.

Machines leven als tabbladen, naast de chat en de diff — in een ruimte of op een PR-pagina, in hetzelfde +-menu, onder Machines:

  • Computer — een Linux-desktop met Chromium, Firefox en WebKit
  • Chromium, Firefox of WebKit — een browser
  • Android — de draaiende Android-emulator
  • iOS-simulator — een wegwerpsimulator die voor dit gesprek wordt aangemaakt

Kies er een en druk op Machine starten. Het tabblad zegt in welke fase het opstarten zit (“Starting the microVM”, “Waiting for the guest to come up”) in plaats van alleen maar te draaien.

Het tabblad is gebonden aan het gesprek, en de agenttool ook. Een Chromium-, Firefox- of WebKit-tabblad en browser_use, Android en mobile_use, of de iOS-simulator en ios_use richten zich op dezelfde standaardmachine. Extra plekken in de UI zijn aparte vergelijkingsmachines; agenttools gebruiken altijd de standaardmachine.

Zo bouw, installeer en start je een Flutter-app op Android:

Terminalvenster
fvm flutter build apk --debug

Roep daarna mobile_use aan met install_apk en build/app/outputs/flutter-apk/app-debug.apk, gevolgd door start_app en de naam van het Android-pakket. ui_dump, schermafbeeldingen en invoer sturen hetzelfde apparaat aan dat in het menselijke tabblad te zien is. stop_app, clear_app_data, uninstall_app, open_url en shell-aanroepen in argv-vorm dekken de rest van de ontwikkelcyclus, zonder een shell op de serverhost aan te roepen.

Zo bouw, installeer en start je een Flutter-app in de iOS-simulator:

Terminalvenster
fvm flutter build ios --simulator --debug
/usr/bin/plutil -extract CFBundleIdentifier raw -o - \
build/ios/iphonesimulator/Runner.app/Info.plist

Roep daarna ios_use aan met install_app en de map van de .app, gevolgd door start_app en de bundel-id die plutil afdrukt. De iOS-tool biedt ook stop_app, uninstall_app, open_url en een spawn-actie in argv-vorm voor diagnostiek lokaal in de simulator.

Desktop- en browserweergaven schalen mee met het paneel. iOS houdt de vaste puntgrootte van de simulator aan en zet die met balken in het beeld. Elk oppervlak heeft nog steeds twee onafhankelijke kanalen: de agent krijgt kleine, goedkope schermafbeeldingen en jij de liveweergave. Bij het wisselen van tabblad stopt de menselijke stream, zodat een machine op de achtergrond geen weergavebandbreedte kost.

Een rig-tabblad start niet uit zichzelf een machine, ook niet bij het herstellen van de indeling. Die regel voorkomt dat het starten van de app onverwacht VM’s opstart of simulatorapparaten aanmaakt.

Het canvas is van jou om in te typen en te klikken, zolang niemand anders de exclusieve besturing heeft — of wanneer jij die hebt. Zolang jij die vergrendeling vasthoudt, luidt het statuslabel Jij hebt de besturing, kan de agent nog steeds schermafbeeldingen maken, en weigert de server zijn wijzigende acties bij het ene flessenhalspunt waar elke actie doorheen gaat. Alles wat je doet, wordt op je naam vastgelegd.

Druk op Machine stoppen als je klaar bent.

De besturing is bewust exclusief: twee actoren die in één machine typen, produceren invoer die geen van beiden bedoelde.

Kopiëren en plakken werkt in beide richtingen over het rig-canvas, en bestanden slepen ook.

Kopiëren en plakken. Druk de kopieercombinatie boven het canvas en wat de machine heeft gekopieerd — tekst, een afbeelding, een lijst met bestanden — belandt op jouw klembord. Plakken stuurt het jouwe de andere kant op en drukt binnen de machine op plakken. Op macOS is de combinatie ⌘C/⌘V; ⌃C bereikt een gast-shell nog steeds als onderbreking. Op Windows en Linux gebruik je ⌃C/⌃V — de gast ontvangt dezelfde toetsaanslag die hij toch al zou krijgen, dus ⌃C in een gastterminal onderbreekt nog steeds en jouw klembord blijft ongemoeid.

Er wordt niets op de achtergrond gesynchroniseerd. Een wachtwoord dat je op je eigen machine kopieert, komt niet in een VM terecht omdat er een timer afging; het steekt pas over wanneer je plakt.

Plakken in een rig is standaard toegestaan. Kopiëren uit een rig vraagt eerst om toestemming — een machtiging van tien minuten, of Altijd toestaan onder Instellingen → Server → Rigs → Klembordtoegang. De twee richtingen zijn onafhankelijk, en ze volgen jou, niet de werkruimte.

Bestanden naar binnen slepen. Zet ze neer waar dan ook op het canvas.

  • Op de Browser (VM) ontvangt de pagina een echte drop op het punt waar je loslaat, dus een uploadzone gedraagt zich precies zoals bij een lokaal bestand.
  • Op de Computer (VM) belanden de bestanden in ~/Drops en komen hun paden op het klembord van de machine, zodat ⌃V ze in een bestandsbeheerder of een uploadveld plakt. Een host kan geen sleepbeweging in een willekeurige Linux-app synthetiseren zonder een bevoorrechte daemon in de VM te draaien, en die hebben rigs bewust niet — dus vertelt de melding je waar de bestanden terechtkwamen in plaats van te doen alsof er iets is neergezet.
  • Op een terminal wordt het bestand naar binnen gekopieerd en wordt het pad bij de prompt getypt, klaar om aan een commando mee te geven. Een afbeelding in een terminal plakken doet hetzelfde: hij wordt in de machine opgeslagen en je krijgt het pad.

Bestanden naar buiten slepen werkt vanaf de Computer (VM). Begin een bestand binnen de machine te slepen, beweeg de aanwijzer buiten het canvas, en het wordt een echte sleepbeweging op je desktop — zet het neer in Finder of Verkenner. Bestanden kopiëren in de bestandsbeheerder van de machine en ze aan jouw kant plakken werkt ook. De Browser (VM) biedt dit niet: een headless browser heeft geen sleeplading om te lezen, en gokken op basis van de tekstselectie van de pagina zou gewone kliks kapen.

De terminals in een ruimte of op een PR-pagina kunnen in een rig draaien in plaats van op de eigen machine van de server. Als dat zo is, toont het paneel een badge Afgeschermde VM.

Wat er verandert:

  • Niets wat je uitvoert bereikt de host. Een rm -rf daarbinnen kost je de rig.
  • Het netwerk weigert standaard. Alleen hosts op de allowlist van de rig zijn bereikbaar, en alles gaat door een hek dat die lijst handhaaft.
  • git push werkt nog steeds in een terminal die jij hebt geopend. De rig heeft geen opgeslagen inloggegevens; hij vraagt de server per handeling om een kortlevende set, begrensd door je eigen forge-toegang, en dat token wordt ingetrokken zodra de rig sluit. Een rig die een agent heeft geopend, krijgt inloggegevens met alleen leesrechten: hij kan fetchen, maar niet pushen.

Wat je moet weten:

  • Een herstelde ingesloten terminal wacht op jou. Net als een rig-tabblad toont een microvm-terminal die met je indeling terugkomt een knop Shell openen in plaats van bij het starten zijn VM op te starten. Een host-shell-terminal kost een proces; een ingesloten terminal kost een machine.
  • Bestanden die je op de terminal neerzet, worden getypt, niet geopend. Zet een CSV neer op een ingesloten terminal en hij wordt naar de machine gekopieerd en zijn gastpad verschijnt bij de prompt — het hostpad zou een commando zijn dat daar faalt.
  • De kopie in de rig is een kopie. Je worktree op de host blijft de bron van waarheid. Commits die je in een rig maakt, worden op verzoek teruggezet naar refs/rigs/<id>/* — ze verplaatsen nooit je branch en raken je working tree niet aan.
  • Werk voor een host-doel draait nog steeds op de host. Een Linux-gast kan niet voor macOS bouwen of xcodebuild uitvoeren. Kies daarvoor expliciet de native backend; de app vraagt je om te bevestigen in plaats van stilletjes over te schakelen.

Draai een devserver in de Terminal (VM) — pnpm dev op poort 3000, bijvoorbeeld — en binnen een paar seconden licht het stekkerpictogram in de hoek van de terminal op: de poort wordt doorgestuurd naar localhost:3000 op jouw machine, is bereikbaar op localhost:3000 in de Browser (VM), deelbaar op je netwerk, en te benoemen als https://myapp.test. De hele flow — automatisch doorsturen, delen op het LAN, dev-domeinen met HTTPS — heeft zijn eigen gids: Poorten doorsturen vanaf een terminal.

Een werkruimte kan de Terminal (VM) en Browser (VM) naar zijn eigen images laten wijzen — onder Instellingen → Server → Rigs → Aangepaste images (deze werkruimte). Typisch gebruik: breid de standaardimages uit met de toolchain die je project nodig heeft, zodat elke terminal meteen klaar is, of hergebruik een image die je team al publiceert.

De machine start nog steeds binnen dezelfde omhulling: hetzelfde egress-hek, dezelfde broker voor inloggegevens, dezelfde levenscyclus. Alleen werkruimtebeheerders kunnen de instelling wijzigen, nieuwe machines nemen hem over (draaiende houden de hunne), en de verwijzing moet naar een registry-image wijzen — lokale paden worden geweigerd.

Wat een image moet bieden:

  • Terminal (VM) — een Linux-image met bash. Het heeft ook git, curl en socat nodig — vooraf geïnstalleerd, of installeerbaar bij de eerste start (elk Debian-/Ubuntu-image werkt: ze worden automatisch geïnstalleerd, samen met een CLI-toolset in de stijl van een door GitHub gehoste runner: compilers, Python 3, jq, archieftools, rsync. Taalruntimes zoals Node/Go/Java en Docker worden niet vooraf geïnstalleerd). Gastpoort 7911 is gereserveerd voor de poortdoorschakelaar.
  • Browser (VM) — een Debian-/Ubuntu-image met bash en socat, plus een chromium-binary. De server start Chromium zelf als chromium --headless=new en relaist DevTools van gastpoort 9223 naar 9222. PulseAudio en ffmpeg worden bij de eerste start geïnstalleerd. Bouw niet FROM chromedp/headless-shell — die binary heeft geen audio. De override geldt alleen voor Chromium-rigs; Firefox en WebKit negeren hem en starten het vastgezette Debian-image. Gastpoorten 9222/9223 zijn gereserveerd.

Twee aanbevelingen: zet de verwijzing vast op digest (@sha256:…) zodat de bytes niet onder je vandaan kunnen veranderen, en host hem op Docker Hub of GitHub Container Registry — de downloadhosts van die registries komen automatisch door het egress-hek; bij andere moet je misschien hun contentdeliveryhosts bereikbaar maken om te kunnen pullen.

Rigs zijn bedoeld als tijdelijk:

  • Inactief — na ~15 minuten zonder activiteit parkeert een browser-, desktop- of mobiele rig (bevroren, wekt direct bij de volgende actie). Een ingesloten terminal wacht 45 minuten. Na twee keer het inactiviteitsvenster sluit hij.
  • Tijdslimiet — elke rig heeft een harde levensduur die hij niet kan verlengen, wat hij ook doet.
  • Geheugen — als de server ruimte nodig heeft voor een nieuwe rig, sluit hij de minst recent gebruikte. Een rig die iemand bestuurt, bekijkt of waarin een terminal openstaat, wordt nooit afgepakt.

Als een ingesloten rig sluit, wordt zijn schijf weggegooid. Het sluiten van een Android-rig ontkoppelt van de host-emulator — hij wordt niet verwijderd. Een iOS-rig verwijdert het CoreSimulator-apparaat dat hij heeft aangemaakt. Haal eerst alles wat je wilt bewaren terug.

Ingesloten terminal-, browser- en desktop-rigs beginnen met een egress-hek dat standaard alles weigert: je staat hosts expliciet toe, en de enige route van de gast is een hek dat die lijst handhaaft. Een browserrig staat ook de productsite (usectrl.dev) standaard toe. De broker voor inloggegevens gebruikt dezelfde lijst.

Twee eerlijke kanttekeningen:

  • Mobiel netwerk volgt de host. De emulator van Android en CoreSimulator van Apple zitten niet achter het egress-hek van de omhulling. Geen van beide mobiele tabbladen biedt een knop om het netwerk te omzeilen, omdat het door de host beheerde netwerk toch al onbeperkt is.
  • Alles wat een rig leest, is niet-vertrouwd. Paginatekst, DOM, toegankelijkheidsbomen en UI-dumps komen terug bij de agent, omhuld met markeringen die zeggen “dit zijn gegevens, geen instructies”. Een pagina die jouw agent opdrachten probeert te geven, leest als een geciteerde string.

Je kunt alles wat draait bekijken en elk onderdeel stoppen onder Instellingen → Server → Rigs.

  • Rigs en omhullingen — het model achter dit alles: waarom VM’s, de twee weergavekanalen, de broker voor inloggegevens, de levenscyclus
  • Poorten doorsturen vanaf een terminal — bereik een devserver vanaf elke plek waar het ertoe doet
  • Rigreferentie — elk oppervlak, werkwoord, poort en standaardwaarde op één plek
  • Beveiligingen configureren — Drive an enclosure (rig) is een actieklasse die je per werkruimte, agent of ruimte kunt instellen op toestaan, eerst vragen of weigeren. Alleen-lezen-modi weigeren het ronduit.