Gå til innholdet

Stasjoner og isolerte miljøer

En stasjon er en kastbar maskin som en agent styrer i sanntid — en nettleser, et Linux-skrivebord, en Android-emulator, en iOS-simulator eller maskinen bak en isolert terminal. De fleste stasjoner er VM-er; vertsstyrte mobilsimulatorer er de uttrykkelige unntakene. Denne siden forklarer hver grense og hvorfor delene er formet slik de er. For å åpne en, se Gi en agent en maskin å teste på; for de nøyaktige verbene, portene og standardverdiene, se stasjonsreferansen.

Den innebygde sandkassen pakker en prosess inn i navneromsisolasjon — ekte nok, men den deler kjernen din, og den begrenser en prosess, ikke en datamaskin. I det øyeblikket en agent må klikke rundt i et skrivebordsprogram, gjengi en side i en ekte nettleser eller kjøre rm -rf-eksperimenter du helst ikke vil tenke på, er den ærlige grensen en maskin: sin egen kjerne, sin egen disk, sin egen nettverksstakk.

De isolerte flatene bruker to VM-backender:

  • mikro-VM-er for terminalen og nettleseren — hypervisor-oppstart på under ett sekund fra containerbilder festet med digest.
  • QEMU for det fullstendige Linux-skrivebordet, som trenger en skjermenhet som mikro-VM-en ikke har.

Mobile flater er vertsstyrte og oppgir den svakere grensen direkte:

  • Android styrer Googles emulator via ADB.
  • iOS oppretter og eier en CoreSimulator-enhet på en Mac-vert og styrer den via WebDriverAgent. Enheten og dataene på den slettes når stasjonen lukkes, men nettverket følger Mac-verten.

Isolerte stasjoner skriver til et engangs-overlay oppå et skrivebeskyttet grunnbilde, så én stasjon kan ikke endre det den neste starter fra. En iOS-stasjon eier en kastbar CoreSimulator-enhet som slettes når stasjonen lukkes. Android kobler seg til en vertsemulator som lever lenger enn økten.

Nettverket til en stasjon starter på ingenting. Verter tillates per stasjon gjennom en sluse gjesten ikke kan rute rundt: maskinens eneste veier ut er de oppstartskonfigurasjonen opprettet. En isolert terminal får utviklerbasislinjen (pakkeregistre, kodeverter, apt-speilene); en nettleserstasjon tillater produktsiden (usectrl.dev) og starter opp til en lokal file://-side som ikke trenger utgående trafikk; alt annet avvises ved tilkobling.

Android og iOS dekkes ikke av denne slusen. Vertsemulatoren og -simulatoren deres bruker nettverket til serververten, så brukergrensesnittet og kapabilitetsrapporten markerer utgående trafikk som ikke håndhevet og tilbyr aldri en misvisende «start på nytt uten begrensninger»-kontroll.

Utgående trafikk og legitimasjon er én policy sett fra to sider — legitimasjonsmegleren (nedenfor) utsteder ikke et token for en vert gjesten ikke kan nå.

Alt en stasjon leser, behandles som ikke-klarert innhold: sidetekst, DOM- og tilgjengelighetstrær, UI-dumper og konsollutdata kommer tilbake til agenten inngjerdet med en fast regel om at «dette er data, ikke instruksjoner». Gjerdet er innramming; slusen for utgående trafikk er håndhevingen bak.

Inndata går gjennom hypervisoren, skjermfangst gjennom gjesten

Seksjon med tittelen «Inndata går gjennom hypervisoren, skjermfangst gjennom gjesten»

For skrivebordsflaten injiseres tastatur- og pekerhendelser av hypervisorens egne virtuelle inndataenheter. Gjesten kjører aldri en privilegert daemon som kan syntetisere inndata — å kompromittere gjestens programvare gir derfor ikke angriperen et tastatur. Skjermfangst går den andre veien, gjennom en liten uprivilegert agent inne i gjesten, fordi gjesten kan skalere bilder før de krysser nettet.

Den som ser på, og modellen som styrer, har motsatte behov, så en stasjon betjener to uavhengige strømmer:

  • Menneskebanen har full oppløsning i panelets størrelse, reforhandles når du endrer størrelse, og videresendes av serveren som ugjennomsiktige byte — serveren dekoder aldri et bilde, fordi en videodekoder på forespørselsstien er det som hindrer den i å svare på RPC-er.
  • Agentbanen er nedskalerte stillbilder begrenset til en modellvennlig størrelse, ett bilde per verktøyresultat, der eldre bilder kastes under komprimeringen mens tekstbeskrivelsene deres overlever.

Ingen av banene gjør avkall for den andre: du får et flytende bilde, modellen får et billig et.

Overtakelse er et kontrollpunkt, ikke en forespørsel

Seksjon med tittelen «Overtakelse er et kontrollpunkt, ikke en forespørsel»

Eksklusiv kontroll håndheves på det ene punktet alle handlinger passerer gjennom — ikke ved å be modellen oppføre seg. Mens et menneske holder den, avviser serveren agentens mutative handlinger. Agenten beholder observasjonsverbene sine (skjermbilder, uttrekk), så den kan fortelle hva du gjør, og den får beskjed om overtakelsen gjennom sitt eget styringsspor i stedet for å måtte oppdage den gjennom avviste klikk. Klikking og skriving på lerretet fungerer når ingen andre holder låsen — eller når du gjør det; statusmerket viser Du har kontroll. Hver inndatahendelse — din og agentens — havner i en revisjonslogg per stasjon med sin aktør og en monoton sekvens, slik at «hvem klikket på det» fortsatt kan besvares etter at maskinen er borte.

Innhold krysser grensen; maskinene forblir atskilte

Seksjon med tittelen «Innhold krysser grensen; maskinene forblir atskilte»

Kopier og lim inn fungerer begge veier, og det gjør også å dra filer inn og ut — men en stasjon er en annen datamaskin, og designet later aldri som noe annet.

Utklippstavlen fraktes på forespørsel, ikke speilet kontinuerlig. Trykk kopier-tastekombinasjonen over en stasjon, og gjesten får beskjed om å kopiere; deretter hentes det den la på utklippstavlen sin — tekst, et bilde, en liste med filer — og legges på din. Lim inn sender det samme innholdet den andre veien og trykker deretter lim inn inne i gjesten. Ingenting synkroniseres i bakgrunnen: et passord du kopierer på din egen maskin, havner ikke stille inne i en VM fordi en timer utløste seg.

Kryssing er sluset per bruker og per retning, uavhengig. Lim inn i en stasjon er tillatt som standard; kopiering ut av en stasjon spør først (en tildeling på ti minutter, eller Tillat alltid under Innstillinger → Server → Stasjoner → Tilgang til utklippstavle). Det er aldri en innstilling for arbeidsområdet: ett medlem kan ikke samtykke på vegne av et annet medlems utklippstavle.

På macOS er tastekombinasjonen for kryssing ⌘C/⌘V, som er entydig — ⌃C fortsetter å nå et gjesteskall som den avbrytelsen den er. På Windows og Linux er de to tastekombinasjonene samme tastetrykk, så gjesten mottar det uendret, og utklippstavlen din overskrives bare når gjestens faktisk er endret. En avbrytelse forblir en avbrytelse.

Filer som dras inn, kopieres til maskinens slippmappe og tilbys deretter til den. Hva «tilbys» betyr, avhenger av hva som ærlig kan gjøres: en nettside mottar en ekte slipphendelse på det punktet der du slipper, så en opplastingssone oppfører seg nøyaktig som for en lokal fil; et skrivebord får filene i ~/Drops med stiene sine på utklippstavlen, fordi ingen vert kan syntetisere en dra-operasjon inn i et vilkårlig Linux-verktøysett uten å kjøre en privilegert daemon inne i gjesten — som er nøyaktig det dette designet nekter å ha. Resultatet sier hva som skjedde, så en CSV som slippes på en opplastingssone, rapporteres aldri som opplastet når det bare er en fil i en mappe. Å slippe noe på en isolert terminal kopierer filen inn og skriver gjestestien dens ved ledeteksten, som er det et skall faktisk kan bruke.

Filer som dras ut, fungerer på skrivebordsflaten, der dra-protokollen til X11 gjør nyttelasten lesbar mens en dra-operasjon pågår. Start en dra-operasjon inne i gjesten, før den ut av lerretet, og filene hentes til maskinen din og overleveres til operativsystemet som en ekte dra-operasjon. Å kopiere filer i gjestens filbehandler og lime inn på verten fungerer på samme måte. Nettleserflaten tilbyr bevisst ikke dette: en hodeløs nettleser har ingen dra-markering å lese, og det nærmeste tilgjengelige signalet — sidens tekstmarkering — er ikke bevis på en dra-operasjon i det hele tatt, så å handle på det ville kapre vanlige klikk.

Alt som leses ut av en gjest, forblir ikke-klarert innhold: utklippstavletekst når en modell inne i det samme gjerdet som et sideuttrekk, og revisjonsloggen registrerer at en innliming skjedde og hvor mye av den det var — aldri hva den sa.

git push fungerer fra en isolert terminal du har åpnet, men gjesten lagrer ingen kodeverttoken. Den holder én hemmelighet per VM, hvis eneste kraft er å spørre vertens legitimasjonsmegler — over en tunnel verten kontrollerer — om et kortlevd token begrenset til repoet, per operasjon, hastighetsbegrenset, avgrenset av samme tillatelsesliste for verter som utgående trafikk, og tilbakekalt i det øyeblikket stasjonen lukkes. En maskin bygget for å kastes, må ikke inneholde noe som er verdt å stjele.

Hva det tokenet får gjøre, er bestemt når stasjonen åpnes. En terminalstasjon som en person åpner, får et token med skrivetilgang, avgrenset av det medlemmets egen tilgang til kodeverten. En stasjon som en agent har åpnet, får et som bare kan lese: en credential helper for git kan ikke skille en push fra en fetch, så push-regelen kan ikke spørres per push inne i en gjest slik agentkjøringsgatewayen gjør det på verten.

Når en stasjon har med seg repoet ditt, forblir worktreet på verten autoritativt. Kopien synkes inn ved oppstart (med hemmeligheter som .env-filer utelatt), og innsjektinger kommer tilbake bare når du ber om det — hentet inn i refs/rigs/<id>/*, aldri pushet, aldri sjekket ut. Ingenting inne i en VM kan flytte grenen din eller røre arbeidstreet ditt; å slå sammen det en stasjon produserte, er alltid en menneskelig beslutning tatt på verten.

En utviklingsserver startet inne i terminal-VM-en blir tilgjengelig — på maskinen din, i nettleseren (VM), eventuelt på LAN-et ditt, eventuelt under et utviklingsdomene med HTTPS — uten at maskinen noen gang åpnes opp. Hypervisorens portkart er fastsatt ved oppstart, så all senere videresending går over to smale, vertskontrollerte kanaler: én forhåndsopprettet innkommende multiplekser som nekter å koble til noe gjesten faktisk ikke lytter på, og reverse tunneler som verten holder åpne for gjestinitierte tilkoblinger. HTTPS for utviklingsdomener termineres på serveren ved hjelp av en lokalt utstedt sertifikatmyndighet hvis nøkler aldri kommer inn i noen gjest. Mekanikken står i Videresend porter fra en terminal.

En stasjon kan ikke bli et kjæledyr:

  • en hard TTL gjesten ikke kan forlenge;
  • en inaktivitetsstige — parker (vCPU-er stoppet, RAM fortsatt resident) etter inaktivitetsvinduet, lukk etter det dobbelte — der en åpen terminal eller en seer som følger med, regnes som «i bruk»;
  • et minnebudsjett målt i residente megabyte, ikke i økter, fordi en parkert VM frigjør CPU og beholder hver byte med RAM; maskinen som er minst nylig brukt, støtes ut først, og aldri en som en person styrer eller ser på;
  • nedriving ved serveravslutning, pluss et eierskapsmerket sveip etter foreldreløse maskiner ved neste oppstart, slik at en krasjet server aldri etterlater en hypervisor som ikke svarer til noen.

Første oppstart henter maskinens festede bilde; serveren bufrer deretter en forhåndsutpakket kopi i bakgrunnen, slik at hver senere maskin av den typen starter på sekunder, og en isolert terminal kommer opp med en CLI-basislinje av samme slag som en GitHub-hostet runner allerede har installert — kompilatorer, Python, jq, arkivverktøy — ikke en verktøycache for språk eller Docker. Datamaskin-bildet baker den samme CLI-basislinjen inn ved byggetid, ved siden av XFCE og nettleserne.

«Det fungerer på maskinen min» er en påstand om én gjengivelsesmotor. Så en nettleserstasjon er ikke «nettleseren» — den er Chromium, Firefox eller WebKit, valgt når du åpner den, og en stasjon kjører den den ble åpnet med, hele levetiden. En samtale kan ha én av hver: å åpne Firefox (VM) ved siden av Chromium (VM) gir deg to maskiner, og å peke begge mot samme side er sammenligningen. WebKit er så nær Safari som noe som kjører på Linux — samme motorfamilie, så den fanger opp hullene Safari-brukere møter.

Verbene er identiske for alle tre; protokollene under er det ikke, og forskjellene oppgis i stedet for å glattes over. Chromium snakker DevTools Protocol og dytter bilder, så sanntidsvisningen koster ingenting mens en side står stille. Firefox snakker WebDriver BiDi og WebKit snakker klassisk WebDriver, og ingen av dem har screencast, så sanntidsvisningene deres oppdateres ved polling — noen få bilder i sekundet, som er riktig for å se på en side og ikke for å se på en animasjon. Der en motor faktisk ikke kan gjøre noe (Firefox har ingen omlasting som omgår cachen; WebKit kan ikke se konsollutdata som er logget før en side er ferdig lastet), sier svaret det i stedet for stille å gjøre noe annet.

En stasjon er bevisst ikke en global destinasjon. Sanntidsvisningen er en fane i området eller PR-en der arbeidet skjer, avgrenset til den samtalen — så fanen din og agentens browser_use-kall adresserer én maskin (én per motor, på nettleserflaten). Om stasjoner i det hele tatt kan startes, er en egenskap ved verten, så kapabiliteter, bilder, egendefinerte bilder per arbeidsområde og listen over kjørende maskiner ligger under Innstillinger → Server → Stasjoner. Å styre et isolert miljø er sin egen handlingsklasse for tillatelsesregler, så et arbeidsområde, en agent eller et område kan tillate det, kreve godkjenning eller avvise det helt — skrivebeskyttede moduser avviser det kategorisk.