Op hol geslagen CI
Een coding-agent die in een lus pusht, runs opnieuw start of pull requests opent, kan je runnerminuten in een paar uur opmaken, en niets waarschuwt je tot de e-mail bij 80% verbruik. fremforge let daarop.
Wat er wordt gemeten
Elke 5 minuten bekijkt fremforge voor elke organisatie de Actions-runs van het afgelopen uur (60 minuten) op de gehoste runners, en meet:
| Signaal | Wat | Grens |
|---|---|---|
| Runs per persoon | Runs die één persoon in de organisatie startte | Boven 3 keer het drukste normale uur van die persoon, en nooit onder 80 |
| Runnerminuten per persoon | Runnerminuten die die runs gebruikten | Boven 3 keer het drukste normale uur van die persoon, en nooit onder 600 |
| Pushes naar één pull request | Verschillende commits die één persoon naar één pull request pushte | Meer dan 12 |
“Het drukste normale uur van die persoon” is het uur op het 99e percentiel over de afgelopen 14 dagen, eenmaal per dag opnieuw berekend. Een persoon met minder dan 20 actieve uren in die periode wordt in plaats daarvan gemeten tegen het drukste normale uur van de organisatie. Een team waarvan de agents de hele dag CI draaien, wordt dus gemeten tegen zijn eigen normaal, niet tegen dat van een rustig team.
De grens voor pull requests telt pushes, geen runs: één push start zoveel runs als de repository er workflows voor heeft.
Het gaat altijd om een persoon. Een run die een agent namens iemand start, is de run van die persoon (de gebruiker die de run startte), en er zijn geen agentaccounts. Bots, zoals Renovate, worden op dezelfde manier gemeten en als bot gemarkeerd. Runs die fremforge zelf start, zoals het verversen van lockfiles, worden niet gemeten.
Kalibratie
De grenzen zijn vastgesteld op een maand CI waarin de meeste runs van coding-agents komen. Afgespeeld door de detector levert die maand geen enkele op hol geslagen CI op zodra elke persoon 14 dagen geschiedenis heeft.
Wat er gebeurt
Gaat een waarde over haar grens, dan legt fremforge eenmalig een geval van op hol geslagen CI vast:
- Een e-mail aan elke eigenaar van de organisatie, met de persoon, de plek (de organisatie of één pull request) en de cijfers.
- Een e-mail aan de persoon van wie de runs zijn, aan hem of haar gericht, zodat die de sessie kan stoppen. Niet voor een bot, en een eigenaar van wie de runs zijn, krijgt één e-mail, niet twee.
- Een event
ci.runawayop de eventfeed, één per repository waarin de runs staan, zodat een agentsessie die de feed leest het ook ziet. - Een auditevent (
ci_runaway.detected). - Een regel op de pagina CI-gebruik (zie In de console).
Zolang de waarde boven de grens blijft, wordt het geval ververst, maar niet opnieuw gemaild. Het eindigt vanzelf na 60 minuten onder de grens.
Er wordt niets gestopt, tenzij je organisatie de pauze heeft aangezet.
De pauze (optioneel)
Met de pauze aan zorgt een geval van op hol geslagen CI er ook voor dat de runners van fremforge geen nieuwe runs van die persoon meer starten, of bij een geval op een pull request: geen nieuwe runs van die persoon op die pull request, totdat een beheerder het hervat. De pauze staat standaard uit.
Wat de pauze nooit doet:
- Ze annuleert nooit iets. Een vastgehouden run wacht in de wachtrij, wordt op Verkennen → Actions als gepauzeerd getoond en start binnen enkele seconden na het hervatten.
- Ze stopt nooit een run die al is begonnen. Een run waarvan al een job draait, loopt door, inclusief zijn latere jobs.
- Ze houdt nooit iemand anders tegen. Alleen runs die door de gepauzeerde persoon zijn gestart (op de gepauzeerde pull request), wachten.
- Ze faalt open. Kan fremforge de pauze niet lezen, dan starten runs zoals gewoonlijk.
Ze houdt alleen de gehoste runners van fremforge tegen. Een runner die je organisatie zelf draait, kan de job nog steeds oppakken.
Een gepauzeerd geval eindigt niet vanzelf. Een eigenaar hervat het, of zet de pauze uit, waarmee alle gepauzeerde gevallen tegelijk worden hervat. Na het hervatten wordt dezelfde persoon 60 minuten lang niet opnieuw gemarkeerd.
De geplande workflows van Forgejo (de gebruiker forgejo-actions) worden gemeten en er wordt voor gewaarschuwd, maar ze worden nooit gepauzeerd.
In de console
Eigenaren van de organisatie vinden gevallen van op hol geslagen CI onder Bouwen en uitrollen → CI-gebruik, sectie Op hol geslagen CI (https://frem.sh/<org>/_admin/ci-usage#runaways): eerst de pauzeschakelaar, daarna elk geval met de persoon, de plek, het drukste uur, de status en een knop Hervatten (of Negeren). Een banner boven aan de pagina laat zien wanneer er een actief is.
API
Het token heeft runners:read nodig om op te vragen en runners:write om te hervatten of de pauze om te zetten. Elke wijziging wordt geaudit op naam van de persoon namens wie de aanroeper handelt.
# List (state=live for open and paused only)
curl https://frem.sh/_app/api/v1/orgs/<org>/ci-runaways \
-H "Authorization: Bearer $FREMFORGE_TOKEN"
# Turn the pause on (or off: off resumes every paused runaway)
curl -X PUT https://frem.sh/_app/api/v1/orgs/<org>/ci-runaways/settings \
-H "Authorization: Bearer $FREMFORGE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"pause": true}'
# Resume one (or close an open one)
curl -X POST https://frem.sh/_app/api/v1/orgs/<org>/ci-runaways/<id>/resume \
-H "Authorization: Bearer $FREMFORGE_TOKEN"Een geval in de lijst:
{
"id": "4f0c…",
"status": "paused",
"scope": "pr",
"person": "alice",
"person_kind": "person",
"repo": "api",
"pr_number": 42,
"signals": ["pr_pushes"],
"runs": 48,
"heads": 16,
"minutes": 0,
"detected_at": "2026-10-25T09:40:00.000Z",
"paused_at": "2026-10-25T09:40:00.000Z",
"resumed_at": null
}status is open (gemeld), paused, ended of resumed. De MCP-server toont ze met list_ci_runaways.
De lus zelf stoppen
De melding vertelt je wiens werk in een lus zit; de sessie is van die persoon. Stop de agentsessie, of trek het token in dat ze gebruikt. Bij tokens die namens iemand handelen, stopt het intrekken van het gedelegeerde token die sessie zonder het andere werk van de persoon te raken.