Doing things once

There's something that has been bugging me since I started working more with coding agents: helping them close the loop effectively. This is the exploration behind Once, an automation substrate that lets agents understand the best way to validate their changes.

There's something that has been bugging me since I started working more and more with coding agents, and it ties nicely with our goals at Tuist: helping agents close the loop effectively and efficiently.

As you might know, agents are LLM loops with access to tools. They have gotten quite good at navigating codebases and making changes, for example to implement a new feature, but when it comes to validating the work, the map between the changes and what needs to run is a bit loose. Unlike other domains, coding harnesses have the advantage that they can validate the work with more logic, for example with automated tests, but the dependencies often span beyond just the test file associated with the source file the changes landed on.

Locally, LLMs run just enough automation to bring some confidence, and then they let CI/CD jobs take care of running everything else. But this is unproductive. First, you are wasting CI resources running unrelated things and making developers wait. Second, if something breaks, it leads to more iterations, which is, once again, a waste of time. There must be a better way.

Turns out there is. Automation dependency acyclic graphs, which build systems work with internally, are the solution, not just to optimize builds, but to let agents understand the best way to validate their changes. However, these graphs were designed at a time when developers didn't ask questions like "what should I run to validate my changes?" It was natural for a developer to just run the tests associated with that file, like agents do today, but we need to get smarter than that. We need a graph that tells the agent, "and don't forget about X, Y, and Z, because they are connected to the changes too." This kind of automation substrate needs to span all kinds of automation tasks, from compiling Rust code to linting Swift code. Moreover, it needs to be accessible. You should be able to move incrementally toward a full graph declared in this language, without having to do everything in one shot, which is what often ends up happening with Bazel: all or nothing.

These things motivated me to start tinkering with Once. I won't lie: when I started, I didn't have a full picture of where we could bring value, or how we could make Once different from Bazel and Buck. But the more I dove into the work, the more it became clear that we were onto something.

First, the obvious one: the JVM. It should go away. You shouldn't have to run a heavy runtime as a daemon. Buck2 chose Rust wisely, so we should too.

Second, Starlark should be an opt-in interface, not the default one. In fact, scripts should be cacheable too, converted into the internal building blocks that Once works with.

Third, an MCP that coding harnesses can tap into to learn about the graph, validate it, and write automation for users. Bazel is known for the level of expertise you need to build internally, which makes it unattractive for many companies. I want to change that. I want to equip agents with everything they need to be effective at it.

Fourth, sandboxes are making compute cheaper and more accessible, so why not lean on that to build remote execution systems?

Fifth, why not expose this programmatically, so other programs can tap into remote caching and execution capabilities easily? It should not be exclusive to the automation substrate that we distribute through the executable.

Sixth, and thanks to Buck for the idea, the most popular ecosystems will come supported by us through prelude rules. We'll make sure those rules follow best practices and stay maintained. We don't want your software stack to depend on brittle incentives. We've built a company so we can continuously pour money into the commons, and we are designing Once to be vendor neutral.

I think Once can make an impact on how automation happens in software projects, learning from battle-tested solutions like Bazel and Buck while filling the gaps that coding harnesses need, and giving them the tools to develop and maintain the automation substrate. From the Tuist side, we'll plug into its standard contracts to provide both remote execution and cache infrastructure.