In the world of software development, automation is king. Yet, as our systems grow, our automation scripts often become a tangled mess of brittle, hard-to-maintain code. What starts as a simple script to handle one task balloons into a monolithic beast that no one wants to touch. The promise of "Business-as-Code" feels distant.
Enter the .do platform and its core principle: the atomic action.
This guide will walk you through the fundamental building block of modern automation. We'll show you how to define, build, and execute your very first action.do, transforming a single, repeatable task into a robust, reusable component for powerful agentic workflows.
Think of an atomic action as the smallest, indivisible unit of work in your system. It's a self-contained, supercharged function designed to perform one task and one task only, but to do it reliably.
Unlike a traditional serverless function, an Action on the .do platform is automatically instrumented with production-ready features like logging, error handling, retries, and versioning. You encapsulate a single piece of business logic, and the platform turns it into a discoverable, composable building block. By chaining these simple blocks together, you can orchestrate complex API automation and deliver entire Services-as-Software.
Let's get practical. We'll build a common and essential action: sending a standardized welcome email to a new user.
Here is the complete TypeScript code for our send-welcome-email action. We'll break down each part below.
import { Action } from '@do-sdk/core';
// Define a new Action to send a welcome email
const sendWelcomeEmail = new Action({
name: 'send-welcome-email',
description: 'Sends a standardized welcome email to a new user.',
handler: async (inputs: { email: string; name: string }) => {
console.log(`Preparing to send email to ${inputs.email}...`);
// Logic to connect to an email service (e.g., SendGrid, SES)
// const emailSent = await emailService.send({
// to: inputs.email,
// subject: `Welcome, ${inputs.name}!`,
// body: 'We are so glad you joined us...'
// });
const result = { success: true, messageId: `msg_${Date.now()}` };
console.log('Email sent successfully:', result.messageId);
return result;
},
});
// Execute the action via the .do SDK
async function run() {
const execution = await sendWelcomeEmail.run({
email: 'alex@example.com',
name: 'Alex',
});
console.log('Execution Result:', execution);
}
run();
Let's examine the key components of the new Action({...}) constructor:
Notice the commented-out section. This is where you would integrate with a real third-party service like SendGrid, AWS SES, or Mailgun. The action encapsulates this specific integration logic, abstracting it away from the rest of your system.
The second part of the script shows how to run the action directly using the .do SDK:
async function run() {
const execution = await sendWelcomeEmail.run({
email: 'alex@example.com',
name: 'Alex',
});
console.log('Execution Result:', execution);
}
The .run() method executes the action's handler with the provided inputs. When you run this script, you'll see an output confirming the execution and the result:
Preparing to send email to alex@example.com...
Email sent successfully: msg_1678886400000
Execution Result: { success: true, messageId: 'msg_1678886400000' }
You've just defined and executed your first atomic action!
Running a single action is useful, but the true power is unleashed when you combine them. This is the essence of agentic workflows.
Imagine a new user signs up. Instead of a single, massive script, you can now define a workflow.do that orchestrates a series of atomic actions:
Each step is modular, independently testable, and reusable. If you need to change your email provider, you only update the send-welcome-email action. The rest of the workflow remains untouched. This is Business-as-Code in practice: clean, manageable, and scalable.
An atomic action is the smallest, indivisible unit of work in a workflow. It's a self-contained, reusable function designed to perform a single task reliably, like 'send an email', 'create a user', or 'query a database'.
Actions on .do are supercharged functions. They are automatically instrumented with logging, error handling, retries, and versioning. They are designed to be discovered and composed into larger workflows, effectively turning your business logic into manageable code.
While Actions are designed to be atomic, complex logic is best handled by orchestrating multiple Actions within a Workflow (workflow.do). This promotes modularity, reusability, and a clearer separation of concerns in your automation architecture.
Virtually any task you can script. Common examples include interacting with third-party APIs (e.g., Stripe, Slack, Salesforce), performing database operations, running data transformations, or executing machine learning model inferences. If you can code it, you can make it an Action.
Ready to stop writing brittle scripts and start building resilient, scalable automations? Start encapsulating your logic into atomic actions today and DO MORE, FASTER.