the problem I had⌗

I’ve worked in a small team operating a large ‘fleet’; 20+ microservices, with one or two of us on maintenance. When a critical CVE landed, I was the one hand-editing go.mods, Dockerfiles and pipelines repo by repo to ship the patched build, or worse, missing a couple and watching the fleet silently rot. Every existing answer was either imperative one-shot scripting (run a script across repos, forget what “correct” was), dependency-only bots, or a platform we’d have to staff.

I didn’t want that to ever be my week again. So I chose to build the tool I wished I’d had.

what elostirion is⌗

Elostirion was the tallest and westernmost of the three White Towers that holds the master seeing-stone. One binary that watches all the repos. The name chose itself.

I’m building elostirion to be a desired-state management for ‘fleets’ of repositories. You declare what every service must look like; language version, base image, required files, and eventually pipeline shape, env contract, Terraform module versions, in one fleet-spec.yaml. The tool then closes the loop.

verify gates every repo in CI against the spec (exit codes, JUnit, SARIF; zero credentials needed for local mode), scan sweeps the whole fleet and names exactly who digresses and why, plan shows the precise diffs that would fix each repo, and apply opens the PRs that converge them, without cloning.

why it wins⌗

The core bet is declarative over imperative. A script fixes the fleet once and forgets what “correct” was; the spec is the memory, so the drift that shows up next month is caught by the same rule that fixed it this month. Think kubectl-apply for repos, not xargs. And it closes the whole loop — detect, gate, diff, PR — in one tool.

Everything else in this space picks one quadrant. multi-gitter, git-xargs and turbolift are great execution plumbing, but they’re imperative one-shots: no spec, no memory, no gate. Renovate and Dependabot stop at dependency bumps (run them alongside; they won’t converge a Dockerfile or a pipeline). cruft and copier sync template checksums, so repos that never shared a scaffold are out of reach. elostirion checks contracts extracted from file contents, so heterogeneous repos still converge. Backstage-style scorecards observe but never open the fixing PR.

elostirion sits in the intersection nobody occupies: declare the fleet, verify it in CI, open the PRs that make it so, one OSS binary.

It’s also deliberately boring to run. No server, no operator, no SaaS, no platform team to staff. In CI it behaves like a good citizen; exit codes, JUnit for Bitbucket’s test UI, SARIF for GitHub PR annotations, and every rule carries a severity plus a grace_until date, so a new fleet-wide policy warns for a while before it starts blocking merges. You can roll out a rule without breaking twelve pipelines in one morning.

Under the hood it stays small on purpose. The pieces (pkg/model, pkg/scan, pkg/reconcile, pkg/forge) are importable, so the fleet model can power other internal tools. And on GitHub, apply never clones: it writes tree → commit → ref → PR straight through the Git Data API. Fast, stateless, runs from a tiny CI container, and every commit comes back API-verified.

where it stands⌗

verify, scan, plan, and apply work today, with Go, Python, and Dockerfile scanners.

terminal recording of elo catching drift across a demo fleet
elo catching drift across a demo fleet

Terraform drift detection, the vacancy driftctl left behind, is next in the implementation pipeline, alongside Bitbucket/GitLab backends and more scanners. view planned improvements

elostirion is a hobby project born from real ops pain. The repo is github.com/whoisnjoguu/elostirion if you’d like to work on this too, and make it into a tool you love to use.

I’ll be building and maintaining this in public.

@CtrlAltEng on X

@CtrlAltEng — come say hi.