An atomic action is the fundamental building block of any powerful automation—a single, self-contained task designed to do one thing well. Sending an email, creating a user in a database, or querying an API are all perfect examples. While powerful on their own, their true potential is unlocked when you start composing them into sophisticated, agentic workflows.
Real-world business processes are rarely a single step. They involve sequences of tasks, critical decision points, and opportunities for efficiency. To build automation that truly mirrors and enhances these processes, you need to go beyond executing single actions and start orchestrating them.
This guide will explore the three fundamental patterns for orchestrating atomic actions on the .do platform:
The simplest way to build a workflow is by chaining actions together. This is a sequential process where the successful completion of one action triggers the next, often passing its output data along as input.
Think of it like a recipe: you must mix the dry ingredients before you add the eggs. The order matters, and one step depends on the one before it.
Use Case: New User Onboarding
A classic example is onboarding a new user to your platform. This involves a clear sequence of events:
This creates a reliable, repeatable process where data flows seamlessly from one stage to the next.
import { Action } from '@do-co/agent';
// Assume these actions are defined elsewhere
const createUserInDb = new Action(/* ... */);
const sendWelcomeEmail = new Action(/* ... */);
const addToCrm = new Action(/* ... */);
// Orchestrate the chain
async function onboardNewUser(userData) {
// Step 1: Create the user
const { userId, email, name } = await createUserInDb.run(userData);
// Step 2: Use the output from Step 1 to send an email
await sendWelcomeEmail.run({ userId, email, name });
// Step 3: Use the same data to update the CRM
await addToCrm.run({ userId, name, email });
console.log(`Successfully onboarded user ${userId}`);
}
Chaining is the backbone of all automation, establishing a logical, cause-and-effect flow for your business logic.
Static, linear workflows are useful, but intelligent automation requires the ability to adapt. Branching introduces conditional logic (if/then/else) into your workflows, allowing them to take different paths based on the data they process.
This is where your automation moves from being a simple script to a dynamic, agentic system capable of making decisions.
Use Case: Smart Ticket Routing
Imagine a customer support system. Not all tickets are equal; some are urgent, while others are standard inquiries. Branching allows you to route them intelligently.
import { Action } from '@do-co/agent';
// Assume these actions are defined
const analyzeTicketSentiment = new Action(/* ... */);
const escalateToTier2 = new Action(/* ... */);
const addToGeneralQueue = new Action(/* ... */);
// Orchestrate with branching logic
async function routeSupportTicket(ticketData) {
const { sentiment } = await analyzeTicketSentiment.run({ text: ticketData.body });
if (sentiment === 'negative') {
console.log('Negative sentiment detected. Escalating...');
await escalateToTier2.run({ ticketId: ticketData.id });
} else {
console.log('Adding ticket to general queue.');
await addToGeneralQueue.run({ ticketId: ticketData.id });
}
}
By introducing branching, your workflows can handle exceptions, prioritize tasks, and respond dynamically to changing conditions, making them vastly more powerful and useful.
Not every task in a workflow needs to wait for the one before it. When you have multiple independent actions that need to be performed, running them in parallel can dramatically reduce the total execution time.
Think about cooking dinner: you can preheat the oven at the same time you chop the vegetables. Waiting to do one after the other is inefficient.
Use Case: Customer Data Enrichment
When a new lead signs up, you want to gather as much information as possible, as quickly as possible. Many of these data-gathering tasks are independent and can be run simultaneously.
import { Action } from '@do-co/agent';
// Assume these actions are defined
const lookupInClearbit = new Action(/* ... */);
const findLinkedinProfile = new Action(/* ... */);
const updateCrmRecord = new Action(/* ... */);
// Orchestrate with parallel execution
async function enrichNewLead(leadData) {
// Trigger independent actions in parallel
const [clearbitResult, linkedinResult] = await Promise.all([
lookupInClearbit.run({ email: leadData.email }),
findLinkedinProfile.run({ name: leadData.name })
]);
// Combine the results and perform the final action
const combinedData = {
...leadData,
company: clearbitResult.company,
linkedinUrl: linkedinResult.profileUrl,
};
await updateCrmRecord.run({ leadId: leadData.id, data: combinedData });
console.log('Lead enrichment complete.');
}
Parallelization is key for building high-performance, responsive systems, especially when dealing with multiple external API calls or time-consuming tasks.
The true power of the .do platform emerges when you combine these patterns. A real-world agentic workflow isn't just a chain, a branch, or a parallel set of tasks—it's an intricate dance of all three. You can chain sequences of parallel actions, have branches that lead to different chains, and nest these patterns to build logic of any complexity.
By breaking down your business processes into discrete, atomic actions, you gain a set of powerful, reusable building blocks. By orchestrating them with chaining, branching, and parallelization, you can transform those blocks into intelligent, efficient, and scalable automations that drive your business forward.
Ready to move beyond single tasks? Explore the .do platform and start building your first orchestrated workflow today.