Imagine this: a new customer signs up for your service. Your automated onboarding workflow kicks off. It successfully charges their credit card... and then fails while creating their database account due to a temporary network blip. You now have a charged customer with no access, an inconsistent data state, and a support ticket that will take engineering time to manually fix.
This scenario is a common nightmare for developers building automations. Complex, multi-step processes are fragile. When they break midway, they leave behind a mess that damages data integrity and user trust.
The solution isn't to write more complex error-handling logic inside a single, massive function. The solution is to change the way we architect workflows entirely. The key lies in a principle borrowed from the world of databases: atomicity.
In the context of workflows, an atomic action is a self-contained, single-purpose operation that is treated as an indivisible unit. It either succeeds completely, or it fails completely, leaving the system in the same state as if the action had never been attempted. There is no partial success.
Think of it like a sealed transaction:
Each action does one thing and does it well. It has clearly defined inputs (like customerId and amount) and a predictable, structured output. This "all or nothing" guarantee is the cornerstone of building reliable systems.
When we ignore atomicity and build monolithic functions that handle multiple distinct tasks, we invite chaos. Consider an all-in-one onboardUser function that:
If step 3 fails, the user has been charged and their account exists, but they can't use the service they paid for. This creates cascading problems:
This brittle architecture simply doesn't scale.
The modern approach is to treat each step of your business logic as a discrete, reliable, and observable atomic action. This is the core philosophy behind the action.do platform.
Instead of a monolith, you define each operation as a standalone, atomic action that can be called like a simple API.
Let's look at how you'd define a process-payment action. It encapsulates all the logic for communicating with a payment gateway, handling errors, and returning a clear result.
import { Do } from '@do-sdk/core';
// Define an atomic action to process a payment
const processPayment = Do.action('process-payment', {
inputs: {
customerId: 'string',
amount: 'number',
},
handler: async ({ inputs, context }) => {
// Connect to a payment provider like Stripe
console.log(`Processing payment of $${inputs.amount} for ${inputs.customerId}`);
// ... payment gateway logic here
// Return a structured result
return { success: true, transactionId: `txn_${context.runId}` };
},
});
// Execute the action securely via the .do API
const result = await processPayment.run({
customerId: 'cust_12345',
amount: 49.99,
});
console.log(result);
// Output: { success: true, transactionId: 'txn_...' }
By encapsulating logic this way, you gain immense benefits:
This architectural shift is more important than ever with the rise of AI-powered agentic workflows. AI agents are phenomenal at planning and reasoning, but they need a reliable set of "tools" to interact with the world.
These tools must be atomic. An AI agent shouldn't need to understand the internal logic of your billing system. It just needs to know it can call a tool named process-payment with a customerId and an amount.
Atomic actions on the .do platform are these perfect tools. They provide a secure, reliable, and observable bridge between an AI's intent and its execution in the real world. You give the agent a toolbox of robust actions, and it can build powerful automations on the fly. You encapsulate the logic; the agent executes it flawlessly.
Stop building fragile automations that put your data at risk. Start thinking in terms of atomic actions. By breaking down your business processes into their fundamental, indivisible parts, you build systems that are more reliable, maintainable, and ready for the future of intelligent automation.
A: An atomic action is a self-contained, single-purpose function that performs one specific task, like sending an email or updating a database record. It's the fundamental building block for creating reliable and modular agentic workflows.
A: While similar, an action.do is purpose-built for agentic systems. It includes native integration with the .do ecosystem for state management, observability, and composition, allowing you to treat business logic as a first-class citizen in your automations.
A: A single action is designed to be atomic and perform one task. To orchestrate multiple actions, you use a 'workflow.do', which composes individual actions into a larger, stateful process. This promotes a clean separation of concerns.
A: Anything you can code. Actions can perform data transformations, integrate with third-party APIs (e.g., Stripe, SendGrid), query databases, or run machine learning models. It encapsulates any unit of business logic and exposes it as a simple API.
A: Inputs are defined with clear types in the action's configuration and are passed during execution. Secrets, like API keys or database credentials, are managed securely through the .do platform and injected into the action's context at runtime, never exposed in your code.