In the world of software and business process automation, complexity is the enemy of reliability. Large, monolithic scripts and tangled workflows are difficult to build, a nightmare to debug, and fragile in the face of change. What if we could build powerful automations not as one giant, complex machine, but by assembling simple, robust, single-purpose components?
This is the core philosophy behind action.do: the fundamental, atomic building block of automation. An action.do represents a single, indivisible, executable step. By chaining these simple actions together, you can create powerful, automated services and deliver valuable Services-as-Software that are scalable, testable, and easy to understand.
At its heart, action.do is about executing a singular task. Think of it as the verb in your automation sentence: "Send an email," "Create a user," "Update a database record." Each action is designed to do one thing and do it well. This "atomic" nature is its superpower. It ensures that every step in your process is isolated, predictable, and verifiable.
When you build with atomic actions, you're not just writing code; you're defining your business as code. Each process becomes a clear, composable sequence of actions that can be versioned, tested, and deployed with confidence.
Theory is great, but seeing it in practice makes it real. The .do SDK provides a clean and expressive way to define and execute your own actions. Let's look at a simple example: creating an action to send a welcome email to a new user.
import { action } from '@do-sdk/core';
// Define an action to send a welcome email
const sendWelcomeEmail = action.create({
id: 'send-welcome-email',
description: 'Sends a welcome email to a new user.',
execute: async ({ email, name }) => {
// Your email sending logic via an external API
console.log(`Sending welcome email to ${name} at ${email}...`);
// Imagine an API call here:
// await emailProvider.send({ to: email, ... });
return { success: true, messageId: 'xyz-123' };
}
});
// Execute the action with specific inputs
const result = await sendWelcomeEmail.execute({
email: 'jane.doe@example.com',
name: 'Jane Doe'
});
console.log(result); // { success: true, messageId: 'xyz-123' }
As you can see, the structure is incredibly straightforward:
This simple pattern allows you to encapsulate any piece of business logic—from sending a Slack message to provisioning cloud infrastructure—into a reusable, standalone unit.
A common question is how an action.do relates to a workflow.do. The distinction is crucial to understanding the power of the .do ecosystem.
You build powerful workflows by composing a series of simple actions. For example, a "New User Onboarding" workflow might be composed of these actions: create-user-record -> send-welcome-email -> add-user-to-crm. Each action is a self-contained unit, and the workflow is the conductor ensuring they execute in the correct order.
Two design principles make actions uniquely powerful: they are atomic and stateless.
By embracing these principles, action.do provides the foundation for building resilient, scalable, and maintainable agentic workflows that drive your business forward.
Q: What is an 'atomic action' in the context of .do?
A: An atomic action is the smallest, indivisible unit of work in a workflow. It performs a single, specific task, like 'send an email' or 'update a database record', ensuring that operations are reliable, testable, and easy to debug.
Q: How does an action.do differ from a workflow.do?
A: An action.do represents a single step, while a workflow.do orchestrates multiple actions to achieve a larger business outcome. You build powerful workflows by composing a series of simple actions.
Q: Can I create my own custom actions?
A: Yes. The .do platform is designed for extensibility. You can define your own custom actions using our SDK, encapsulating your specific business logic and integrating any third-party API to make them available in any workflow.
Q: Are actions stateful?
A: No, actions are stateless by design. They receive input, perform their task, and produce output without retaining memory of previous executions. State management is handled at the workflow level, ensuring actions are reusable and predictable.