Installation
Install the core package. LLM providers and channel adapters are peer dependencies — install only what you use.
npm install botinabox
# Providers (pick one or more)
npm install @anthropic-ai/sdk # Anthropic Claude
npm install openai # OpenAI GPT
# Ollama requires no extra package — just a running Ollama server
# Connectors (optional)
npm install googleapis # Google Gmail & Calendarlatticesql, uuid, cron-parser, ajv, and yaml — all installed automatically.Quick Start
Create a database, register a provider, set up an agent, and run a task.
import {
HookBus,
DataStore,
defineCoreTables,
AgentRegistry,
TaskQueue,
RunManager,
ProviderRegistry,
ModelRouter,
ApiExecutionAdapter,
} from 'botinabox';
import createAnthropicProvider from 'botinabox/anthropic';
// 1. Initialize
const hooks = new HookBus();
const db = new DataStore({ dbPath: './data/bot.db', wal: true, hooks });
defineCoreTables(db);
await db.init();
// 2. Register a provider
const providers = new ProviderRegistry();
providers.register(
createAnthropicProvider({ apiKey: process.env.ANTHROPIC_API_KEY! })
);
const router = new ModelRouter(providers, {
default: 'claude-sonnet-4-6',
});
// 3. Register an agent
const agents = new AgentRegistry(db, hooks);
const agentId = await agents.register({
slug: 'assistant',
name: 'Assistant',
adapter: 'api',
});
// 4. Create and execute a task
const tasks = new TaskQueue(db, hooks);
const runs = new RunManager(db, hooks);
const taskId = await tasks.create({
title: 'Summarize the quarterly report',
assignee_id: agentId,
priority: 3,
});
const runId = await runs.startRun(agentId, taskId, 'api');
const adapter = new ApiExecutionAdapter(router);
const result = await adapter.execute({
agent: { id: agentId, model: 'claude-sonnet-4-6' },
task: { description: 'Summarize the quarterly report.' },
});
await runs.finishRun(runId, {
exitCode: result.exitCode,
output: result.output,
usage: result.usage,
});Configuration
Bot in a Box can be configured with a YAML file. Environment variables are interpolated automatically using ${VAR_NAME} syntax. The config is validated at load time with AJV.
# botinabox.config.yml
data:
path: ./data/bot.db
walMode: true
channels:
slack:
enabled: true
botToken: ${SLACK_BOT_TOKEN}
appToken: ${SLACK_APP_TOKEN}
providers:
anthropic:
enabled: true
apiKey: ${ANTHROPIC_API_KEY}
agents:
- slug: researcher
name: Research Agent
adapter: api
model: smart
budgetMonthlyCents: 5000
models:
default: smart
aliases:
fast: claude-haiku-4-5
smart: claude-sonnet-4-6
powerful: claude-opus-4-6
routing:
conversation: fast
task_execution: smart
classification: fast
fallbackChain: []
budget:
globalMonthlyCents: 100000
warnPercent: 80
schedules:
- slug: daily-report
cron: "0 9 * * *"
timezone: America/New_York
action: agent.wakeup
actionConfig:
agentSlug: researcher
taskTitle: "Generate daily report"HookBus
The HookBus is the central event system. Every layer — channels, orchestration, data, security — communicates through hooks. Handlers are priority-ordered (0–100, lower runs first) and error-isolated.
import { HookBus } from 'botinabox';
const hooks = new HookBus();
// Register a handler (priority 10 = runs early)
hooks.on('task.created', async (ctx) => {
console.log('New task:', ctx.task.title);
}, { priority: 10 });
// Filter-based handler
hooks.on('run.completed', async (ctx) => {
console.log('Run finished with exit code:', ctx.exitCode);
}, { filter: (ctx) => ctx.agentSlug === 'researcher' });
// Fire an event
await hooks.fire('task.created', { task: { title: 'Hello' } });Built-in events include task.created, run.completed, budget.exceeded, message.inbound, agent.wakeup, schedule.fired, workflow.completed, slack.message.changed, slack.message.deleted, and slack.message.outbound.
DataStore
DataStore wraps SQLite (via latticesql) with schema-driven tables, CRUD operations, and soft deletes.
import { DataStore, defineCoreTables } from 'botinabox';
const db = new DataStore({
dbPath: './data/bot.db',
wal: true, // WAL mode for concurrent reads
hooks, // HookBus for audit events
});
// Register the 20+ core tables
defineCoreTables(db);
await db.init();
// CRUD operations
const id = await db.insert('agent', {
slug: 'assistant',
name: 'Assistant',
adapter: 'api',
});
const agent = await db.get('agent', id);
const all = await db.query('agent', { adapter: 'api' });
await db.update('agent', id, { name: 'Updated' });
await db.delete('agent', id); // soft deleteAgents
Agents are the core actors. Each agent has a slug, name, execution adapter (api or cli), model preference, and optional budget.
import { AgentRegistry } from 'botinabox';
const agents = new AgentRegistry(db, hooks);
const agentId = await agents.register({
slug: 'researcher',
name: 'Research Agent',
adapter: 'api',
model: 'smart', // model alias
budgetMonthlyCents: 10000, // $100/month
systemPrompt: 'You are a research assistant.',
});
// List all agents
const all = await agents.list();
// Get by slug
const agent = await agents.getBySlug('researcher');Tasks & Runs
Tasks represent work to be done. Runs represent a single execution attempt. A task can have multiple runs (retries, followups).
import { TaskQueue, RunManager } from 'botinabox';
const tasks = new TaskQueue(db, hooks);
const runs = new RunManager(db, hooks);
// Create a task (priority 1-10, lower = higher priority)
const taskId = await tasks.create({
title: 'Analyze the dataset',
assignee_id: agentId,
priority: 3,
context: { datasetPath: './data/input.csv' },
});
// Start a run
const runId = await runs.startRun(agentId, taskId, 'api');
// Finish with result (model/provider enable cost tracking)
await runs.finishRun(runId, {
exitCode: 0,
output: 'Analysis complete.',
usage: { inputTokens: 500, outputTokens: 200 },
model: 'claude-sonnet-4-20250514',
provider: 'anthropic',
});Task Queue
The task queue orders work by priority (1–10) and creation time. Tasks can trigger followup tasks, forming chains with a maximum depth of 5 to prevent infinite loops.
// Peek at the next task for an agent
const next = await tasks.peek(agentId);
// Claim and process
const claimed = await tasks.claim(agentId);
if (claimed) {
// Execute...
await tasks.complete(claimed.id, { output: 'Done' });
}
// Create a followup task
await tasks.create({
title: 'Follow-up analysis',
assignee_id: agentId,
priority: 5,
parentTaskId: taskId, // links to parent
});Run Manager
The RunManager coordinates execution. It locks per-agent to prevent concurrent runs, handles retries with exponential backoff, and records complete audit trails.
const runs = new RunManager(db, hooks);
// Start with adapter type
const runId = await runs.startRun(agentId, taskId, 'api');
// The API execution adapter handles the LLM loop
const adapter = new ApiExecutionAdapter(router);
const result = await adapter.execute({
agent: { id: agentId, model: 'smart', systemPrompt: '...' },
task: { description: 'Summarize this document.' },
tools: [], // optional tool definitions
maxIterations: 20, // tool-use loop limit
});
// Record the result
await runs.finishRun(runId, {
exitCode: result.exitCode,
output: result.output,
usage: result.usage,
});Workflows
Workflows are directed acyclic graphs (DAGs) of steps. Steps can depend on other steps, enabling parallel execution where dependencies allow. Context flows between steps via interpolation.
import { WorkflowEngine } from 'botinabox';
const workflows = new WorkflowEngine(db, hooks);
const workflowId = await workflows.create({
slug: 'code-review',
name: 'Code Review Pipeline',
steps: [
{
id: 'analyze',
name: 'Static Analysis',
agentSlug: 'analyzer',
taskTemplate: {
title: 'Run static analysis on {{pr_url}}',
description: 'Analyze the PR for issues.',
},
},
{
id: 'review',
name: 'Code Review',
agentSlug: 'reviewer',
dependsOn: ['analyze'],
failurePolicy: 'abort', // abort | skip | retry
taskTemplate: {
title: 'Review PR based on analysis',
description: 'Review using analysis: {{analyze.output}}',
},
},
{
id: 'summarize',
name: 'Summary',
agentSlug: 'writer',
dependsOn: ['review'],
taskTemplate: {
title: 'Write review summary',
description: 'Summarize: {{review.output}}',
},
},
],
});
// Execute with context variables
await workflows.run(workflowId, {
pr_url: 'https://github.com/org/repo/pull/42',
});{{stepId.output}}.Scheduling
Database-backed scheduling with cron expressions and one-time triggers. Schedules fire hook events that you handle with the HookBus.
import { Scheduler } from 'botinabox';
const scheduler = new Scheduler(db, hooks);
// Cron schedule (daily at 9 AM Eastern)
await scheduler.create({
slug: 'daily-report',
cron: '0 9 * * *',
timezone: 'America/New_York',
action: 'agent.wakeup',
actionConfig: {
agentSlug: 'reporter',
taskTitle: 'Generate daily report',
},
});
// One-time schedule
await scheduler.create({
slug: 'deploy-reminder',
runAt: '2026-04-10T17:00:00Z',
action: 'agent.wakeup',
actionConfig: {
agentSlug: 'devops',
taskTitle: 'Deploy v2.0',
},
});
// Start the polling loop (checks every 30s by default)
scheduler.start();Circuit Breaker for Connector Syncs
Wire a CircuitBreaker into the scheduler to prevent retry storms when a connector is persistently broken. After the failure threshold, the circuit opens and skips all syncs for that connector key until the cooldown expires.
import { Scheduler, CircuitBreaker } from 'botinabox';
const scheduler = new Scheduler(db, hooks);
const breaker = new CircuitBreaker(db, hooks, {
failureThreshold: 3,
resetTimeoutMs: 300_000, // 5-minute cooldown
});
scheduler.setCircuitBreaker(breaker);The breaker key is connector:account (e.g., gmail:alice@example.com), derived from actionConfig. Only connector.sync actions are circuit-checked.
Safe Tool Merging
Use mergeTools() to combine tool arrays without duplicates. Later tool sets override earlier ones (last wins), with a console warning on each override. Prevents Anthropic API 400 errors from duplicate tool names.
import { nativeTools, mergeTools } from 'botinabox';
// Local read_file overrides the built-in read_file
const tools = mergeTools(nativeTools, gmailSkills, pdfSkills, readFileSkills);Budget Controls
Per-agent and global monthly budget enforcement. Costs are calculated from token usage and model-specific pricing.
import { BudgetController } from 'botinabox';
const budget = new BudgetController(db, hooks, {
globalMonthlyCents: 100000, // $1,000/month total
warnPercent: 80, // emit warning at 80%
});
// Check before execution
const allowed = await budget.canSpend(agentId, estimatedCost);
if (!allowed) {
console.log('Agent over budget — skipping');
}
// Record cost after execution
await budget.recordCost(agentId, {
inputTokens: 1500,
outputTokens: 800,
model: 'claude-sonnet-4-6',
});
// Query spend
const agentSpend = await budget.getAgentSpend(agentId);
const globalSpend = await budget.getGlobalSpend();When a budget is exceeded, a budget.exceeded hook fires. You can use this to send alerts, pause agents, or escalate to a human.
Message Store
The MessageStore guarantees every message is stored before any bot response. Inbound messages and attachments are persisted, and outbound messages are stored before delivery.
import { MessageStore } from 'botinabox';
const store = new MessageStore(db, hooks);
// Store inbound BEFORE any bot response
const { messageId, attachmentIds } = await store.storeInbound(msg);
// Store outbound BEFORE sending
const outboundId = await store.storeOutbound({
channel: 'slack',
text: 'Working on it!',
threadId: 'thread-1',
agentSlug: 'assistant',
});
// Query thread history for context
const history = await store.getThreadHistory('thread-1', 20);Chat Responder
The ChatResponder provides fast (<2s) conversational responses via a cheap LLM. It maintains a rolling context window, filters all outbound messages for human readability, and suppresses redundant messages.
import { ChatResponder } from 'botinabox';
const responder = new ChatResponder(db, hooks, messageStore, {
llmCall,
model: 'fast',
contextWindowTokens: 4000,
});
// Fast conversational response with thread context
const reply = await responder.respond({
messageBody: 'deploy to staging',
threadId: 'thread-1',
channel: 'slack',
userName: 'Brian',
});
// Full send pipeline: redundancy check → filter → store → deliver
const messageId = await responder.sendResponse({
text: agentOutput,
channel: 'slack',
threadId: 'thread-1',
source: 'agent',
});
// Returns undefined if suppressed as redundantMessage Interpreter
The MessageInterpreter runs async after every message, extracting structured data: tasks, memories, files, and user context. Supports pluggable Extractor interfaces for custom data types.
import { MessageInterpreter } from 'botinabox';
const interpreter = new MessageInterpreter(db, hooks, {
llmCall,
model: 'fast',
extractors: [customProjectExtractor],
});
const result = await interpreter.interpret(messageId);
// result.tasks — actionable requests
// result.memories — notes and thoughts to remember
// result.isTaskRequest — true if message contains tasks
// result.custom — results from custom extractorsExtracted memories are automatically stored in the memories table. Custom extractors can process any message body and return typed results.
Loop Detection
The LoopDetector scans agent routing history for patterns that indicate stuck loops. It complements the chain depth guard with active pattern detection.
import { LoopDetector, LoopType } from 'botinabox';
const detector = new LoopDetector(db, {
windowSize: 10,
pingPongThreshold: 2,
});
// Check before creating a followup task
const loop = await detector.check(sourceAgentId, targetAgentId, taskId, chainOriginId);
if (loop) {
console.warn(loop.message);
// loop.type: SELF_LOOP | PING_PONG | BLOCKED_REENTRY
}Circuit Breaker
The CircuitBreaker prevents runaway failures by tracking agent error rates and automatically escalating to the human operator when thresholds are reached.
import { CircuitBreaker } from 'botinabox';
const breaker = new CircuitBreaker(db, hooks, {
failureThreshold: 3,
resetTimeoutMs: 300_000,
});
// Attach to RunManager for automatic tracking
runs.setCircuitBreaker(breaker);
// Or check manually
if (!breaker.canExecute(agentId)) {
// Circuit is OPEN — agent is broken
}
// Reset after human review
await breaker.reset(agentId);States: CLOSED (normal) → OPEN (tripped, escalated) → HALF_OPEN (probe). Emits circuit_breaker.tripped and circuit_breaker.recovered hooks.
Triage Routing
The TriageRouter replaces static channel bindings with content-aware routing: keyword matching, regex patterns, priority ordering, and LLM fallback for ambiguous messages.
import { TriageRouter } from 'botinabox';
const router = new TriageRouter(db, hooks, {
rules: [
{ agentSlug: 'devops', keywords: ['deploy', 'infra'], priority: 10 },
{ agentSlug: 'analyst', patterns: ['\\bdata\\b.*report'] },
],
fallbackAgent: 'general',
llmFallback: true,
});
const { agentSlug, decision } = await router.route(message);
// decision.method: 'deterministic' | 'llm'
// decision.reason: "keyword: 'deploy'" or "llm: classified as devops"Learning Pipeline
The LearningPipeline turns execution experience into durable knowledge. Structured feedback is captured, and when patterns emerge, they are automatically promoted to playbooks and skills.
import { LearningPipeline } from 'botinabox';
const learning = new LearningPipeline(db, hooks, {
playbookThreshold: 3, // 3+ similar → playbook
skillThreshold: 3, // 3+ agents → skill
autoPromote: true,
});
// Capture feedback
await learning.captureFeedback({
agentId,
issue: 'Rate limit hit',
rootCause: 'Missing backoff',
severity: 'medium',
repeatable: true,
accuracyScore: 0.8,
efficiencyScore: 0.3,
});
// Get learning metrics
const metrics = await learning.getMetrics(agentId);Governance Gates
Independent validation gates that check agent output from different dimensions. Gates report to the human operator, not to each other. Built-in: QAGate, QualityGate, DriftGate.
import { QAGate, QualityGate, GateRunner } from 'botinabox';
const runner = new GateRunner([
new QAGate([{
name: 'non-empty',
validate: (output) => output.trim()
? []
: [{ severity: 'error', message: 'Empty output' }],
}]),
new QualityGate([{
name: 'no-todos',
check: async (output) => /TODO/i.test(output)
? [{ severity: 'warning', message: 'Contains TODO' }]
: [],
}]),
], hooks);
const { passed, results } = await runner.runAll({
agentId, taskId, output: agentOutput,
});Data Layer Setup
The data layer is powered by latticesql. Call defineCoreTables(db) to register the 20+ core tables, then optionally add domain tables for business data.
import {
DataStore,
defineCoreTables,
defineDomainTables,
} from 'botinabox';
const db = new DataStore({
dbPath: './data/bot.db',
wal: true,
hooks,
});
defineCoreTables(db); // agents, tasks, runs, etc.
defineDomainTables(db); // org, project, client, etc. (optional)
await db.init();Core Tables
Core tables cover the orchestration lifecycle. All tables use TEXT UUIDs, ISO 8601 timestamps, and soft deletes via deleted_at.
| Table | Purpose |
|---|---|
| agent | Agent definitions (slug, name, adapter, model, budget) |
| task | Work items with priority, assignee, and status |
| run | Execution attempts with timing, output, and token usage |
| session | Conversation state per agent/channel/peer |
| message | Inbound and outbound messages |
| user | Cross-channel user identities |
| secret | Encrypted secrets with rotation tracking |
| schedule | Cron and one-time schedules |
| workflow | Workflow definitions (DAGs) |
| workflow_run | Workflow execution state |
| cost_event | Token usage and cost records |
| activity_log | Complete agent action audit trail |
| notification | Outbound notification queue |
Domain Tables
Optional business-domain tables for common patterns. Call defineDomainTables(db) to register them.
| Table | Purpose |
|---|---|
| org | Organizations (multi-tenant isolation) |
| project | Projects linked to orgs |
| client | Clients linked to orgs |
| invoice | Invoices linked to clients |
| repository | Git repositories linked to projects |
| file | Files linked to projects |
| channel | Communication channels |
| rule | Automation rules |
| event | Domain event log |
Context Rendering
DataStore can auto-generate markdown context files from database rows. Each entity gets its own directory with rendered files — so agents always start with accurate, up-to-date state.
// Render all entity context directories
await db.renderAll({ outputDir: './context' });
// Output structure:
// context/
// agents/
// researcher/
// AGENT.md # Agent definition + linked data
// MESSAGES.md # Recent messages
// projects/
// my-project/
// PROJECT.md # Project + linked repos, files, rulesSlack
Full Slack integration with threads, reactions, message editing, media support, and voice message transcription.
import { SlackAdapter } from 'botinabox/slack';
const slack = new SlackAdapter({
botToken: process.env.SLACK_BOT_TOKEN!,
appToken: process.env.SLACK_APP_TOKEN!,
});
// Register with the channel registry
channels.register(slack);
// Send a message
await slack.send({
channel: '#general',
text: 'Hello from Bot in a Box!',
threadTs: '1234567890.123456', // optional thread
});Voice messages are automatically transcribed via whisper.cpp (requires whisper-node and ffmpeg). Slack's mrkdwn format is handled natively.
Discord
Discord adapter with automatic message chunking for the 2,000-character limit.
import { DiscordAdapter } from 'botinabox/discord';
const discord = new DiscordAdapter({
token: process.env.DISCORD_TOKEN!,
});
channels.register(discord);Webhooks
Generic HTTP webhook adapter with HMAC-SHA256 signature verification.
import { WebhookAdapter, WebhookServer } from 'botinabox/webhook';
const webhook = new WebhookAdapter({
secret: process.env.WEBHOOK_SECRET!,
});
channels.register(webhook);
// Start a webhook server
const server = new WebhookServer({
port: 3000,
secret: process.env.WEBHOOK_SECRET!,
onMessage: async (msg) => {
await pipeline.process(msg);
},
});
server.start();Anthropic
Anthropic Claude provider supporting Claude Haiku, Sonnet, and Opus models.
import createAnthropicProvider from 'botinabox/anthropic';
const provider = createAnthropicProvider({
apiKey: process.env.ANTHROPIC_API_KEY!,
});
providers.register(provider);
// Available models:
// claude-haiku-4-5, claude-sonnet-4-6, claude-opus-4-6OpenAI
OpenAI GPT provider supporting GPT-4o, GPT-4o-mini, and o3-mini models.
import createOpenAIProvider from 'botinabox/openai';
const provider = createOpenAIProvider({
apiKey: process.env.OPENAI_API_KEY!,
});
providers.register(provider);
// Available models:
// gpt-4o, gpt-4o-mini, o3-miniOllama
Ollama provider for local and self-hosted models. Models are discovered dynamically from the running Ollama server.
import createOllamaProvider from 'botinabox/ollama';
const provider = createOllamaProvider({
baseUrl: 'http://localhost:11434', // default
});
providers.register(provider);
// Models are discovered from the running Ollama serverModel Router
The ModelRouter maps aliases and purposes to specific models, with fallback chains for resilience.
import { ModelRouter } from 'botinabox';
const router = new ModelRouter(providers, {
default: 'claude-sonnet-4-6',
// Aliases
aliases: {
fast: 'claude-haiku-4-5',
smart: 'claude-sonnet-4-6',
powerful: 'claude-opus-4-6',
},
// Purpose-based routing
routing: {
conversation: 'fast',
task_execution: 'smart',
classification: 'fast',
synthesis: 'powerful',
},
// Fallback chain (tried in order if primary fails)
fallbackChain: ['gpt-4o', 'claude-sonnet-4-6'],
});
// Resolve by alias
const model = router.resolve('smart');
// => 'claude-sonnet-4-6'
// Resolve by purpose
const model2 = router.resolveForPurpose('classification');
// => 'claude-haiku-4-5'Input Sanitization
All input is sanitized before storage. Null bytes and control characters are stripped, field lengths are enforced, and unknown columns are silently dropped on write.
// Sanitization happens automatically on all DataStore writes.
// No manual intervention needed.
// Field length limits are defined per-table in the schema.
// Values exceeding the limit are truncated.
// Unknown columns are stripped on write (silent),
// but cause errors on read (fail-fast).Audit Logging
Fire-and-forget audit events for tracked tables. The activity log records every agent action with timestamps, context, and results.
// Audit events are emitted automatically via HookBus.
// Listen for them to build custom audit pipelines:
hooks.on('audit.write', async (ctx) => {
console.log(`${ctx.table} ${ctx.action}: ${ctx.rowId}`);
});
// Secret access is tracked separately:
hooks.on('secret.accessed', async (ctx) => {
console.log(`Secret ${ctx.key} accessed by ${ctx.agentId}`);
});HMAC Verification
Webhook payloads are verified with HMAC-SHA256 signatures using timing-safe comparison.
import { verifyHmac } from 'botinabox/webhook';
const isValid = verifyHmac({
payload: requestBody,
signature: request.headers['x-signature'],
secret: process.env.WEBHOOK_SECRET!,
});
if (!isValid) {
throw new Error('Invalid webhook signature');
}Google Gmail
Full and incremental email sync via Gmail API. Supports OAuth2 and service account authentication. Can send emails.
import { GoogleGmailConnector } from 'botinabox/google';
const gmail = new GoogleGmailConnector({
credentials: {
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
refreshToken: process.env.GOOGLE_REFRESH_TOKEN!,
},
});
// Full sync
const emails = await gmail.sync();
// Incremental sync (uses historyId cursor)
const cursor = await db.loadCursor('gmail');
const newEmails = await gmail.sync({ cursor });
await db.saveCursor('gmail', newEmails.nextCursor);
// Send email
await gmail.send({
to: 'user@example.com',
subject: 'Hello',
body: 'Sent from Bot in a Box.',
});Google Calendar
Calendar event sync with syncToken-based incremental updates. Supports domain-wide delegation for Google Workspace.
import { GoogleCalendarConnector } from 'botinabox/google';
const calendar = new GoogleCalendarConnector({
credentials: {
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
refreshToken: process.env.GOOGLE_REFRESH_TOKEN!,
},
calendarId: 'primary',
});
// Sync events
const events = await calendar.sync();
// Incremental sync
const cursor = await db.loadCursor('calendar');
const updates = await calendar.sync({ cursor });
await db.saveCursor('calendar', updates.nextCursor);Import Paths
All exports are organized by subpath. The core package has no heavy dependencies — providers and adapters bring their own.
| Path | Exports |
|---|---|
| botinabox | HookBus, DataStore, ChatPipeline, registerExecutionEngine, 22 built-in tools (sendFileTool, readFileTool, dispatchTaskTool, etc.), mergeTools, loadConfig, getConfig, createDefaultLLMCall, buildSystemContext, AgentRegistry, TaskQueue, RunManager, MessageStore, ChatResponder, MessageInterpreter, TriageRouter, LoopDetector, CircuitBreaker, LearningPipeline, PermissionRelay, GovernanceGate, Scheduler, and all shared types |
| botinabox/anthropic | createAnthropicProvider, AnthropicProvider |
| botinabox/openai | createOpenAIProvider, OpenAIProvider |
| botinabox/ollama | createOllamaProvider, OllamaProvider |
| botinabox/slack | SlackAdapter, transcribeAudio, downloadAudio, enrichVoiceMessage |
| botinabox/discord | DiscordAdapter, chunkMessage |
| botinabox/webhook | WebhookAdapter, WebhookServer, verifyHmac |
| botinabox/google | GoogleGmailConnector, GoogleCalendarConnector |
Core Classes
Quick reference for the main classes and their constructor signatures.
new HookBus()
Central event bus. No constructor arguments.
new DataStore({ dbPath, wal?, hooks? })
SQLite database wrapper. Requires dbPath, optionally enables WAL mode and hooks.
new AgentRegistry(db, hooks)
Agent CRUD and lookup. Requires DataStore and HookBus.
new TaskQueue(db, hooks)
Priority task queue with claim/complete lifecycle.
new RunManager(db, hooks)
Run lifecycle with per-agent locking and retry backoff.
new ProviderRegistry()
LLM provider registry. Register providers, then pass to ModelRouter.
new ModelRouter(providers, config)
Model resolution by alias, purpose, or fallback chain.
new BudgetController(db, hooks, config)
Cost tracking and budget enforcement.
new WorkflowEngine(db, hooks)
DAG workflow creation and execution.
new Scheduler(db, hooks)
Cron and one-time scheduling with database persistence.
new SessionManager(db)
Conversation state per agent/channel/peer.
new UserRegistry(db, hooks)
Cross-channel user identity management.
new SecretStore(db, hooks, { encryptionKey? })
Encrypted secret storage with rotation tracking.
new MessageStore(db, hooks)
Store-before-respond guarantee for all inbound and outbound messages.
new ChatResponder(db, hooks, messageStore, config)
Fast conversational responses with rolling context, LLM filter, redundancy check.
new MessageInterpreter(db, hooks, config)
Async structured extraction: tasks, memories, files, user context.
new LoopDetector(db, config?)
Detects self-loops, ping-pong, and blocked re-entry in agent routing.
new CircuitBreaker(db, hooks, config?)
Tracks failures and trips to prevent retries on broken agents.
new TriageRouter(db, hooks, config)
Content-aware routing with keyword/regex matching and LLM fallback.
new LearningPipeline(db, hooks, config?)
Feedback capture with auto-promotion to playbooks and skills.
new GateRunner(gates[], hooks)
Runs independent governance gates and aggregates results.
new PermissionRelay(hooks, config)
Remote approval relay for unattended agent execution.