In modern software development, we don't build complex applications from scratch every time. We use libraries, frameworks, and well-defined functions. We build with LEGOs, not by carving a statue from a single block of marble. This principle, known as composability, is about creating small, independent, and reusable components that can be assembled in various ways to create larger, more complex systems.
As we enter the era of AI agents and digital workers, this principle is more critical than ever. To truly scale your business automation efforts, you can't afford to build every bot as a monolithic, one-off project. The future lies in creating a composable digital workforce.
At bots.do, our "Business-as-Code" philosophy is built for this future. Let's explore how to create composable bots by building reusable functions for your digital workers.
A composable bot is a digital worker constructed from a set of discrete, reusable capabilities. Instead of a single, sprawling script that handles every step of a process, a composable bot orchestrates smaller, specialized functions to achieve its goal.
Think about a common business task: processing a new invoice. A monolithic approach might look like this:
// A monolithic approach
const monolithicInvoiceBot = new Bot({ name: 'Monolithic Invoice Bot' });
monolithicInvoiceBot.task('process-new-invoice', async (invoice) => {
// Step 1: Read the PDF file from storage
// ... logic to connect to S3 and download
// Step 2: Extract text and data using an OCR service
// ... logic to call OCR API, parse JSON response
// Step 3: Look up the customer in the CRM
// ... logic to authenticate and query Salesforce API
// Step 4: Enter the data into accounting software
// ... logic to format data and post to QuickBooks API
// This gets long, hard to debug, and impossible to reuse.
return { status: 'processed' };
});
This works, but it's brittle. What happens when your CRM API changes? Or when you need to build another bot that also needs to read PDFs? You're forced to copy-paste code, creating a maintenance nightmare.
A composable bot, on the other hand, delegates these sub-tasks to reusable functions.
The key to composability is identifying the core, repeatable actions within your business processes and abstracting them into their own functions. These functions become the utility belt for all your digital workers.
Look at your workflows. You'll quickly see recurring patterns:
These are perfect candidates for reusable functions.
Let's refactor our invoice processor into a set of composable functions. We can organize these into utility files.
utils/document.ts
import { ocrService } from './services';
export interface InvoiceData {
id: string;
customerEmail: string;
total: number;
}
export async function extractDataFromPDF(fileBuffer: Buffer): Promise<InvoiceData> {
console.log('Extracting data from PDF...');
const extractedText = await ocrService.process(fileBuffer);
// ...logic to parse text and return structured data
return { id: 'INV-2024-001', customerEmail: 'client@corp.com', total: 1250.75 };
}
utils/accounting.ts
import { quickbooksAPI } from './services';
export async function postInvoiceToLedger(invoice: InvoiceData): Promise<{success: boolean}> {
console.log(`Posting invoice ${invoice.id} to ledger...`);
const result = await quickbooksAPI.createInvoice(invoice);
return { success: result.ok };
}
Now, building our Invoice Processor bot is simple, clean, and declarative. The bot's main task is to orchestrate calls to our reusable functions.
import { Bot } from '@do/sdk';
import { extractDataFromPDF } from '../utils/document';
import { postInvoiceToLedger } from '../utils/accounting';
// Define a new, composable digital worker
const invoiceProcessor = new Bot({
name: 'Invoice Processor',
description: 'Extracts data from invoices and enters it into accounting software.',
});
// Assign a clean, readable task to the bot
invoiceProcessor.task('process-invoice', async (invoice) => {
console.log(`Processing invoice: ${invoice.id}`);
const invoiceData = await extractDataFromPDF(invoice.fileBuffer);
const result = await postInvoiceToLedger(invoiceData);
return { status: result.success ? 'processed' : 'failed' };
});
This is the power of the bots as code approach. Your bot's logic is now clear, and its dependencies are well-defined, testable, and reusable across your entire digital workforce.
Composability doesn't stop at functions. With the bots.do platform, you can create a true agentic workflow, where specialized bots collaborate to execute highly complex business processes.
Imagine a "New Client Onboarding" workflow:
Each bot is an expert at its task, built from its own set of reusable functions. They are deployed and managed independently but work together as a cohesive, autonomous team. This is the ultimate goal of scalable business automation.
Adopting a composable, "Business-as-Code" mindset yields massive benefits:
The era of intelligent automation is here. By building composable bots, you're not just automating tasks—you're engineering a resilient, scalable, and agile digital workforce.
Ready to transform your operations? Deploy your first autonomous AI agent with bots.do.