Software factories
Designing a software factory architecture
A software factory architecture needs a durable record of the work, an environment where an agent can execute it, and evidence tied to the proposed change. Design the boundaries around ownership: who may start work, what the agent may change, and who accepts its result. Then account for the actions that can succeed just before a process fails.
Follow a project-name bug through the system
Suppose a settings page shows the old project name after a successful save. This is an illustrative design exercise. The request includes a browser reproduction and says the saved name must appear after navigation and a reload. It also states that a failed save must preserve the previous name.
Give that request a stable task ID. Store the original brief, repository, starting revision, and person responsible for acceptance. Later attempts belong to the same task but receive separate attempt IDs. That distinction lets an operator see whether a patch came from the initial investigation or a retry after new information arrived.
The coordinator should reject or pause incomplete intake before allocating an expensive environment. If the report names no repository, an agent cannot resolve that missing ownership by running more commands. Route it to the requester with the specific gap.
Keep task ownership separate from execution
The control plane owns task state and authorization. An execution process owns a bounded attempt to do the work. A sandbox supplies its filesystem and services. Keeping these responsibilities explicit helps the coordinator survive a worker restart without losing the task or treating an old worker as its current owner.
| Component | Responsibility in this example |
|---|---|
| Task store | Retain the reproduction, decisions, attempts, and output references. |
| Coordinator | Authorize an attempt and decide when to retry or request a decision. |
| Execution worker | Run the agent against the assigned repository revision. |
| Task environment | Supply the checkout, dependencies, app server, and disposable data. |
| Verification | Record checks against the proposed revision. |
| Review surface | Present the diff, observations, and unresolved questions to the owner. |
A small implementation can keep several components in one service. Separate them in the design even when they share a deployment. For distributed workers, a lease with an ownership token can prevent an expired worker from updating the task after a replacement takes over. Validate ownership where state changes occur.
A lease alone does not settle every concurrency problem. AWS describes how two processes can temporarily believe they are the leader and recommends separate correctness controls for that case. See its leader election guidance.
Make the environment reproducible enough to investigate
The agent needs the affected app and a project fixture whose name it can change. Record how dependencies were installed and how the service started. Separate the fixture from another task's data. A second agent changing the same project could make a correct save look like a regression.
A separate Git checkout isolates file changes. Service ports, databases, and external resources need their own isolation decisions. Our worktrees and cloud sandboxes guide covers where those boundaries differ.
Supply only the tools and credentials required for this attempt. The settings bug needs a test account; it usually does not need production database access. A permission denied response should produce a visible limitation. Repeatedly asking an unavailable tool does not improve the investigation.
Attach evidence to a revision
An agent might trace the problem to an outdated client cache. Verification should cover the requested browser behavior and the failure path. Save the command or procedure, result, and tested commit. If the patch changes afterward, the previous pass remains a fact about the previous revision.
Keep check outcomes explicit: passed, failed, and unavailable carry different meanings. For example, a unit test can pass while a browser check remains unavailable because the fixture server failed to start. The review surface should show both. Allow a useful investigation to end with a named gap instead of representing missing verification as success.
Decide who owns acceptance separately from the implementation agent. An additional agent can inspect the diff, but its review also needs a scope and supporting evidence. Your repository's branch protections and release policy still determine what can land.
Design for a successful action followed by a crash
Consider a worker that opens the PR and then stops before recording its URL. Restarting the whole task can create a duplicate proposal. Use a stable task reference in the branch or artifact metadata, check for existing output on recovery, and retain the result of external actions as soon as it is known.
Put limits on automatic retries. A temporary network failure can justify another attempt. Contradictory acceptance criteria need a person. Cancellation also deserves a defined state: work may stop while a branch, sandbox, or already-opened PR continues to exist. Tell the operator which artifacts remain.
Retain events with the task and attempt IDs so someone can reconstruct the sequence. A current status label alone cannot explain whether preparation failed, the model ran out of budget, or a checked patch is waiting for review.
Implement one complete path before adding more agents
Start with intake, one execution attempt, and a reviewable artifact. Run the project-name example through a normal completion, a failed check, and an interruption after output creation. Resolve those ownership questions before introducing a planning agent or several implementation workers.
In Uno, a session keeps the goal, environment, conversation, and outputs together. Its session guide distinguishes environment preparation from agent progress and explains how to inspect a failed turn. Use that work record alongside the diff and repository checks when deciding whether a result is ready to accept.