In the world of business automation, we often face a tangled web of complexity. A single task, like onboarding a new customer, isn't just one action—it's a cascade of operations: updating a CRM, sending a welcome email, notifying a sales team, and creating a project board. Trying to manage this in a single, monolithic script is a recipe for brittle, unmaintainable, and opaque systems.
What if you could break down that complexity into simple, powerful building blocks? What if each tiny piece of work was a reliable, reusable, and observable component?
This is the core philosophy behind atomic actions. At action.do, we see them as the fundamental particles of agentic workflows. In this post, we'll explore how chaining these atomic actions together allows you to orchestrate sophisticated business processes that are robust, scalable, and beautifully simple.
Before we build a chain, let's look at the links. An atomic action, in the context of action.do, is the smallest, indivisible unit of work within your automation. Think of it as a specialized tool designed to do one thing perfectly.
An atomic action is defined by a few key principles:
Think of them like LEGO bricks. A single 2x4 brick is simple, but by combining it with others, you can construct anything you can imagine.
Having a toolbox full of atomic actions is great, but their true power is unlocked when you connect them. Chaining actions into a sequence—or an agentic workflow—transforms a collection of simple tasks into a powerful business process engine.
Here’s why this approach is so transformative:
Clarity and Readability: A workflow defined as a sequence of named actions like fetch-customer-data → create-crm-record → notify-sales-channel is infinitely more understandable than a 500-line script with nested API calls and convoluted logic. Your business process becomes the code.
Radical Reusability: The create-crm-record action you build for your customer onboarding workflow can be reused in a dozen other processes, from lead capture forms to manual data entry tools. You build it once and leverage it everywhere, saving time and ensuring consistency.
Enhanced Resilience: What happens if the CRM API is down when your monolithic script runs? The entire process likely fails. With a workflow of atomic actions, the workflow engine can manage this gracefully. It can automatically retry the failed create-crm-record action without re-running the steps that already succeeded. You can even build in compensation logic, like creating a support ticket if an action fails repeatedly.
Independent Scalability: Is your transcribe-audio action a performance bottleneck? You can scale that individual service without touching the rest of the workflow. This modularity allows for more efficient and cost-effective scaling.
Let's make this concrete. Imagine a "New User Onboarding" workflow.
First, we define the individual atomic actions we'll need. Each one is a small, focused unit of work.
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.
Using this pattern, we can also define other actions: create-crm-record, enrich-customer-data, and post-to-slack.
Now, we can chain them together in a workflow engine to orchestrate the full process. The output of one action becomes the input for the next.
The Onboarding Workflow:
This entire sequence is reliable, observable at every step, and composed of reusable components. If sending the email fails, you can retry just that step. If you want to switch CRMs, you only need to update the create-crm-record action; the rest of the workflow remains unchanged.
The action.do library provides the core framework for defining these powerful building blocks. By wrapping your business logic in a standardized Action class, you instantly gain the structure, observability, and reliability needed for enterprise-grade automation.
These actions are designed to be orchestrated by higher-level services like workflow.do or agent.do, which handle the chaining, data flow, and error management. action.do is the foundational layer—the source of truth for every task your automated systems can perform.
Stop writing tangled scripts. Start building elegant, resilient, and scalable business processes from simple, powerful building blocks.
Execute. Measure. Automate.
Q: What is an 'atomic action' in the context of .do?
A: An atomic action is the smallest, indivisible unit of work in an agentic workflow. It's a self-contained function (like sending an email or updating a CRM record) with clear inputs and outputs, designed to be reliable, reusable, and observable.
Q: How does action.do differ from a simple function call?
A: While an action.do wraps a function, it adds a structured layer of observability, error handling, retries, and standardization. This transforms a simple function into a managed, enterprise-grade component for reliable automation.
Q: Can I combine multiple actions?
A: Absolutely. The core purpose of atomic actions is to serve as building blocks. They are designed to be orchestrated by higher-level services like workflow.do or agent.do to create complex, multi-step business processes.
Q: What are some common examples of an action.do?
A: Common actions include 'send-email', 'create-support-ticket', 'update-database-record', 'query-api', 'post-to-slack', or 'transcribe-audio'. Each action is focused on performing one specific task perfectly.