← cd ../blog

I Built an Ansible Replacement in Rust. Was It Needed? Probably Not. Here's Why I Did It Anyway.

Why I wrote glidesh — a stateless, SSH-only infrastructure automation tool — and what reproducibility has to do with it.

| 7 min read
#rust #infrastructure #devops #automation #reproducibility

Also published on Medium

I want to be upfront: the world did not need another configuration management tool. Ansible works. It has a massive ecosystem, a decade of battle-testing, and a community that can answer almost any question you throw at it. If Ansible is working for you, this post is not going to tell you you’re wrong.

But there’s a particular itch it never quite scratched for me — and after years of working around it, I decided to scratch it myself. The result is glidesh: a fast, stateless, SSH-only infrastructure automation tool built in Rust. Version 0.3.0 is out now.

The Itch

I’m a Bazel user. I’m a Nix user. The idea that the same inputs should produce the same outputs, every time — that’s not a nice-to-have for me, it’s a foundational principle. When I write a build rule, I expect it to behave identically on my laptop, in CI, and on a coworker’s machine six months from now. When it doesn’t, I consider that a bug in the tooling.

And then I’d switch contexts to infrastructure work and open an Ansible playbook. The contrast was jarring.

Ansible carries a lot of accumulated weight. The Python runtime dependency on both control node and targets. The implicit state management through facts and caching that creates behavior you can’t easily predict. And YAML — YAML as a programming language — where playbooks end up simultaneously too verbose and too implicit.

None of these are dealbreakers alone. But together they widen the gap between “what I specified” and “what actually happens” past what I’m comfortable with.

What glidesh Actually Is

Infrastructure automation stripped to its essential mechanics.

You define an inventory of hosts in KDL. You write plans describing desired state. You run glidesh run and it connects over SSH, checks what needs to change, and applies only the delta. No agent on the target. No runtime dependency. No state file. Just a single Rust binary and SSH access.

The core abstraction is a two-phase check/apply pattern. Every module first inspects the target’s current state. If it already matches the declaration, the module reports Satisfied and moves on. If not, it applies the change. Plans are idempotent by construction — run them ten times and only the delta gets applied.

Here’s a concrete example:

plan "setup-web" {
    target "web"

    step "Install nginx" {
        package "nginx" state="present"
    }

    step "Start nginx" {
        systemd "nginx" {
            state "started"
            enabled #true
        }
    }
}

That’s the entire plan. No boilerplate preamble, no become: yes scattered everywhere, no --- at the top of the file.


Notice enabled #true in that snippet. In KDL, #true is unambiguously a boolean. Quoted values are strings. There is no other interpretation. Compare that to the equivalent YAML:

enabled: yes    # bool? string? depends on your parser version
enabled: "yes"  # definitely string, but now you're fighting the language
enabled: True   # also bool, but differently capitalized than yes

If you’ve ever had a production incident because YAML silently coerced no into false or turned a version number like 3.10 into 3.1, you already understand why this matters. KDL removes the ambiguity entirely — the syntax makes intent explicit, so the tool and the author always agree on what was written.


Design Decisions

Stateless — for now. Desired state is computed fresh every run by diffing the plan against what the target reports. The machine is the source of truth for current state; the plan file is the source of truth for desired state. The tool closes the gap. That said, I’m not ideological about this — tracking what changed, when, and by whom has real value. A future version may introduce optional state tracking. But starting without it felt right: simpler mental model, fewer moving parts, and you can always add state later. Taking it away is harder.

No agent, no runtime. If the target has SSH and a shell, glidesh can manage it. Nothing to install, nothing to keep in sync on the remote side. This is the same philosophy that made Ansible attractive — glidesh just drops the Python dependency from both ends.

Sync and async execution. Sometimes all hosts must finish step N before any starts step N+1 (database migration before app deploy). Sometimes you want maximum throughput with each host running independently. Both modes are supported, selectable per-plan or overridable on the CLI.

Plugins via stdio. Custom modules are standalone executables speaking a JSON protocol over stdin/stdout. Write them in any language. Same check/apply contract. No SDK, no framework — just read JSON in, write JSON out.

Why It Feels Fast

I’m not going to throw made-up benchmark numbers at you. “10x faster” claims without methodology are the kind of thing that makes me distrust a project, not adopt it.

What I can explain is the architectural difference. Ansible forks Python processes per host, serializes facts, and pays significant per-task overhead from module loading. glidesh spawns async Rust tasks sharing a connection pool with native SSH — no subprocess shelling. There’s no fact-gathering phase unless you ask for it.

In my own usage — a modest fleet, nothing dramatic — the difference is noticeable. But “feels faster” is not a benchmark and I won’t pretend otherwise. If someone runs a proper controlled comparison and publishes the results, I’d welcome it.

Speed was never the primary motivation anyway. Predictability was.


What’s Coming: Nix as a First-Class Citizen

Here’s where the story comes full circle.

The next version of glidesh will support Nix natively — not as a shell command you run through the shell module, but as a module that understands Nix profiles, flakes, and derivations. Declare a Nix profile as your desired state, and glidesh checks whether the target matches and applies the delta. The same check/apply pattern, but now the “desired state” is a Nix derivation: content-addressed, cacheable, and hermetic by construction.

This is the convergence I’ve been working toward. Bazel for builds. Nix for system-level packages and configurations. glidesh for applying those configurations to real machines over SSH, with no agent and no runtime dependency beyond a shell. Every layer is auditable. The distance between “what I declared” and “what’s running” shrinks to zero.

I don’t know of another tool trying to bridge Nix’s hermeticity guarantees with agentless infrastructure automation. Maybe nobody else wanted it. But I did.

Who This Is For

If you manage a handful of servers and Ansible works, keep using Ansible. The ecosystem is enormous and the community support is unmatched.

glidesh is for people who feel the same friction I did. People who want their infrastructure tooling to be as predictable as their build system. People tired of debugging YAML type coercion or tracking down why a playbook behaves differently on a fresh control node. People who like a single static binary with zero runtime dependencies. People already invested in Nix who want their deployment layer to speak the same language.

It’s at v0.3.0. Not feature-complete — there are modules I haven’t written and edge cases I haven’t hit. But it works, it’s fast, and I’m using it in production for my own infrastructure.

Try It

curl -L https://github.com/alessiopcc/glidesh/releases/latest/download/glidesh-linux-amd64 -o glidesh
chmod +x glidesh
sudo mv glidesh /usr/local/bin/

Or build from source (Rust 1.85+):

git clone https://github.com/alessiopcc/glidesh.git
cd glidesh
cargo build --release

The documentation covers everything from inventory definition to writing custom plugins. The GitHub repo is where issues and contributions live.

Was it needed? Maybe not. But the tools I enjoy using most are the ones someone built because the existing options didn’t match how they think. glidesh matches how I think about infrastructure. If that resonates, give it a look.


If you want to follow glidesh development or talk about infrastructure automation, open an issue on GitHub.