How to architect software projects for AI agents
If you have delegated more than one task to a coding agent, you have probably seen it repeat the same analysis of the code base at the start of every session, only to reimplement a helper that has been part of that code base for years. It’s tempting to blame the model. However, a more useful perspective is that the agent did exactly what the repository allowed it to do.
A human developer is onboarded once and then carries the project in their head. An agent is onboarded at the start of every task. It has no memory of yesterday, no hallway conversations, and no colleague at the next desk to ask. Whatever the project does not tell it, the agent has to rediscover in every session, and whatever it fails to rediscover, it guesses. A guess is what we usually call a hallucination.
The good news is that this is an engineering problem, and it has engineering solutions. Having an engineer babysit agent sessions is not one of them. Corrections typed into the chat are lost when the session ends, just like the rest of what the agent has learned, so they have to be repeated with every task. In this article I want to show how to architect a software project in which agents can work reliably and without constant supervision, and why this investment pays off quickly.
Agent experience
This discipline is called Agent Experience (AX) by analogy to UX and DX for users and developers, respectively. agentexperience.ax describes it as the holistic experience AI agents have when interacting with a system, i.e. how easily they can access, understand, and operate within it. Applied to a software project, the question is how easily an agent can understand your code base, verify its own changes, and modify it safely.
The same idea appears under different names. Context engineering is the broader discipline of getting the right information to a model at the right time. Project-level AX is the part of it that is versioned and shared by the team, as the context lives in the repository rather than in the prompt window of a single developer. Harness engineering means the practice of building such an environment around a code base (see e.g. articles by OpenAI and Birgitta Böckeler). Note that the word “harness” is also used for the agent runtime itself, which is a different topic.
At the far end of this development sits the software factory, i.e. a setup in which agents do the implementation work on their own. Tickets are planned, implemented, reviewed, and merged by a chain of automated agents. The engineers spend their time on the layer around the product instead, consisting of specifications, conventions, quality scorecards, and review loops. The quality of this layer turns out to limit what the whole factory can produce. This means that the engineering effort shifts from building the product to building the factory that builds the product (see e.g. the report by Ona).
So what does agent-ready mean in practice? Most of it follows from a single principle: repo-local or nonexistent. An agent that works on its own starts every task from a blank context, so anything it cannot reach from inside the repository effectively does not exist for it (e.g. wikis, ticket threads, or the knowledge in the heads of your colleagues). When an agent has to analyze your code base again on every task, this is not a defect of the model that we have to tolerate, but an AX defect that we can fix. A project is agent-ready when the knowledge and the checks an agent needs are in the repository, executable, and up to date.
A simple test for this is to give an agent a ticket from your backlog and no human help, and to see whether it reliably reaches a green verification suite and produces a diff that your reviewers accept. The measures described in the following sections serve this test.
The control system
The most useful mental model for working toward this goal comes from Böckeler. Regard your repository setup as a control system that continuously regulates the code base toward its desired state. Each measure you take is classified along two axes: whether it steers the agent before it acts (feedforward) or verifies the result after (feedback), and whether it is implemented as deterministic code or as an LLM run.
| Guides (steer before) | Sensors (verify after) | |
|---|---|---|
| Computational (fast, cheap, on every change) | one-command setup, task runner, scaffolding, generated reference docs | type checks, linters, tests, structural rules, the build |
| Inferential (LLM-run, semantic, gated or scheduled) | AGENTS.md, docs folder, ADRs, specs, skills | AI review passes, security and modularity reviews, scans for outdated docs |
Both directions are necessary. With sensors but without guides, the agent keeps making the same mistakes because nothing steers it up front. With guides but without sensors, rules pile up and there is no proof that they are followed. Guides improve the quality of the first attempt, while sensors give the agent a self-correction loop.
The control system itself must be actively maintained. Whenever an agent makes a mistake, adjusting the prompt is not enough: change the repository to make sure that the mistake cannot recur. Two habits keep the system maintainable: add the new rule in the same change as the fix it originated from, citing the incident, and introduce rules only for mistakes that actually happened.
The next two sections show how to build each half of the control system.
Architecting the guides
The entry point is AGENTS.md, an open format providing a single predictable place for the context a coding agent needs. Keep this file a compact map of around 150 lines, consisting of tool descriptions, fundamental project rules, and pointers to more detailed documentation. For each line, ask yourself whether removing it would cause a mistake the agent would not otherwise make. Ecosystem defaults do not deserve a line, but deviations from those defaults do.
Instructions cost attention and tokens on every run. This means that a bloated file is likely to increase LLM usage while degrading output quality instead of improving it.
Beyond the entry point, we recommend the convention of a docs folder with two roles. It holds the more detailed documentation that AGENTS.md points to, and it serves as the agent’s memory, i.e. the place where the team writes down what the agent should know in future sessions. Both are versioned and shared via the repository, which means that humans and agents who clone the project work from the same state of knowledge.
Inside the docs folder, the convention prescribes a small set of artifact types, each answering one kind of question:
- ARCHITECTURE.md is the structure (where): a technical overview of the system, the concepts it is built from, and module dependencies.
- Product specs are the promises (what): the currently intended behavior of a capability.
- Design docs are the strategy (how): how a system delivers its promises, i.e. the interfaces and invariants the design relies on, and the trade-offs and rejected alternatives that shaped it.
- Architecture decision records (ADRs) are the reasons (why): one decision per record, with the context, the options that were weighed, and the consequences.
- Exec plans are the work: the in-flight state of tasks that span multiple sessions.
- Guidelines cover the conventions that no tool enforces yet.
Specs deserve special attention. Experience from software factories shows that the quality of the spec determines how much additional work is necessary after the first implementation. Most bugs turn out to be specification failures rather than capability failures, because the agents build what is described and miss what is not. When agents implement, the spec becomes the main control surface.
Spec-driven development takes this to its extreme and starts each feature with a spec from which the implementation is derived. We recommend a more selective approach and add specs only where they help to communicate intent or requirements, e.g. when a feature is about to be built or when the intended behavior is contested. Everywhere else, a spec would be a second copy of what the code and its tests already express, and one more document to keep in sync.
How do you build such a knowledge layer without a month of writing? Let agents extract it instead. They can scan your code base, your git history, and your issue tracker. A surprisingly large share of the knowledge layer can be derived and verified from what is already there. For the part that exists only in the heads of your colleagues, flip the interaction and let the agent interview them. The division of labor is clear: the agent digs up the facts, while you make the decisions.
Architecting the sensors
The control system table above distinguishes computational sensors, which are fast and deterministic, from inferential sensors, which require LLM reasoning. You should make a check computational wherever technically possible, and inferential only where judgment is needed. For example, a module boundary (such as the rule that code shared between browser and server must not import browser-only modules) should be explained semantically in ARCHITECTURE.md and enforced by a structural test. It’s the test that makes the explanation trustworthy.
Creating a computational sensor means using a tool or writing a script, and the part of this work that deserves the most care is its error message, because for an agent error channels are guidance channels. Whenever you have that under your control, write the message for self-correction, stating what is wrong, why the rule exists, and what to do instead.
The self-correction loop only catches what a sensor can observe, so a code change should be verified at its observable output (the rendered page, the emitted data, the API response, etc.). A page that renders incorrectly while all unit tests pass is a typical example of a defect that goes unnoticed otherwise. Where the agent cannot perceive the output on its own, supplying the perception tooling should be made part of the architecture, and this may take more sophisticated tools than a test runner. For a web UI, for example, browser automation with Playwright serves as the agent’s eyes. Expand this kind of coverage before allowing more agent-generated work to land with less human review.
As an overview, these are the kinds of sensors we typically set up in a project:
- Standard build steps: compile, type-check, lint, test, package
- Structural rules for modules and dependencies (e.g. via a custom ESLint rule that restricts imports)
- Drift checks that fail when generated artifacts or the documentation no longer match the code
- Browser automation for inspecting UIs (e.g. via Playwright)
- Observability tools that expose logs, metrics, and traces of a running system (e.g. via OpenTelemetry and Prometheus)
- Domain-specific languages with semantic validations
- AI review passes that judge a change against specs and guidelines
Getting there follows the same pattern as with the guides, so let agents audit the repository. During such an audit, an agent checks every command cited in the docs, finds discrepancies between documentation and reality, and fixes them. If applying this to a mature codebase yields a large number of findings, there’s no reason to be embarrassed: this is the normal state of any project that has grown over several years. The result should be a verification step that runs all computational sensors and is cited in AGENTS.md, so all agents run it before declaring their task done.
Whether the software does the right thing is a question no sensor can decide. It stays with the people who own the intent, who write the specs and set the target for the whole control system.
An agent skill for AX
AGENTS.md and the docs folder are always active and specific to one project. A skill is the opposite: an on-demand procedure (e.g. how to release or how to migrate an API), packaged as a folder with a SKILL.md file and loaded only when a task calls for it. The Agent Skills format has become the standard for this and is read by dozens of coding agents, which means that know-how packaged this way is reusable across repositories and teams.
We have distilled this article’s playbook into an open source skill named agent-experience, published in TypeFox/agent-skills. Point it at your repository and it runs the process described above. It audits what is there by inventorying repository instructions, checking claims against their enforcement, and verifying the documented commands by execution. It interviews your team for the knowledge that exists only in heads. Then it generates and maintains the layer of guides and sensors, following the standards from this article.
Installation takes a single command:
npx skills add TypeFox/agent-skills -g -s agent-experience
It grew out of the research summarized here and has been hardened by field-testing on real projects, including our own. It’s MIT-licensed, so feel free to use it and let us know where it falls short.
Summing up
The test proposed at the beginning of this article was to give an agent a ticket from your backlog and no human help, and to see whether it reliably comes back with a diff that’s ready to ship. A project passes this test when it operates as a control system, with guides that steer the agent before it acts and sensors that verify the result after. In contrast to corrections typed into the chat, this investment is preserved. Every mistake becomes a rule or a sensor in the repository, so the agent’s memory grows with each task instead of being reset with every session. Software engineers stay in the picture, but their work moves up one level, from writing the code to setting the target for the control system and maintaining it.
At TypeFox, we have spent more than a decade building languages, tools, and development environments for complex domains, and this experience lands right in the sensor column of the control system. Type checks, linters, and the build come for free with a mainstream language. For a domain-specific language, someone has to create the parser, the type checker, the validators, and the language server first, and this is what we have been doing since the company was founded. If you need support with making your project agent-ready, or if you’ve read this article and think we are wrong about something, we’d love to hear from you.
About the Author
Dr. Miro Spönemann
Miro joined TypeFox as a software engineer right after the company was established. Five years later he stepped up as a co-leader and is now eager to shape the future direction and strategy. Miro earned a PhD (Dr.-Ing.) at the University of Kiel and is constantly pursuing innovation about engineering tools.

