Dry-run als standaard: CLI-tools die je durft te draaien
Waarom een CLI die mail verwijdert, records bijwerkt of bestanden verplaatst standaard alleen moet laten zien wat hij zou doen, en hoe je dat netjes bouwt.
Een command-line tool is snel, scriptbaar en gevaarlijk. Eén verkeerd filter en een opruimcommando raakt duizend records in plaats van tien. In een webinterface zie je dat misschien nog aankomen; in de terminal ben je het kwijt voordat je het doorhebt.
De oplossing is simpel en wordt toch vaak overgeslagen: laat destructieve commando’s standaard alleen zien wat ze zouden doen, en voer pas uit met een expliciete vlag.
Plan en uitvoering scheiden
Het patroon heeft twee stappen. Eerst bereken je een plan: een lijst van concrete acties. Daarna toon je dat plan, of voer je het uit. Omdat beide paden hetzelfde plan gebruiken, ziet de gebruiker in de dry-run precies wat er met --apply zou gebeuren.
import argparse, json, sys
def build_plan(messages, older_than_days):
return [
{"action": "archive", "id": m["id"], "subject": m["subject"]}
for m in messages
if m["age_days"] > older_than_days and not m["starred"]
]
def main(argv=None):
p = argparse.ArgumentParser(prog="tidy", description="Archiveer oude mail.")
p.add_argument("--older-than", type=int, default=90, metavar="DAGEN")
p.add_argument("--apply", action="store_true", help="voer de acties echt uit (standaard: dry-run)")
p.add_argument("--json", action="store_true", help="plan als JSON, voor scripts")
args = p.parse_args(argv)
plan = build_plan(load_messages(), args.older_than)
if args.json:
print(json.dumps({"apply": args.apply, "actions": plan}))
else:
for a in plan:
print(f"{'ARCHIVE' if args.apply else 'would archive'} {a['subject']}")
print(f"\n{len(plan)} acties" + ("" if args.apply else " (dry-run; gebruik --apply om uit te voeren)"))
if args.apply:
failed = [a for a in plan if not execute(a)]
return 1 if failed else 0
return 0
if __name__ == "__main__":
sys.exit(main())
De details die het verschil maken
- De default is veilig. Wie de tool voor het eerst draait, kan niets kapotmaken. Dat verlaagt de drempel om hem te gebruiken.
- De dry-run is eerlijk. Hetzelfde plan voor beide paden; geen aparte “simulatie”-code die kan afwijken van wat er echt gebeurt.
- Het aantal staat erbij. “1.204 acties” valt op als je er twintig verwachtte.
--jsonvoor automatisering. Een script of CI-job kan het plan inspecteren voordat het--applyaanroept.- Exit codes kloppen. 0 bij succes, niet-nul als een actie mislukte, zodat een cron-job of pipeline het merkt.
Waar AI in beeld komt
Het patroon wordt belangrijker zodra een taalmodel de beslissingen voorbereidt. In CtrlGmail categoriseert de tool mail en extraheert hij taken; opruimen en uitschrijven tonen eerst wat er zou gebeuren en wijzigen pas iets in Gmail met --apply. Een model dat een categorie verkeerd inschat, levert zo een verkeerde regel in een rapport op, geen verwijderde mail.
Dat is de algemene les voor AI-automatisering: laat het model voorstellen doen, en houd het uitvoeren expliciet en controleerbaar.