An intuition we had early on in this era of AI in software engineering was that "anything you can represent as code, you probably should." This turned into a heuristic that's served us well as agents have taken on more and more of our software development lifecycle.
Before LLMs, writing code was expensive and slow, so the activity was heavily prioritized on developing core production features. Supporting workflows around that process, while valuable to overall quality and delivery, were harder to justify writing code for. We saw LLMs changing this equation: making code cheaper to write, bringing domain expertise across languages and frameworks, and offering a universal natural-language interface to develop through. So we bet that as coding agents pushed the frontier of agent-driven work, the more we represented as code, the more we could ride the wave of their improvements.
As it turned out, those supporting workflows ended up mattering more than we expected. Moving them into code didn't just make individual tasks faster; it brought them into the same shared context and delivery lifecycle as our product code, which ended up laying the foundation for a software factory.
Code is the language of agents
When you represent a domain in code, you give agents a legible and expressive interface into it. Infrastructure as code was our original source of inspiration, and investing in Terraform early on allowed our team of product engineers to use agents for cloud infrastructure. Agents removed the "new syntax" barrier so we could combine the LLM's intelligence with engineering intent and judgment. Code made the work legible to agents and more tractable for generalist engineers. Arcane cloud consoles became composable modules you could reason about with an intelligent co-pilot, increasing our confidence and ambition in evolving our infra to meet our product's needs.
Internal tooling was another area where agents tipped our decision-making towards code. We started on hosted app platforms because we needed to build simple apps fast. Then advances in coding agents pointed to a trajectory where the agent chat interface would clearly leapfrog GUIs for productivity. The AI capabilities of hosted app platforms lagged behind, so we made the call to move our internal tools into code we owned. As agents got better at visual design, it made sense to follow suit with our marketing website as well.
Obviously every build vs. buy consideration is nuanced and individualized, and our perspective is biased to a small and technical team. In our case, choosing to own the code has let us adopt frontier agents earlier and more broadly. On top of that, the falling cost of generating and maintaining code compounds across the team. The marginal effort to maintain another app in a standardized codebase drops significantly when you're wielding coding agents, because skills translate and your patterns replicate easily. We reap the benefits inherent to code, and every model release and coding agent upgrade now flows directly to our product, internal tools, and website.
One nice side effect of this approach was that internal apps became a sandbox for developing and sharing prototypes, since "tooling as code" set up the exact environment needed for "prototypes as code." That middle space between having an idea and building a full feature was rarely worth spending engineering time on before, even though nothing beats playing with a working concept early. Putting it in code let agents bridge that gap for us.
Code is a legible, shared context
Another useful property of code is that it already syncs as local files across developer machines. As model context windows grew, it became evident that the more relevant context we could provide to our agents, the better they'd perform. "Keep useful context close" became a guideline for our agents, and sharing local files was the easiest way to achieve this. Naturally, we adopted the path of writing our technical documentation as code (e.g., Markdown files in the codebase).
We created rules and patterns for our documentation, which have since evolved into agent skills that automatically update docs based on code changes and context captured from our chat sessions, focusing on the decision-making and the "why" that the code itself can't explain. Even as the MCP protocol emerged to give agents easy access to context stored in other applications, the simplicity and other benefits of code continue to outweigh moving work elsewhere.
A major reason is that co-locating context in code prevents drift. Tests are an obvious example of this: they're a supporting artifact to production code that we must ship alongside every PR. As they live in the codebase, agents can natively see the broader impact of changes they make and write tests in the exact same workflow. Following that pattern led us to represent more supporting artifacts in code:
Seed data as code. Once we created a dev seed data framework in code, it became easy to institute the guidance that "all new features should ship with corresponding seed data". One agent skill now ensures that all future engineers can develop on a feature out of the box.
Dashboards and monitors as code. Adding dedicated observability to your features in production has long been best practice, but in reality it's often "best effort." Defining these in code made it a standard for us, as our coding agents can now help create and tune monitors in tandem with code changes. They've proactively caught issues where signals would have broken in production because a metric or log changed.
Agent memory as code. The skills.md standard formalized what we had been calling "runbooks" in our codebase documentation, and it was trivial to port our files over. Skills gave us stronger guarantees that agents would use them, and having them in code promoted knowledge sharing on the team.
Putting all of this in one place turned our codebase into a searchable source of truth for both humans and agents, and let the whole system evolve in sync.
Code is the heartbeat of your software delivery cycle
When you put something in code, you're not just choosing a storage format; you're adopting a battle-tested lifecycle for delivering work. Software engineering has spent decades solving a hard problem: how do you let many independent actors evolve a complex system without breaking it? That scaffolding becomes even more important when those actors are agents.
Pull requests bring a built-in culture of review across all of our supporting work (infra, skills, monitors, and docs), acting as both a quality gate and a way to share knowledge across the team, even as code review itself evolves. Every change runs through automated CI checks before it touches production, and version control gives us a permanent audit trail and a clean rollback when an agent inevitably makes a mistake.
The software factory is built in code
Look back at the three properties above and you have the foundation of a software factory: agents that can operate across a broader swath of the development lifecycle, shared context that keeps them grounded, and a delivery pipeline that checks their work before it ships.
We didn't set out to build a factory, but all those supporting workflows that used to be hard to justify writing code for (infra, internal tools, docs, seed data, monitors, runbooks) turned out to be the factory itself. Feature code is what the factory produces; the supporting work is what lets it produce reliably. Each piece we moved into code gave agents better context, environments, and guardrails, making every subsequent agent run a little better.
And because the factory is defined in code, with our skills, conventions, and checks living in the repo, the agents can help improve the factory too. The more of your work you represent as code, the more your factory can take on, and as coding agents keep getting better, everything you've put in code rides the wave with them.