By Vicente Arteaga Gomez
MisLinux · Last updated: May 5, 2026
This is part of my Kubernetes-on-Hetzner-and-operations series on MisLinux. It comes from repeated operator work, not from a vendor playbook.
I used to use the phrase "just a quick script" as if it reduced the risk.
It did not.
The script still:
- touched real data
- encoded assumptions
- created artifacts someone would rely on later
- became copy-paste material for the next incident
At some point I stopped calling these scripts disposable. I started treating them as source code that merely had a short original deadline.
The rule I use now
If a script is important enough to run once against real operational data, it is important enough to deserve:
| Minimum standard | Why it matters |
|---|---|
| DRY helpers | avoid re-deriving parsing and transport logic later |
| tests | catch the obvious contract breaks before the next rerun |
| CIR notes | preserve why the workflow exists in this shape |
| saved artifacts | prove what happened on that run |
That does not mean every script needs a huge framework. It means the script should stop pretending it is exempt from engineering standards.
What changed my mind
The real problem was not the first run. The first run usually works well enough.
The problem was the second and third run:
- slightly different data
- slightly different date window
- slightly different production state
- slightly different operator
That is where "ad hoc" turns into "mysterious legacy."
A script can be short and still be real code
I do not need a large package structure before I apply discipline.
Even a small automation helper can be structured like this:
script entrypoint
-> parse arguments
-> call a shared library/helper
-> write artifacts
-> exit non-zero on real failure
That shape makes testing possible and keeps the second script from re-implementing the same logic a week later.
A concrete command trail I prefer
# Good: deterministic rerun with explicit output folder
php operations/example/report.php \
--input artifacts/source.json \
--output history/20260505-example-run/
# Good: test the shared logic separately
vendor/bin/phpunit tests/example/ReportBuilderTest.php
# Better: use the exact same helper from the next automation layer
php operations/example/next-stage-proof.php --from history/20260505-example-run/
This is much safer than three unrelated shell fragments that happen to work today.
The subtle benefit: better failure messages
Once I treat the script like real software, I also stop accepting vague operator output.
I want errors that explain:
- what input was missing
- what upstream state was unexpected
- which artifact path contains the evidence
That matters more than people think. A one-off script with useless errors becomes a slow manual process again the moment it fails.
Failure case: the fake one-off
The fake one-off script usually looks like this:
- one file
- mixed fetching, parsing, mutation, and reporting
- hardcoded ids or paths
- no test seam
- no artifact contract
Then somebody asks for the same run with a new date range or a new target, and now it has to be reverse-engineered from scratch.
Why this matters more with AI-assisted workflows
AI agents are extremely good at making a one-off script "work."
They are much less useful if the script:
- hides its assumptions
- cannot be re-run deterministically
- has no tests
- has no saved evidence
That is why I now want the script to be reusable before I want it to be clever.
My current checklist for a so-called ad-hoc script
Before I accept it, I want:
- a small shared library if parsing or transport logic may recur
- at least one unit test around the risky part
- an output directory or artifact contract
- one CIR note explaining why the script exists and what would go wrong if someone "simplified" it blindly
If it touches production directly, I want even more proof than that.
What I'd do differently now
I used to optimize for speed on the first run and structure on the second run. What I would do differently now is merge those decisions: build the smallest reusable version first. It is usually only slightly slower at the beginning and much faster after that.