In the world of software development and business automation, complexity is the enemy. Monolithic applications and brittle, tangled scripts make it difficult to adapt, scale, and maintain processes. The promise of "Business-as-Code" is to tame this complexity, but how do we get there? The answer lies in thinking smaller. Much smaller.
The future of automation isn't about writing bigger scripts; it's about defining smaller, more intelligent building blocks. This is the core philosophy behind action.do: a platform for creating powerful, agentic workflows by packaging your business logic into atomic actions. It represents a fundamental shift towards treating your operations as Services-as-Software.
An atomic action is the smallest, indivisible unit of work in a system. It's a self-contained, reusable function designed to perform one single task reliably and predictably.
Think of it like a Lego brick. A single brick is simple, but when you combine them, you can build anything. In the world of workflow orchestration, an atomic action is your brick.
Each of these is a perfect candidate for an action.do. It performs a single, well-defined job, takes specific inputs, and produces a predictable output. By encapsulating any single, repeatable task as a self-contained Action, you can chain them together to create powerful, intelligent automations.
Defining an Action on the .do platform is designed to be as straightforward as writing a function. You focus on the core logic, and the platform handles the rest.
Here’s a simple example in TypeScript showing how to define an Action that sends a welcome email to a new user.
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 break this down:
You might be thinking, "Isn't this just a serverless function?" While similar, Actions on .do are supercharged for the world of Business as Code.
Unlike traditional serverless functions, .do Actions are automatically instrumented with the features you'd otherwise have to build yourself:
This turns your business logic from isolated code into managed, reliable, and reusable components.
The true power emerges when you orchestrate these atomic actions. While an Action is designed to be atomic, you can compose them within a workflow.do file to handle complex processes.
This pattern promotes a clear separation of concerns. Instead of an Action calling another Action directly, a Workflow directs the flow of data between them.
Example Workflow: New User Onboarding
A workflow orchestrates these four independent, reusable Actions to complete a complex business process. This architecture is modular, easy to debug (you can pinpoint exactly which Action failed), and incredibly flexible.
Virtually any task you can script can become an Action. If you can code it, you can turn it into a reusable building block for your automation library. Common use cases include:
By building a catalog of these atomic actions, you are creating a true platform of Services-as-Software. You're not just writing code; you're building a library of executable business capabilities that can be combined and recombined to meet any challenge. This is the foundation for building powerful, scalable, and truly agentic workflows.