Naar de hoofdinhoud

frembench — dev benches

frembench is een Linux-machine die je per minuut huurt en vanuit je browser bereikt: een dev bench. Hij heeft dezelfde taaltoolchain als je CI-runners, dus wat op een bench bouwt, bouwt ook in CI.

Wat het kost

Een bench-gebruiker kost € 39 per maand en omvat 200 uur draaitijd. Boven het tegoed betaal je € 0,20 per uur, en het totaal heeft een harde bovengrens: je rekening kan nooit hoger worden dan € 99 per bench-gebruiker per maand, hoe intensief je ze ook gebruikt. Bij één gebruiker wordt die grens bereikt bij 500 uur draaitijd; daarna blijft de bench zonder extra kosten draaien. Alle bedragen hier zijn in EUR, de valuta waarin benches worden gefactureerd, net als de rest van je abonnement.

Uren worden gedeeld over alle bench-gebruikers, zoals CI-minuten. Het tegoed is 200 uur × aantal gebruikers, gemeten over alles wat de benches van je organisatie hebben gedraaid. Twee gebruikers delen dus 400 uur: een drukke bench put uit het tegoed van een rustigere collega in plaats van meteen in de overschrijding te gaan. Het plafond wordt op dezelfde manier gedeeld: de grens is € 99 per bench-gebruiker, niet per machine, dus één bench in een organisatie met twee gebruikers kan meer dan € 99 kosten terwijl de organisatie binnen € 198 blijft.

Twee formaten

StandaardGroot
Machine2 vCPU, 8 GB4 vCPU, 16 GB
Gebruiker€ 39 / maand€ 78 / maand
Toevoeging aan het gedeelde tegoed200 uur400 uur
Tegoeduren per draaiuur12
Boven het tegoed€ 0,20 / uur€ 0,40 / uur
Maximale kosten per gebruiker per maand€ 99€ 198

Een grote gebruiker telt in alle opzichten als twee bench-gebruikers, dus alles op deze pagina geldt ervoor met verdubbelde getallen: één tegoed voor de hele organisatie, dezelfde meting per seconde, hetzelfde plafond. Een rustige gebruiker van het ene formaat compenseert een drukke van het andere. Een beheerder van de organisatie koopt grote gebruikers op de factuurpagina en kiest het formaat wanneer diegene een gebruiker aan een persoon toewijst; de bench wordt aangemaakt in het formaat van de gebruiker van zijn eigenaar.

Twee details die het waard zijn om te weten, omdat ze bepalen wat je daadwerkelijk betaalt:

  • Tijd wordt in seconden gemeten en één keer afgerond, aan het einde van de periode. Een bench schort zichzelf op na 30 minuten inactiviteit en wordt wakker wanneer je verbinding maakt, dus een werkdag bestaat uit veel korte intervallen. Als we elk daarvan naar een hele minuut zouden afronden, zouden twintig keer tien seconden wakker zijn als twintig minuten worden gefactureerd: dan betaal jij voor onze eigen optimalisatie van het opschorten.
  • 200 uur is veel meer dan een werkmaand aan verbonden tijd. Het tegoed is afgemeten op de werkelijke tijd dat een bench wakker is, niet op de uren achter je toetsenbord; een agent die een lange taak draait telt mee, een inactieve editor niet.

Gebruikers worden naar rato verrekend wanneer je ze toevoegt of verwijdert, net als elke andere gebruiker. Zie de prijzenpagina voor hoe het zich verhoudt tot de rest van het abonnement.

Je hoeft hem niet te beheren. Hij wordt wakker wanneer je verbinding maakt en schort zichzelf op wanneer niemand verbonden is en er niets draait.

Wat blijft bewaard en wat niet

Dit is het enige wat je moet begrijpen voordat je een bench gebruikt, omdat het al het andere bepaalt.

Je bench heeft twee schijven. Het profielvolume van 50 GB is van jou en blijft bestaan. De opstartschijf wordt bij elke keer wakker worden opnieuw opgebouwd uit een verse image. Zo krijg je updates zonder onderhoudsvenster en zonder dat je ooit gevraagd wordt om opnieuw op te starten.

$HOME staat op het profielvolume. Dus:

WatOverleeft opschorten
Je code, je node_modules, je build-uitvoerja
Dotfiles, shellgeschiedenis, git-configuratie, SSH-sleutelsja
npm i -g, pip --user, uv tool, pipx, cargo install, go installja
Je aanmelding bij Claude Codeja
apt installnee

apt is de bewuste uitzondering: systeempakketten zijn waar de image voor is. Heb je er elke ochtend een nodig, dan hoort die in de image thuis. Open een issue in plaats van het in je shellprofiel te scripten; met de wekelijkse herbouw is het dan niet meer jouw probleem.

Je bestanden meenemen

Je profielvolume overleeft opschorten, maar niet het verdwijnen van je bench. Wanneer een beheerder van de organisatie je bench-gebruiker verwijdert, wordt de bench meteen mee verwijderd:

  • Hij stopt direct en je kunt hem niet meer openen, niet in de browser en niet met fremforge bench attach.
  • Het profielvolume wordt 30 dagen bewaard. Gedurende die 30 dagen kan een beheerder van de organisatie de verwijdering ongedaan maken op de beheerpagina Benches van de organisatie. Dan komt de bench terug zoals hij was, slapend, op dezelfde schijf, met jouw gebruiker.
  • Na 30 dagen wordt het profielvolume verwijderd. Het kan niet opnieuw worden gekoppeld of hersteld, en een nieuwe bench begint altijd met een leeg profiel.

Neem dus mee wat je wilt bewaren zolang je de bench nog hebt, bijvoorbeeld voordat je een project of de organisatie verlaat. Is hij al verwijderd, vraag dan een beheerder van de organisatie om de verwijdering binnen de 30 dagen ongedaan te maken, kopieer je bestanden zoals hieronder beschreven en laat hem daarna opnieuw verwijderen.

Er is geen scp, rsync of SSH naar een bench: hij heeft geen inkomend netwerkpad, en fremforge bench attach geeft je een terminal, geen bestandsoverdracht. Wat je meeneemt, gaat via frem.sh naar buiten, op een van de drie manieren hieronder.

Je werk pushen

Code hoort in git, en de bench heeft al een git-credential voor frem.sh. Zo vind je elke repository onder je homedirectory met iets wat nog niet is gepusht (niet-gecommitte wijzigingen, of commits op een branch die op geen enkele remote staat):

find ~ \( -name node_modules -o -name .cache \) -prune -o -name .git -print 2>/dev/null |
while read -r g; do
  r=$(dirname "$g")
  if [ -n "$(git -C "$r" status --porcelain)" ] ||
     [ -n "$(git -C "$r" log --branches --not --remotes --oneline -1)" ]; then
    echo "not pushed: $r"
  fi
done

Commit en push ze stuk voor stuk. Kun je niet pushen naar de branch waarop je zit, push dan naar een eigen branch (git switch -c wip/<topic>, daarna git push -u origin HEAD). git stash list toont stashes, die een push niet meeneemt.

Al het andere: een privérepository

Dotfiles, notities en kladbestanden die bij geen enkele repository horen, kunnen in een eigen privérepository. Maak er een aan in je organisatie via de webinterface van frem.sh (Nieuwe repository, zichtbaarheid Privé), bijvoorbeeld bench-files-<your-login>. Kun je geen repository’s aanmaken in de organisatie, vraag het dan aan een eigenaar van de organisatie. Daarna, op de bench:

mkdir ~/bench-files && cd ~/bench-files
cp -a ~/.bashrc ~/.tmux.conf ~/notes .   # whatever you want to keep
git init -b bench-files
git add -A
git commit -m "Files from my bench"
git remote add origin https://frem.sh/<org>/bench-files-<your-login>.git
git push -u origin bench-files

De branch heet bench-files in plaats van main, zodat de branchbeveiliging van je organisatie, die standaard main dekt, de push niet weigert. Op je eigen machine:

git clone -b bench-files https://frem.sh/<org>/bench-files-<your-login>.git

Twee dingen die je niet moet kopiëren:

  • ~/.git-credentials en ~/.config/fremforge/token. Die zijn voor de bench aangemaakt, worden ingetrokken wanneer hij verdwijnt en werken nergens anders.
  • Je eigen secrets, zoals private SSH-sleutels of credentials voor een cloud-CLI. Iedereen met toegang tot de repository kan ze lezen, ook de eigenaren van de organisatie. Maak in plaats daarvan nieuwe aan op je volgende machine.

Git is niet geschikt voor grote binaire bestanden, dus beperk de repository tot wat je echt nodig hebt.

Eén klein bestand: download het in je browser

Voor één klein bestand is er een kortere weg via Doorgestuurde poorten. Pak wat je wilt in één bestand in en serveer de directory ervan:

mkdir -p ~/outbox
tar -czf ~/outbox/dotfiles.tar.gz -C ~ .bashrc .tmux.conf
cd ~/outbox && python3 -m http.server 8000

Poort 8000 verschijnt onder Doorgestuurde poorten. Open hem, klik op het bestand om het te downloaden en stop daarna de server met Ctrl-c. Een doorgestuurd antwoord is begrensd op 8 MB, dus dit werkt alleen voor kleine bestanden; gebruik voor alles wat groter is een repository.

Een agent draaien

Codex en opencode zijn vooraf geïnstalleerd. Beide hebben een opensourcelicentie, dus leveren we ze mee.

Claude Code is niet vooraf geïnstalleerd, en de reden is een licentie, geen vergissing: de voorwaarden ervan zijn geen opensourcelicentie, en dit is een product dat we verkopen, dus meeleveren zou het herdistribueren van propriëtaire software zijn. Het is één commando, onder je eigen overeenkomst met Anthropic:

frembench-install-claude-code
claude

Het wordt geïnstalleerd vanuit het openbare npm-register via de egress-proxy van de bench, net als elk ander pakket dat je op de bench installeert. Dit doe je maar één keer: de installatie en de aanmelding staan op je profielvolume.

Geen telemetrie van de vooraf geïnstalleerde tools. Gebruiksrapportage en updatecontroles staan uit voor de agents en tools waarmee een bench komt (OpenChamber, opencode, Codex, Mistral Vibe, Claude Code als je het installeert, en de cloud-, build- en pakkettools), en elke build van het bench-image controleert dat. Een paar tools halen nog inhoud op die ze nodig hebben om te werken, geen gegevens over jou: de modellenlijst van opencode, de plugincatalogus van Codex en de versiecontrole van de Azure CLI bij de eerste start. Wil je de rapportage van een tool weer aanzetten, stel dan zelf de variabele ervan in.

Meerdere dingen tegelijk draaien

De terminal van je bench is geen kale shell: hij koppelt aan een tmux-sessie met de naam frembench:

tmux new-session -A -s frembench

Daardoor overleeft een agent het dichtklappen van je laptop, en zo draai je er ook meerdere tegelijk. De prefixtoets is de standaard Ctrl-b, en de muis staat aan.

ToetsenWat het doet
Ctrl-b cNieuw venster: start hier een tweede agent
Ctrl-b n / Ctrl-b pVolgend / vorig venster
Ctrl-b 0 … Ctrl-b 9Direct naar een venster springen
Ctrl-b wKiezen uit een lijst met vensters
Ctrl-b ,Het huidige venster hernoemen; de moeite waard, geef ze een naam per taak
Ctrl-b %Splitsen in panelen naast elkaar
Ctrl-b "Splitsen in panelen boven elkaar
Ctrl-b zEén paneel schermvullend maken, en terug
Ctrl-b dLoskoppelen: alles blijft draaien

Een tweede browsertabblad spiegelt; het splitst niet af. Elke verbinding gaat naar dezelfde sessie frembench, dus twee tabbladen tonen hetzelfde venster en zitten elkaar in de weg. Gebruik vensters en panelen voor parallel werk, geen extra tabbladen.

Wil je toch twee tabbladen die verschillende dingen tonen, geef het tweede dan een eigen weergave van dezelfde vensters:

Ctrl-b :  new-session -t frembench -s second
Ctrl-b :  switch-client -t second

-t frembench groepeert de nieuwe sessie met de oorspronkelijke, zodat beide dezelfde vensterlijst zien maar elk op een ander venster kan staan. Een net geopend tabblad komt altijd op frembench uit, dus je geeft switch-client per tabblad opnieuw.

Twee details die mensen verrassen:

  • Een nieuw venster is een gewone login-shell. ~/.frembench/startup draait alleen wanneer de sessie voor het eerst wordt aangemaakt, dus niet opnieuw per venster.
  • Tabbladen van verschillende grootte maken elkaar niet kleiner. aggressive-resize staat aan, dus een venster krijgt de afmetingen van de client die er echt naar kijkt, niet van de kleinste die verbonden is.

Een dev-server openen in je browser

Een bench heeft geen inkomend netwerkpad. Niets op internet kan hem bereiken, en dat is geen beperking die we van plan zijn op te heffen: het is de reden dat de verbindingsroute verdedigbaar is.

Dev-servers werken nog steeds. Start er een zoals je gewend bent:

npm run dev

Binnen een paar seconden verschijnt de poort onder Doorgestuurde poorten: een eigen kaart op de frembench-pagina, onder Holds; onder de shell op de schermvullende terminalpagina. Klik erop. De verbinding loopt uitgaand over hetzelfde kanaal als je terminal; er wordt geen poort opengezet en er komt geen tunnelprogramma aan te pas.

De kaart toont niet alleen waar er geluisterd wordt, maar ook wat er luistert:

PoortService
5173node
8000python3

Een paar dingen om te weten:

  • Alleen poorten waarop je bench echt luistert, worden aangeboden. Je kunt niet om een willekeurige poort vragen, en niets anders dat een link heeft ook niet.
  • De kolom Service toont de eigen korte naam van het proces, uitgelezen op de bench: node in plaats van vite, want zo noemt het proces zichzelf. Er staat Onbekend bij een poort waarvan het proces niet kon worden vastgesteld, en op een bench met een image van voor deze functie; die pikt het op bij de volgende keer wakker worden.
  • Een server die alleen aan het privéadres van de bench is gebonden, wordt niet getoond, omdat doorsturen ernaar zou mislukken. Bind aan localhost of 0.0.0.0.
  • SSH wordt nooit aangeboden. Gebruik de terminal.
  • Hot reload werkt. Een doorgestuurde pagina wordt geserveerd vanaf de eigen origin van je bench, en een WebSocket die vanaf die origin wordt geopend, gaat ook mee; dat is precies wat het live-reloadkanaal van een dev-server nodig heeft. Hier stond eerder dat het niet werkte; dat was geschreven voordat de origin per bench bestond en bleef staan nadat die er kwam.

Zo bereik je ook een web-UI voor agents, zoals OpenChamber. Die is op elke bench geïnstalleerd en start bij elke keer wakker worden op poort 3000, achter een wachtwoord dat voor je bench is aangemaakt (OPENCHAMBER_UI_PASSWORD in ~/.frembench/openchamber.env): open die poort. Draai geen openchamber tunnel: dat is een Cloudflare-tunnel, en de doorsturing hierboven is zowel de soevereine route als de route die je al authenticeert.

De API-credential op een bench

Een bench authenticeert zich bij frem.sh met twee credentials, en weten welke welke is, scheelt je een middag.

CredentialWaarWat het bereikt
Git-credential~/.git-credentialsgit clone / push / pull, en de eigen API van Forgejo op /api/v1/…
API-credential~/.config/fremforge/tokende fremforge-API op /_app/api/v1/…

Beide worden door het platform voor je aangemaakt. Je maakt ze niet aan, plakt ze niet en vernieuwt ze niet, en je moet ze niet vervangen door een persoonlijk token.

Hij wordt bij elke keer wakker worden aangemaakt

De API-credential is een ffp_…-token dat wordt aangemaakt wanneer je bench start, ongeveer een dag geldig is en wordt ingetrokken wanneer de bench wordt opgeschort. Bij de volgende keer wakker worden wordt een nieuw token aangemaakt. Daarom is het veilig dat het op het profielvolume staat: een token dat van een afgedankte schijf wordt gelezen, is al ingetrokken.

Het praktische gevolg: een wijziging in wat je bench mag, gaat in bij de volgende keer wakker worden, niet meteen. Is er net een mogelijkheid voor je aangezet en weigert de API nog steeds, schort de bench dan op en maak hem wakker voordat je een bug meldt.

Hij handelt als jou, met een beperkter bereik

Het token is gekoppeld aan jouw identiteit, niet aan een organisatie. Elk verzoek wordt nog steeds gecontroleerd tegen je werkelijke rechten in organisaties, dus een bench kan nooit een organisatie bereiken die je vanaf je laptop niet kunt bereiken.

Wat het bewust niet heeft: facturatie, SSO-configuratie, wijzigingen van gebruikers en de mogelijkheid om verdere tokens aan te maken. Dat zijn de scopes waarvan de gevolgen het weggooien van de bench zouden overleven. Al het andere wat een bench dagelijks nodig heeft (organisaties, runners, bevindingen, SBOM’s, auditlogs lezen, updates van afhankelijkheden, deploymentomgevingen en secrets, en het starten en downloaden van een data-export) is inbegrepen.

403 Token lacks required scope '…' vanaf een bench betekent dat het endpoint bestaat en dat de credential van je bench die scope niet heeft. Het betekent niet dat de functie ontbreekt. De formulering wordt makkelijk gelezen als “zo’n endpoint bestaat niet”; controleer de scope voordat je iets over de API concludeert.

Eigenaren van een organisatie kunnen de API-credential van benches voor de hele organisatie uitzetten in beheer → Authenticatiebeleid. Standaard staat hij aan.

Gebruik

curl -fsS https://frem.sh/_app/api/v1/orgs/<your-org>/environments \
  -H "Authorization: Bearer $(cat ~/.config/fremforge/token)"

Let op het voorvoegsel /_app. Het kale pad /api/v1/… is de eigen API van Forgejo, die dit token niet accepteert, en de foutmelding citeert het token dat je stuurde. Plak de uitvoer van een mislukte aanroep dus niet in een ticket of een chat.

Opschorten, wakker worden en waarvoor je betaalt

Je betaalt voor de minuten dat je bench wakker is. Een opgeschorte bench kost alleen zijn profielvolume, dus het loont om precies te weten wat hem wakker houdt.

Wat hem wakker houdt

Je bench blijft actief zolang een van deze dingen waar is:

  • Iemand is verbonden: een browsertabblad of een SSH-sessie die echt verbonden is.
  • Een agent is aan het werk. Niet alleen actief: zie hieronder.
  • Je hebt hem wakker gehouden via de bench-pagina.

Geldt geen van deze, dan wordt de bench na 30 minuten opgeschort.

Wat “een agent is aan het werk” betekent

Een agent die bij een prompt wacht, is niet aan het werk, en dit onderscheid bepaalt je rekening. Een Claude-sessie die ’s nachts open blijft staan, lijkt volgens elke naïeve maatstaf bezig: hij gebruikt nog steeds ongeveer 1% van een CPU. Daarom beslissen we niet op CPU alleen.

Een agent telt als aan het werk wanneer een van deze dingen waar is:

  • hij heeft in de laatste 10 minuten naar zijn eigen sessiegeschiedenis geschreven, of
  • hij of iets wat hij heeft gestart, gebruikt minstens 10% van een CPU-core.

Het tweede bestaat voor lange tool-aanroepen. Start je agent een build van een half uur, dan schrijft hij een half uur niets terwijl hij wacht, maar de compiler die hij startte is bezig, dus de bench blijft actief.

Een agent die echt niets doet, houdt je bench dus ongeveer 10 minuten na zijn laatste activiteit niet meer vast, en de bench wordt ongeveer 30 minuten daarna opgeschort: grofweg 40 minuten na je laatste interactie, als niets anders hem vasthoudt.

Het enige geval dat je ons moet laten weten

Een lange taak die je zelf hebt gestart, niet via een agent, houdt de bench niet wakker. Een make -j, een data-import, een duurtest: start je die in een shell en klap je je laptop dicht, dan wordt de bench eronder opgeschort.

Dat is bewust. Als elk druk proces een machine wakker zou houden, kon een inactieve bench door wat dan ook eindeloos blijven factureren, en het goedkoopste om op andermans machine te draaien is een cryptominer. De regel is dus dat wij alleen werk meetellen dat we aan een agent kunnen toeschrijven, en dat al het andere jouw beslissing is: houd de bench wakker, en zet dat weer uit wanneer de taak klaar is.

Verbonden blijven werkt ook, omdat een verbonden client zelf al de bench wakker houdt.

Wakker worden gaat automatisch: maak verbinding en hij komt terug. Je bestanden staan waar je ze hebt achtergelaten, en de indeling van je terminal komt mee terug: de vensters die je open had worden in dezelfde directory’s opnieuw aangemaakt, en Claude, Codex, opencode en OpenChamber worden opnieuw gestart, elk hervat in de sessie waarin ze zaten, wachtend bij een prompt. Er wordt niets voor je opnieuw afgespeeld; een agent doet niets terwijl je weg bent.

Twee dingen komen niet terug. Een sessie die zonder hervatbare id is gestart, komt terug als een nieuwe sessie in de juiste directory, en elk ander langlopend proces, zoals je eigen dev-server of een build, wordt niet opnieuw gestart. Zet het in ~/.frembench/restore-commands.txt, één commandonaam per regel, als je dat wel wilt.

Houd een bench wakker via de bench-pagina wanneer je een lange taak hebt die onze meting niet ziet. Wakker houden is niet permanent: een bench die te lang niet is herbouwd, wordt hoe dan ook bijgewerkt, omdat een niet-bijgewerkte machine op internet niet iets is wat je met wakker houden zou moeten kunnen kopen.

Er een krijgen

Dev benches worden per tenant ingeschakeld. Heeft je organisatie ze, dan staat de pagina onder Instellingen → Dev benches; zo niet, dan meldt die pagina dat. De beheerder van je organisatie bepaalt hoeveel benches je tenant tegelijk mag draaien.

Eén bench per organisatie

Een bench hoort bij een organisatie, niet bij jou. Ben je lid van meerdere organisaties met bench-gebruikers, dan krijg je in elk daarvan één bench: aparte machines, aparte profielen, apart gefactureerd aan de organisatie die de gebruiker heeft toegekend. Je kunt geen bench aanmaken in een organisatie die geen bench-gebruikers heeft gekocht, dus geen enkele organisatie kan worden gefactureerd voor een machine waarmee ze niet heeft ingestemd.

Profielen gaan niet met je mee tussen organisaties. Elke bench heeft zijn eigen profielvolume, dus de tools, shellconfiguratie en credentials die je op de ene bench installeert, bestaan niet op een bench in een andere organisatie. Richt elke bench die je gebruikt apart in.

Dit is een gevolg van de grens tussen tenants, geen beperking die we van plan zijn op te heffen: een gedeeld profiel zou betekenen dat de ene organisatie betaalt voor de opslag van het werk van een andere, en zou bestanden over een grens heen brengen waarop klanten vertrouwen.

Benches worden onafhankelijk van elkaar opgeschort na een half uur inactiviteit, dus benches in meerdere organisaties houden niet meerdere machines draaiende: alleen de bench die je echt gebruikt, blijft wakker.

Waarom Claude Code niet vooraf is geïnstalleerd

De image van de bench levert codex (Apache-2.0) en opencode (MIT) gebruiksklaar mee. Claude Code is niet vooraf geïnstalleerd, en dat is een licentiebeslissing, geen vergissing: de licentie is niet open source, en frembench is een product dat we verkopen. Het in onze image meeleveren zou betekenen dat we het herdistribueren als onderdeel van iets waarvoor we geld vragen.

Zelf installeren is één commando, en daarna draait het onder jouw overeenkomst met Anthropic in plaats van de onze. Daarom overleeft het ook het opschorten: je profielvolume bewaart het, dus je installeert het één keer per bench.

Dit is dezelfde regel die overal in het product geldt: afhankelijkheden die wij meeleveren zijn soeverein, actueel en volledig open source gelicentieerd. Alles wat niet aan die eis voldoet, neem je zelf mee; wij bundelen het niet.