In the world of business automation, complexity is the enemy of reliability. We've all seen them: sprawling scripts and tangled processes that are brittle, difficult to debug, and impossible to scale. A small change in one part can cause unpredictable failures elsewhere. What if you could build robust, scalable automation not as a monolithic script, but as a series of simple, powerful, and reusable building blocks?
This is the core principle behind atomic actions, the foundation of modern agentic workflows. With action.do, you can move from chaotic scripts to clean, manageable business processes as code.
Think of an atomic action as the "atom" of your workflow—the smallest, indivisible unit of work. It’s a self-contained function designed to do one thing and do it perfectly. It has clearly defined inputs, produces predictable outputs, and is designed from the ground up to be reliable, reusable, and observable.
Common examples of atomic actions include:
Each action is a specialist, focused on performing its single task flawlessly, forming the bedrock of any complex business automation.
"Isn't this just a fancy function call?" It's a fair question. While an action.do does wrap a function, it adds a critical layer of structure and control that transforms a simple script into an enterprise-grade component.
A standard function call simply executes code. An action.do elevates this by providing:
This structured approach turns your code from a liability into a managed, reliable asset for automation.
Talk is cheap; let's see the code. Here’s how you would define an atomic action to send an email using action.do in TypeScript.
import { Action } from '@do-co/core';
// Define the input for our action
interface SendEmailInput {
to: string;
subject: string;
body: string;
}
// Define the output of our action
interface SendEmailOutput {
messageId: string;
status: 'sent' | 'failed';
}
// Create the action as a service
const sendEmail = new Action<SendEmailInput, SendEmailOutput>({
name: 'send-email',
description: 'Sends a transactional email.',
handler: async (input) => {
// Integration with an email provider (e.g., SendGrid, SES)
// would happen here. For this example, we'll simulate it.
console.log(`Sending email to ${input.to}...`);
const messageId = `msg_${Date.now()}`;
return {
messageId,
status: 'sent',
};
},
});
// This action can now be executed within any workflow or agent.
Notice how clean and self-contained this is. The inputs and outputs are explicit, and the handler function contains only the core logic for this specific task. This send-email action is now a robust, reusable component ready to be plugged into any agentic workflow.
The true power of atomic actions is realized when you combine them. They are designed to be the fundamental building blocks orchestrated by higher-level services, such as a workflow engine (workflow.do) or an autonomous agent (agent.do).
Imagine an automated customer onboarding process:
Each step is a distinct, observable, and reliable atomic action. If the Slack notification fails, it doesn't prevent the user's CRM record from being created or their welcome email from being sent. The system is resilient by design.
By embracing an atomic approach to automation, you encapsulate individual tasks into manageable, reusable, and observable actions. You stop wrestling with complex, monolithic scripts and start composing powerful workflows from simple, robust building blocks.
Ready to build your business processes as code? Discover the foundation of agentic workflows and start defining your atomic actions with action.do.