PyInfra is an agentless infrastructure automation tool. Same job description as Ansible, Salt, Chef. SSH into hosts, describe desired state, it diffs and converges. No agent, no central server, no daemon.
The difference: your "playbook" is just Python. Not Python cosplaying as YAML. Not Jinja smuggled inside YAML inside a Helm chart inside a Kustomize overlay. Actual Python:
from pyinfra.operations import apt, files, server
apt.packages(packages=["nginx"], update=True)
files.template(src="nginx.conf.j2", dest="/etc/nginx/nginx.conf")
server.service(service="nginx", running=True, enabled=True)
Idempotent operations. Facts gathered from hosts, branched on with normal `if` statements. Real loops, real imports, a real debugger, real type hints. Your editor autocompletes arguments because, brace yourself, they are just function signatures.
About YAML. Wonderful format. For about eleven minutes. Then someone needs an `if`, and you have `{% if %}` inside a string inside a list inside a map. Then someone types `no` as a country code for Norway and it ships to prod as `False`. Then someone indents with a tab and the parser dies without saying where. Congratulations, you reinvented a programming language. Badly. The honest move is to admit you wanted code, then write code.
PyInfra skips the eleven good minutes and goes straight to code.
Release notes in the link. Happy to answer questions.
Infrastructure as Code, not infrastructure as YAML.
Yeah, but I have Claude Code or Codex do this Ansible stuff and they do just fine with all this and then there's a gazillion of examples that they can lean on and once the patterns are established, it's pretty smooth. Opus 4.5 was when the big inflection was I was heavy into automation all summer. It was Opus 4.0. It was like pulling teeth. And then when 4.5 came out, it was just beautiful.
Thank you for this. I've implemented my own version of this a couple times over the previous 25 years. This is how my code always looked.
I've used Salt, CFEngine, Chef, Puppet, Make, Bash, and many hand-rolled iterations of this approach. I finally threw in the towel and forced myself to come to terms with Ansible and it's quirks because I needed the wider community support.
Now with AI tooling, I'm not so convinced the community modules moat is an actual moat. I'm going to very seriously consider porting all my Ansible code to this and see how it feels. I anticipate I'll be much happier after the change.
Do you have any plans to integrate with/build on other communities modules? i.e. even if it's not perfect, being able to call Ansible or Salt modules from PyInfra would be one way to fill the gap.
> Infrastructure as Code, not infrastructure as YAML.
Right on.
It's amazing to me that we've spent decades with programming languages and environments which can accurately guess what you're about to type next, which have enormous expressiveness while maintaining cogency, which are intuitive and well understood by humans, which have endless libraries and an infinity of ways of connecting with the world.
And what do we use to configure the most sophisticated infrastructure to run such code? Yet another mark-up language!
In the spirit of Saltstack with full python throughout including Mako templating. It has a very simple set of operators mostly around idempotent file management and shell commands to do things like restart services.
This enables very fast deploys - small changes on a small number of machines in < 10 seconds.
> The honest move is to admit you wanted code, then write code
This war will never end ... because there are genuine tradeoffs on both sides. YAML being a bad data description format isn't actually central to the question of whether you describe infra as data or as code. You can use JSON if you want. Data is static, 100% predicatable. Code is non-deterministic right up to the halting problem. If your infra should look different on wednesday to thursday, well it can do that! Some people like it, some people think it's the definition of hell.
Terraform makes an interesting tradeoff to try and have the best of both worlds but ultimately still falls on the same issue ... I've not seen one project yet of any complexity that didn't use workarounds to implement optional components (let's just pretend there's a list of them and it has 1 or zero elements in it!).
Ultimately I agree with your philosophy but maybe not your language. IMHO You really want a language that is built from the ground up around static typing and immutable constructs for this. Get as close to that predictable determinism as possible. But then, if the whole world knows python, I guess python it is.
That would have been very useful to me, before I retired! That said, I only run the Hermes Agent on leased VPSs and PyInfra might be a cool and easy to access Hermes - I need to think about that.
Adding to sibling comments: I used to use Ansible professionally and PyInfra for homelab. Ansible is ridiculously slow.
The only issue was I had to implement some facts and operations myself that probably were available in some Ansible package but to be honest it was trivial.
This seems cool, I'd particularly be interested if their 10x faster than Ansible claims pan out. Has anyone here used PyInfra? If so what's your experience been like?
I've been using PyInfra for a while, albeit just for simple automation (Updating systems, checking certain stats) and I'm a big fan. Compared to Ansible, I found the docs, syntax and usage patterns much easier to get on with. Might just be a preference thing, but I always had trouble going through the Ansible docs.
Ran into some bugs, like one machine that seems to cause errors and mess up the output on restart, although that looks like it might have been addressed in this release.
The is cool, thank you for sharing. I was just thinking about onboarding to ansible since I’ve just been following a manual checklist of commands for my remote server but based on positive feedback here I’ll probs oh give this a shot. Only downside is I imagine LLMs are probably a little more proficient at ansible just due to volume of training data.
I used ansible for years and pyinfra is very approachable since it has similar concepts, like inventories, common operations like files.put, server.shell, loving it so far, and it is quite fast
If you're a software engineer who wants to setup and maintain infrastructure, give PyInfra and Pulumi a go!
Huge fan of PyInfra. For my homelab, I use Pulumi with Python and PyInfra to build fully declarative intent based infrastructure. You can use actual software engineering principles like composition, inheritance, DI to setup and wire your infrastructure and services. One of the benefits of this is your infrastructure and services are now self documenting (have them write out a mermaid diagram!) and easily testable using pytest (from cheap unit tests to extensive integration tests (I use Incus)).
Instead of Pulumi, I originally used Terraform CDK with Python before CDK got IBM'd. The migration to Pulumi was refreshingly painless. My original reason for not choosing Pulumi was the crippled state of the open source, self hosted backend support a decade ago but it looks like that is now way more mature and less crippled.
PyInfra is a breath of fresh air compared to Ansible - its not just fast, it's more Pythonic, so IDE features actually work, readable, maintainable, debuggable. I call it infrastructure for software engineers.
If anyone wants to use an AI agent to try out PyInfra - One issue I've faced is that PyInfra was rearchitected in v2 (and some more in v3?) but what belongs in v1 vs v2 vs v3 isn't very clear, so an AI agent could spend a lot of time writing v1 code, having it fail and iterate to v2 and then to v3.
The official site uses the version in the URL as the namespace but it seems like the SOTA AI agents don't pay much attention to that.
Maybe writing a llms.txt for PyInfra v2, or v3 would be an extremely useful task to help with onboarding newcomers?
Disclosure: PyInfra core contributor here.
We just shipped 3.8.0.
PyInfra is an agentless infrastructure automation tool. Same job description as Ansible, Salt, Chef. SSH into hosts, describe desired state, it diffs and converges. No agent, no central server, no daemon.
The difference: your "playbook" is just Python. Not Python cosplaying as YAML. Not Jinja smuggled inside YAML inside a Helm chart inside a Kustomize overlay. Actual Python:
from pyinfra.operations import apt, files, server
apt.packages(packages=["nginx"], update=True)
files.template(src="nginx.conf.j2", dest="/etc/nginx/nginx.conf")
server.service(service="nginx", running=True, enabled=True)
Idempotent operations. Facts gathered from hosts, branched on with normal `if` statements. Real loops, real imports, a real debugger, real type hints. Your editor autocompletes arguments because, brace yourself, they are just function signatures.
About YAML. Wonderful format. For about eleven minutes. Then someone needs an `if`, and you have `{% if %}` inside a string inside a list inside a map. Then someone types `no` as a country code for Norway and it ships to prod as `False`. Then someone indents with a tab and the parser dies without saying where. Congratulations, you reinvented a programming language. Badly. The honest move is to admit you wanted code, then write code.
PyInfra skips the eleven good minutes and goes straight to code.
Release notes in the link. Happy to answer questions.
Infrastructure as Code, not infrastructure as YAML.
You can substitute Pulumi for Terraform, PyInfra for Ansible and google for sample projects that use Terraform and Ansible to get a good idea of their strengths and how they come together.
Then, you take that understanding and you realize using PyInfra and Pulumi, you can do all of that in just Python, using all of Python's rich ecosystem.
This reminds me of Nortel Command Console back in 2000-2005!
I worked for a telco company that had a lot of Nortel Passport devices (does anyone know what Frame Relay is?).
We started changing the network from Nortel to Cisco.
Cisco used telnet (later SSH), but Nortel people were extremelly reluctant to switch.
Turns out the Nortel network managment system (nortel nms) had a very interesting feature: you could open the command console to connect to one of the passport devices... or you could connect to a device group (or all the network) and run the same command in all devices.
This was great for auditing which version had every single device in the network... or for changing access-lists globally.
This looks great! pyinfra will integrate better with my other code, and installing it with uv fits my workflow better. Thanks for the post. I'll give it a try. I think some of my Caprover initialization tasks could also be handled by pyinfra.
Never heard of this before. In looking through docs, honestly it looks like Ansible, but for people who don’t know Ansible, and with way more footguns. The fact that you can import any existing Python library means you’re now relying on those libraries to not introduce bugs, or throw an exception in the middle of an operation, etc.
I despise YAML, but I can appreciate that it makes it harder to introduce imperative logic, and it forces you to stay on the paved path - which is very well-tested.
That was why any moderate to large Chef installation always turned out to be such a nightmare in practice - it was so easy to break out of the DSL, so people ended up swaddling it in impenetrable, unmaintainable spaghetti code. Ansible was a real breath of fresh air when it first came along!
This is just the pendulum swinging back again, and at least Python tends to be a little less "clever" (and therefore less write-only) than Ruby.
It seems to me that infra management is inherently suited to declarative logic. I'm pragmatic enough to understand why SWEs with little infra experience might prefer an imperative approach, but I tend to think you should pick one or the other and stick to it. In my experience, hybrid systems end up combining the worst aspects of both.
Hey, fair pushback, let me try to clear up a couple of points because I think there are some genuine misconceptions worth untangling.
On footguns.
Totally hear you that "Python lets you do anything" feels like a footgun. The flip side that I think gets missed: because it is real Python, you can actually test it. Pytest, mypy, ruff, jump-to-definition, refactor-rename, all of it just works. Unit-testing a 400-line YAML role with nested Jinja conditionals is genuinely hard, and that gap is what pushed me toward PyInfra in the first place.
On "importing Python libraries introduces bugs".
This one I think is worth a closer look, because the mechanics are not what they appear. PyInfra does not run Python on your servers. It runs Python on your control node to plan the change, then transpiles each operation to plain POSIX shell and pipes that over SSH. If you run with `-vvv` you can see it: `sh -c '...'` and nothing else on the wire. The target needs zero Python, zero agent, zero runtime. So whatever library you imported into your deploy script ran locally, produced a string of shell, and that string is what touches the box. A bug in some PyPI dependency cannot throw mid-operation on the host, because there is no Python on the host to throw it. Worth noting that Ansible, by contrast, ships a Python interpreter and module code to the target for most tasks, so if anything the library exposure on the executing side is larger there, not smaller.
On the control node, sure, you have dependencies, same as Ansible has Jinja2, PyYAML, paramiko, cryptography, and a long tail of Galaxy collections of varying quality. PyInfra has a stable API, solid test coverage, idempotent operations, and a real two-phase model (gather facts, then apply) so the apply phase is deterministic generated shell rather than arbitrary code running on the box.
On YAML keeping you on the paved path.
I really wanted this to be true for years, honestly. In practice, the moment you need a conditional you end up writing `{% if %}` inside a quoted string inside a map inside a list inside a role, with no type system, no debugger, and a few sharp edges in the parser (`no` as boolean, leading zeros as octal in YAML 1.1, tab/space mixing failing without a useful pointer). And the escape hatch when Jinja-in-YAML cannot express what you need is... writing a custom Python module. So you end up writing Python anyway, just with worse tooling around it.
The way I would put it: PyInfra is Python where Python helps (writing, testing, planning) and shell where shell belongs (executing on the host). Happy to dig into any specific footgun you have run into though, those are usually the most useful conversations.
See lots of comparisons to Ansible but Chef/puppet (both of which have agent-less modes) in Python instead of Ruby is what immediately came to mind. I guess Salt as well technically.
“Built on Python, Salt is an event-driven automation tool and framework to deploy, configure, and manage complex IT systems. Use Salt to automate common infrastructure administration tasks and ensure that all the components of your infrastructure are operating in a consistent desired state.”
Is there anything like Ansible Tower or Semaphore for PyInfra? Or some more generic tool that would work similarly?
I could likely vibecode something up if I had to, but I'm interested in a job orchestration system that can run things like upgrades, scheduled backups, ideally with a nice dashboard showing successful/failed jobs.
I have started to adapt https://testinfra.readthedocs.io/en/latest/, which looks similar in style to this from the verification side. Having previously used Salt, Ansible, and Chef at other companies, this looks great from a UX perspective compared to those other tools.
I'm glad to see PyInfra is still under active development. I don't currently use PyInfra, but I previously used it for a couple years to manage a build farm of about 100 Mac Pros. Those machine had previously been partially managed by Chef to ill effect.
I found PyInfra to be a great tool for the job at hand. Even though it didn't have many of the operations I needed, I found it easy to write new operations specific to macOS management tasks.
I recently looked at it again to help build EC2 Mac AMIs in combination with Packer, but I ended up with pydoit this time instead.
What I really want is something like either ansible or this that:
- Doesn't unnecessarily send code over the network.
- Has some sort of "execution optimizer".
Think for example a query planner/optimizer of a db. Or, as a good example, the query planner of the polars framework as opposed to how it works in pandas.
If I do a for loop and each loop iteration copies a file into the same dir, the optimizer should catch that and send over one compressed tar file.
44 comments
[ 1.8 ms ] story [ 63.1 ms ] threadWe just shipped 3.8.0.
PyInfra is an agentless infrastructure automation tool. Same job description as Ansible, Salt, Chef. SSH into hosts, describe desired state, it diffs and converges. No agent, no central server, no daemon.
The difference: your "playbook" is just Python. Not Python cosplaying as YAML. Not Jinja smuggled inside YAML inside a Helm chart inside a Kustomize overlay. Actual Python:
Idempotent operations. Facts gathered from hosts, branched on with normal `if` statements. Real loops, real imports, a real debugger, real type hints. Your editor autocompletes arguments because, brace yourself, they are just function signatures.About YAML. Wonderful format. For about eleven minutes. Then someone needs an `if`, and you have `{% if %}` inside a string inside a list inside a map. Then someone types `no` as a country code for Norway and it ships to prod as `False`. Then someone indents with a tab and the parser dies without saying where. Congratulations, you reinvented a programming language. Badly. The honest move is to admit you wanted code, then write code.
PyInfra skips the eleven good minutes and goes straight to code.
Release notes in the link. Happy to answer questions.
Infrastructure as Code, not infrastructure as YAML.
I've used Salt, CFEngine, Chef, Puppet, Make, Bash, and many hand-rolled iterations of this approach. I finally threw in the towel and forced myself to come to terms with Ansible and it's quirks because I needed the wider community support.
Now with AI tooling, I'm not so convinced the community modules moat is an actual moat. I'm going to very seriously consider porting all my Ansible code to this and see how it feels. I anticipate I'll be much happier after the change.
Do you have any plans to integrate with/build on other communities modules? i.e. even if it's not perfect, being able to call Ansible or Salt modules from PyInfra would be one way to fill the gap.
Right on.
It's amazing to me that we've spent decades with programming languages and environments which can accurately guess what you're about to type next, which have enormous expressiveness while maintaining cogency, which are intuitive and well understood by humans, which have endless libraries and an infinity of ways of connecting with the world.
And what do we use to configure the most sophisticated infrastructure to run such code? Yet another mark-up language!
In the spirit of Saltstack with full python throughout including Mako templating. It has a very simple set of operators mostly around idempotent file management and shell commands to do things like restart services.
This enables very fast deploys - small changes on a small number of machines in < 10 seconds.
This war will never end ... because there are genuine tradeoffs on both sides. YAML being a bad data description format isn't actually central to the question of whether you describe infra as data or as code. You can use JSON if you want. Data is static, 100% predicatable. Code is non-deterministic right up to the halting problem. If your infra should look different on wednesday to thursday, well it can do that! Some people like it, some people think it's the definition of hell.
Terraform makes an interesting tradeoff to try and have the best of both worlds but ultimately still falls on the same issue ... I've not seen one project yet of any complexity that didn't use workarounds to implement optional components (let's just pretend there's a list of them and it has 1 or zero elements in it!).
Ultimately I agree with your philosophy but maybe not your language. IMHO You really want a language that is built from the ground up around static typing and immutable constructs for this. Get as close to that predictable determinism as possible. But then, if the whole world knows python, I guess python it is.
The only issue was I had to implement some facts and operations myself that probably were available in some Ansible package but to be honest it was trivial.
Ran into some bugs, like one machine that seems to cause errors and mess up the output on restart, although that looks like it might have been addressed in this release.
If it helps, I put together a video when initially exploring PyInfra: https://www.youtube.com/watch?v=S-_0RiFnKEs
I can't get over the fact of how suspicious he looks while doing it. And doesn't even cover his face. Crazyness
https://x.com/porqueTTarg/status/2047652413306277970 https://xcancel.com/porqueTTarg/status/2047652413306277970
If you're a software engineer who wants to setup and maintain infrastructure, give PyInfra and Pulumi a go!
Huge fan of PyInfra. For my homelab, I use Pulumi with Python and PyInfra to build fully declarative intent based infrastructure. You can use actual software engineering principles like composition, inheritance, DI to setup and wire your infrastructure and services. One of the benefits of this is your infrastructure and services are now self documenting (have them write out a mermaid diagram!) and easily testable using pytest (from cheap unit tests to extensive integration tests (I use Incus)).
Instead of Pulumi, I originally used Terraform CDK with Python before CDK got IBM'd. The migration to Pulumi was refreshingly painless. My original reason for not choosing Pulumi was the crippled state of the open source, self hosted backend support a decade ago but it looks like that is now way more mature and less crippled.
PyInfra is a breath of fresh air compared to Ansible - its not just fast, it's more Pythonic, so IDE features actually work, readable, maintainable, debuggable. I call it infrastructure for software engineers.
If anyone wants to use an AI agent to try out PyInfra - One issue I've faced is that PyInfra was rearchitected in v2 (and some more in v3?) but what belongs in v1 vs v2 vs v3 isn't very clear, so an AI agent could spend a lot of time writing v1 code, having it fail and iterate to v2 and then to v3.
The official site uses the version in the URL as the namespace but it seems like the SOTA AI agents don't pay much attention to that.
Maybe writing a llms.txt for PyInfra v2, or v3 would be an extremely useful task to help with onboarding newcomers?
---
The original post by the OP https://news.ycombinator.com/user?id=wowi42:
Disclosure: PyInfra core contributor here. We just shipped 3.8.0.
PyInfra is an agentless infrastructure automation tool. Same job description as Ansible, Salt, Chef. SSH into hosts, describe desired state, it diffs and converges. No agent, no central server, no daemon.
The difference: your "playbook" is just Python. Not Python cosplaying as YAML. Not Jinja smuggled inside YAML inside a Helm chart inside a Kustomize overlay. Actual Python:
Idempotent operations. Facts gathered from hosts, branched on with normal `if` statements. Real loops, real imports, a real debugger, real type hints. Your editor autocompletes arguments because, brace yourself, they are just function signatures. About YAML. Wonderful format. For about eleven minutes. Then someone needs an `if`, and you have `{% if %}` inside a string inside a list inside a map. Then someone types `no` as a country code for Norway and it ships to prod as `False`. Then someone indents with a tab and the parser dies without saying where. Congratulations, you reinvented a programming language. Badly. The honest move is to admit you wanted code, then write code.PyInfra skips the eleven good minutes and goes straight to code.
Release notes in the link. Happy to answer questions.
Infrastructure as Code, not infrastructure as YAML.
You can substitute Pulumi for Terraform, PyInfra for Ansible and google for sample projects that use Terraform and Ansible to get a good idea of their strengths and how they come together.
Then, you take that understanding and you realize using PyInfra and Pulumi, you can do all of that in just Python, using all of Python's rich ecosystem.
I worked for a telco company that had a lot of Nortel Passport devices (does anyone know what Frame Relay is?). We started changing the network from Nortel to Cisco. Cisco used telnet (later SSH), but Nortel people were extremelly reluctant to switch.
Turns out the Nortel network managment system (nortel nms) had a very interesting feature: you could open the command console to connect to one of the passport devices... or you could connect to a device group (or all the network) and run the same command in all devices.
This was great for auditing which version had every single device in the network... or for changing access-lists globally.
I despise YAML, but I can appreciate that it makes it harder to introduce imperative logic, and it forces you to stay on the paved path - which is very well-tested.
This is just the pendulum swinging back again, and at least Python tends to be a little less "clever" (and therefore less write-only) than Ruby.
It seems to me that infra management is inherently suited to declarative logic. I'm pragmatic enough to understand why SWEs with little infra experience might prefer an imperative approach, but I tend to think you should pick one or the other and stick to it. In my experience, hybrid systems end up combining the worst aspects of both.
On footguns. Totally hear you that "Python lets you do anything" feels like a footgun. The flip side that I think gets missed: because it is real Python, you can actually test it. Pytest, mypy, ruff, jump-to-definition, refactor-rename, all of it just works. Unit-testing a 400-line YAML role with nested Jinja conditionals is genuinely hard, and that gap is what pushed me toward PyInfra in the first place.
On "importing Python libraries introduces bugs". This one I think is worth a closer look, because the mechanics are not what they appear. PyInfra does not run Python on your servers. It runs Python on your control node to plan the change, then transpiles each operation to plain POSIX shell and pipes that over SSH. If you run with `-vvv` you can see it: `sh -c '...'` and nothing else on the wire. The target needs zero Python, zero agent, zero runtime. So whatever library you imported into your deploy script ran locally, produced a string of shell, and that string is what touches the box. A bug in some PyPI dependency cannot throw mid-operation on the host, because there is no Python on the host to throw it. Worth noting that Ansible, by contrast, ships a Python interpreter and module code to the target for most tasks, so if anything the library exposure on the executing side is larger there, not smaller.
On the control node, sure, you have dependencies, same as Ansible has Jinja2, PyYAML, paramiko, cryptography, and a long tail of Galaxy collections of varying quality. PyInfra has a stable API, solid test coverage, idempotent operations, and a real two-phase model (gather facts, then apply) so the apply phase is deterministic generated shell rather than arbitrary code running on the box.
On YAML keeping you on the paved path. I really wanted this to be true for years, honestly. In practice, the moment you need a conditional you end up writing `{% if %}` inside a quoted string inside a map inside a list inside a role, with no type system, no debugger, and a few sharp edges in the parser (`no` as boolean, leading zeros as octal in YAML 1.1, tab/space mixing failing without a useful pointer). And the escape hatch when Jinja-in-YAML cannot express what you need is... writing a custom Python module. So you end up writing Python anyway, just with worse tooling around it.
The way I would put it: PyInfra is Python where Python helps (writing, testing, planning) and shell where shell belongs (executing on the host). Happy to dig into any specific footgun you have run into though, those are usually the most useful conversations.
“Built on Python, Salt is an event-driven automation tool and framework to deploy, configure, and manage complex IT systems. Use Salt to automate common infrastructure administration tasks and ensure that all the components of your infrastructure are operating in a consistent desired state.”
https://docs.saltproject.io/en/latest/topics/about_salt_proj...
I could likely vibecode something up if I had to, but I'm interested in a job orchestration system that can run things like upgrades, scheduled backups, ideally with a nice dashboard showing successful/failed jobs.
https://github.com/pyinfra-dev/pyinfra/blob/3.x/src/pyinfra/...
I found PyInfra to be a great tool for the job at hand. Even though it didn't have many of the operations I needed, I found it easy to write new operations specific to macOS management tasks.
I recently looked at it again to help build EC2 Mac AMIs in combination with Packer, but I ended up with pydoit this time instead.
- Doesn't unnecessarily send code over the network.
- Has some sort of "execution optimizer".
Think for example a query planner/optimizer of a db. Or, as a good example, the query planner of the polars framework as opposed to how it works in pandas.
If I do a for loop and each loop iteration copies a file into the same dir, the optimizer should catch that and send over one compressed tar file.