The problem
Building multi-agent bots from scratch is hard.
You need task routing, priority queues, retry logic, cost tracking, multi-channel messaging, workflow orchestration, session management, and security — before you even get to the LLM call. Most teams end up building the same infrastructure over and over.
Bot in a Box gives you all of that in a single npm package. Define your agents, wire up your channels, and focus on what your bot actually does.
Without a framework
- Manual task routing with custom if/else chains
- No budget controls — surprise API bills
- Per-channel glue code for Slack, Discord, webhooks
- No retry logic — failed tasks are lost
- No workflow support — everything is sequential
- In-memory state — lost on restart
- Security bolted on after the fact (or not at all)
With Bot in a Box
- Declarative agents with automatic task assignment
- Per-agent and global budget enforcement
- Unified channel adapters — one interface, any platform
- Retry with exponential backoff and followup chains
- DAG workflows with parallel execution
- SQLite-backed state — survives restarts
- Input sanitization, audit logging, HMAC verification built in
The pattern
Define agents
Declare agents in YAML or TypeScript — model, role, adapter, budget.
Wire channels
Register Slack, Discord, or webhook adapters. Agents auto-connect.
Route messages
Inbound messages are parsed, user-resolved, and dispatched to agents.
Execute tasks
The run manager picks up tasks, calls the LLM, handles retries.
Return results
Output flows back through channels. State persists to SQLite.
In practice
Customer Support Bot
Tables: agents, channels, tasks, sessions
A team needs to handle support tickets across Slack and Discord with different agents for billing, technical issues, and general questions.
import {
HookBus, DataStore, defineCoreTables,
AgentRegistry, TaskQueue, RunManager,
ChannelRegistry, MessagePipeline,
SessionManager,
} from 'botinabox';
import { SlackAdapter } from 'botinabox/slack';
import { DiscordAdapter } from 'botinabox/discord';
const hooks = new HookBus();
const db = new DataStore({ dbPath: './support.db', hooks });
defineCoreTables(db);
await db.init();
const agents = new AgentRegistry(db, hooks);
const channels = new ChannelRegistry(hooks);
const sessions = new SessionManager(db);
// Register specialized agents
await agents.register({
slug: 'billing',
name: 'Billing Support',
adapter: 'api',
});
await agents.register({
slug: 'technical',
name: 'Technical Support',
adapter: 'api',
});
// Connect channels
channels.register(new SlackAdapter({
botToken: process.env.SLACK_BOT_TOKEN!,
appToken: process.env.SLACK_APP_TOKEN!,
}));
channels.register(new DiscordAdapter({
token: process.env.DISCORD_TOKEN!,
}));
// Messages auto-route to the right agent
const pipeline = new MessagePipeline(
agents, new TaskQueue(db, hooks), hooks
);Insight
The message pipeline resolves users, classifies intent, and routes to the right agent — all without custom routing code.
DevOps Automation Bot
Tables: agents, workflows, schedules
An engineering team wants to automate their deploy pipeline: run tests, build, deploy to staging, wait for approval, then deploy to production.
import {
HookBus, DataStore, defineCoreTables,
AgentRegistry, WorkflowEngine, Scheduler,
} from 'botinabox';
const hooks = new HookBus();
const db = new DataStore({ dbPath: './devops.db', hooks });
defineCoreTables(db);
await db.init();
const agents = new AgentRegistry(db, hooks);
const workflows = new WorkflowEngine(db, hooks);
const scheduler = new Scheduler(db, hooks);
// Define a deploy workflow (DAG)
const workflowId = await workflows.create({
slug: 'deploy-pipeline',
name: 'Deploy Pipeline',
steps: [
{
id: 'test',
name: 'Run Tests',
agentSlug: 'ci-agent',
taskTemplate: {
title: 'Run test suite',
description: 'Execute all unit and integration tests',
},
},
{
id: 'build',
name: 'Build',
agentSlug: 'ci-agent',
dependsOn: ['test'],
taskTemplate: {
title: 'Build artifacts',
description: 'Compile and bundle for production',
},
},
{
id: 'deploy-staging',
name: 'Deploy to Staging',
agentSlug: 'deploy-agent',
dependsOn: ['build'],
taskTemplate: {
title: 'Deploy to staging',
description: 'Push build to staging environment',
},
},
],
});
// Schedule nightly deploys
await scheduler.create({
slug: 'nightly-deploy',
cron: '0 2 * * *', // 2 AM daily
timezone: 'America/New_York',
action: 'workflow.run',
actionConfig: { workflowId },
});Insight
Steps run in parallel when dependencies allow. If "test" fails, downstream steps are skipped automatically based on the failure policy.
Research Assistant
Tables: agents, providers, budget, tasks
A research team wants multiple agents using different LLM providers — a fast model for classification, a powerful model for synthesis — with strict cost controls.
import {
HookBus, DataStore, defineCoreTables,
AgentRegistry, TaskQueue, RunManager,
ProviderRegistry, ModelRouter,
BudgetController,
} from 'botinabox';
import createAnthropicProvider
from 'botinabox/anthropic';
import createOpenAIProvider
from 'botinabox/openai';
const hooks = new HookBus();
const db = new DataStore({ dbPath: './research.db', hooks });
defineCoreTables(db);
await db.init();
// Register multiple providers
const providers = new ProviderRegistry();
providers.register(
createAnthropicProvider({
apiKey: process.env.ANTHROPIC_API_KEY!,
})
);
providers.register(
createOpenAIProvider({
apiKey: process.env.OPENAI_API_KEY!,
})
);
// Route by purpose
const router = new ModelRouter(providers, {
default: 'claude-sonnet-4-6',
aliases: {
fast: 'claude-haiku-4-5',
smart: 'claude-opus-4-6',
},
routing: {
classification: 'fast',
task_execution: 'smart',
},
});
// Enforce budgets
const budget = new BudgetController(db, hooks, {
globalMonthlyCents: 50000, // $500/month
warnPercent: 80,
});
const agents = new AgentRegistry(db, hooks);
await agents.register({
slug: 'classifier',
name: 'Classifier',
adapter: 'api',
model: 'fast',
budgetMonthlyCents: 5000, // $50/month
});
await agents.register({
slug: 'synthesizer',
name: 'Synthesizer',
adapter: 'api',
model: 'smart',
budgetMonthlyCents: 30000, // $300/month
});Insight
Each agent has its own budget. When the classifier hits $50, it stops — but the synthesizer keeps running on its separate $300 budget.
Ready to build?
Install botinabox and have your first agent running in minutes.