This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
mailbots is a TypeScript/Node.js framework for creating email-based bots and FollowUpThen (FUT) Skills. It's part of the FUT monorepo ecosystem where:
- mailbots provides the SDK/framework for building MailBot applications and FUT Skills
- Skills extend FollowUpThen functionality by injecting UI elements and behaviors into the email followup lifecycle
- The service receives webhooks from
fut-core-apifor task lifecycle events (task.created,task.triggered, etc.) - Skills can interact with 3rd party services (SMS, Zapier, CRMs) to enhance email workflows
npm run build # Compile TypeScript to dist/
npm run build:watch # Build in watch mode
npm test # Run full test suite (requires build)
npm run test:watch # Run tests in watch mode
npm run test:inspect # Debug tests with inspectornpm run docs:build # Generate HTML docs to docs-html/ and markdown to docs.md
npm run dev:docs # Serve live documentation at localhost
npm run toc:build # Generate table of contentsnpm run prepublishOnly # Auto-runs before npm publish (builds dist/)
npm run publish:prod # Push git, push tags, npm publishsrc/mailbots.ts- Main MailBots class with handler registration and Express appsrc/lib/bot-request.ts- BotRequest class wrapping webhook request/response logicsrc/lib/webhook-helpers.ts- Helper methods for responding to webhookssrc/lib/settings-page.ts- Settings UI generation helperssrc/types.ts- TypeScript interfaces for webhooks, tasks, UI blocks, etc.src/index.ts- Main exports
The framework supports several webhook handler types:
onCommand(command, handler)- Handle email commands (todo@bot.eml.bot)onTrigger(command, handler)- Handle when scheduled tasks triggeronAction(action, handler)- Handle email-based actions (button clicks)onTaskViewed(command, handler)- Handle task preview in web UIonEvent(event, handler)- Handle 3rd party webhooks
onFutCreateUser(handler)- Modify task creation confirmation emailonFutTriggerUser(handler)- Inject UI into triggered followup emailsonFutViewUser(handler)- Add UI when viewing tasks in web interfaceonFutAction(handler)- Handle actions from injected UI elementsonFutUpdate(handler)- Handle task updates/edits
onSettingsViewed(handler)- Render custom settings pagesonSettingsSubmit(handler)- Handle settings form submissions
fut-core-apisends POST to/webhooksendpoint- Framework routes to appropriate handler based on webhook type/command
- Handler receives
BotRequestinstance with helper methods - Handler responds with JSON (UI blocks, emails, data updates, etc.)
Skills are reusable packages that can be installed via npm:
const skillPackage = require('mailbots-skill-name');
skillPackage.activate(mailbot); // Auto-register handlers
// Or use skill components explicitly
const { renderSomething, middleware } = require('mailbots-skill-components');
mailbot.app.use(middleware);
mailbot.onCommand('test', bot => {
renderSomething(bot);
bot.webhook.respond();
});- Tests use Mocha with Chai assertions
- Test files:
test/mailbots.test.js,test/bot-request.test.js - Test fixtures in
test/fixtures/contain sample webhook payloads - Set
NODE_ENV=testto disable webhook signature validation - Use
mailbot.exportApp()instead of.listen()to get testable Express app
Example test pattern:
const request = require('supertest');
const mailbot = new MailBotsApp({ clientId: 'test', clientSecret: 'test' });
mailbot.onCommand('test', bot => { /* handler */ });
const app = mailbot.exportApp();
await request(app).post('/webhooks').send(webhookFixture);CLIENT_ID- MailBots client IDCLIENT_SECRET- MailBots client secretMAILBOT_URL- Public URL for webhook deliveryNODE_ENV=test- Disables webhook validation for testing
- Targets ES6 with CommonJS modules
- Strict mode enabled with
noUnusedLocals - Outputs to
dist/with declarations - Source in
src/, excludesnode_modules
- Prettier with
trailingComma: "none"andarrowParens: "avoid" - Pre-commit hooks run tests via Husky
All handlers must call bot.webhook.respond() to send response:
mailbot.onCommand('hello', bot => {
bot.webhook.quickReply('Hello back!');
bot.webhook.respond(); // Required!
});Use shallow merging pattern for task data:
bot.webhook.setTaskData('namespace', { key1: 'value1' });
bot.webhook.setTaskData('namespace', { key2: 'value2' });
// Result: { namespace: { key1: 'value1', key2: 'value2' }}Settings use namespace isolation:
mailbot.onSettingsViewed(bot => {
const page = bot.webhook.settingsPage({
namespace: 'my-skill',
title: 'My Skill Settings'
});
page.input({ name: 'api_key', title: 'API Key' });
page.button({ type: 'submit' });
// Don't call bot.webhook.respond() for settings handlers
});Set custom error handler for the entire application:
mailbot.setErrorHandler((error, bot) => {
// Custom logging, user notification
bot.webhook.respond({ status: 'error', message: 'Custom error' });
});