The boring parts are the product
Queues, idempotency keys, timeouts and audit trails are what separate an agent demonstration from an agent a business can rely on.
An agent demonstration and an agent in production differ by perhaps 5% of their interesting ideas and nearly all of their code. The gap is not filled with better reasoning. It is filled with the unglamorous machinery that ordinary software has always needed.
Agents pause, so state must be durable
The moment a workflow can wait for a person, in-memory state stops being viable. An approval may sit in a queue over a weekend. A document may wait for a reviewer who is on holiday. The workflow has to be a persisted record that any worker can pick up, not a function call holding a stack.
This single requirement reshapes the architecture. Stages become steps against a stored record. Transitions become explicit and logged. Retrying a stage means re-reading state rather than re-running from the beginning — which is also what makes the system debuggable.
Every side effect needs a key
Agents retry. Queues deliver twice. Networks time out after the request has already succeeded. If an action has an external effect, it needs an idempotency key derived from the thing being acted on, so that the second attempt converges on the first result instead of producing a new one.
The key is usually obvious once you look for it: a document hash, a ticket id, a subscription period. What is not obvious is how many systems ship without one, and how long that holds up before someone receives two refunds.
- Derive the key from the input, not from a generated id, so retries produce the same key.
- Make the write path assert on the key at the database level, not in application logic.
- Log the key with every external call so duplicates are traceable.
Tools are an API surface, not a convenience
It is tempting to give an agent a general HTTP client, or direct database access, and let it work out the rest. It is also the design that makes the blast radius of a mistake unbounded.
Narrow tools cost more to write and are worth it. One function, one permission, one typed input and output, its own timeout and retry policy. The agent gets a small vocabulary of things it can do, and every one of them is a thing you have decided it may do.
The question is never what the model is capable of. It is what the system permits.
Traces are the only debugging tool you have
When a deterministic function misbehaves you can read it. When a model-driven workflow misbehaves, the only thing you can read is what it saw and what it did. That means recording, for every run, the assembled context, the retrieved passages, the proposed action, the validation results and the final outcome.
This is not optional observability to add later. A trace that was not recorded cannot be reconstructed, and the interesting failures are the ones nobody was watching for.