Skip to main content
This page is for the code path - wiring events, webhooks, credentials and MCP by hand. To build an agent without code, start with Build your first agent. An agent is only useful if something real can start it and something real happens when it finishes. You do not have to change how your business emits work to get either: a run starts from whatever you already have, and the result leaves the same way. Both directions keep a durable attempt log you can inspect, redeliver, or replay, so “did the partner ever get it?” is a question with an answer.

Getting a run started

Pick whichever you already have; a workflow can be started by more than one.

Getting the result out

An agent can drive all of it

Duraton ships an MCP server, so an AI agent is a first-class operator: it can list and control runs, send events, and decide approvals. An agent is not only the thing being run; it can be the thing doing the running. The same server, and llms.txt, are how you point a coding assistant at these docs and your project.

What each inbound transport guarantees

Every transport ships a capability descriptor you can read from the engine, generated from the same closed sets the API serves. A webhook source is the only transport today, so nothing differs - the descriptor exists so that when a second one lands, its differences are stated rather than implied away.

Ordering is two questions, not one

A transport’s ordering is not an ordering your runs keep. A broker that guarantees delivery order within a partition or a queue says nothing about execution order: Duraton does not preserve ordering past ingest, because runs are admitted from a queue sorted on when they are due, with no creation-order tiebreak, and a concurrency key buys mutual exclusion rather than sequence. That is why the descriptor carries two fields. ordering is what the transport promises on the way in; runOrdering is what survives, and it is none for every transport today. Reading the first without the second is the mistake this section exists to prevent: a true fact about your broker reads as a promise about your workflows.
If your workload needs records for one key handled in order, ordering at the transport is not enough. Model it explicitly: one workflow that processes a batch in order, or a state machine keyed on the entity, rather than assuming per-partition delivery becomes per-partition execution.

Acknowledgement is what makes durability possible

The promise is that work triggered by a message actually finishes. That rests on being able to tell the transport a message was handled, and on not telling it when the message was not.
  • Synchronous (webhooks): the HTTP status is the acknowledgement. There is nothing to acknowledge later, so a sender that gives up is the end of it. That is why an inbound delivery is recorded and can be replayed.
A transport that acknowledges nothing cannot carry the promise honestly. Redis pub/sub and MQTT QoS 0 are fire-and-forget: nothing is retained, nothing is replayed, and a consumer that was not listening simply missed the message. Duraton does not offer them as sources rather than accepting them and quietly delivering a weaker guarantee under the same name.

Where a dedupe id comes from

A dedupe id is what makes a redelivery a no-op rather than a second run. There is no universal formula for it, and the descriptor says so per transport:
  • A webhook has no identifier that is stable across redelivery, so there is no default: a source that wants dedupe names a key to read from the payload or a header.
Both are overridable with a template. The default is the transport’s to declare, because it depends on what that transport actually keeps stable. A RabbitMQ delivery tag, for instance, is scoped to a channel and is not stable across redelivery, so it could never serve as one.
  • Webhooks - inbound sources, outbound subscriptions, signing, and the attempt log.
  • Credentials - stored credentials a step resolves at run time.
  • MCP server - what an agent can do to Duraton, and how to connect one.