MVP-to-production monorepo for hands-free realtor CRM operations using Follow Up Boss (read + write/log only), IDX context, outbound messaging, strict inbound command extraction, and auditable execution.
packages/core: action model, schemas, orchestration engine, safety policy, idempotency, instruction parsing, SQLite persistence.packages/adapters-fub: Follow Up Boss API client + mock adapter.packages/adapters-idx: pluggable IDX adapter interface + mock + HTTP adapter.packages/adapters-sendhub: SendHub SMS sender + webhook verification + mock.packages/adapters-email: SMTP/SendGrid/Mailgun/Gmail/GOG email adapters + mock.packages/adapters-kvcore: KVcore Public API v2 adapter + optional Twilio call fallback.packages/adapters-elevenlabs: optional voice adapter + outbound-only transport adapter boundary.packages/adapters-slybroadcast: Slybroadcast voicemail drop adapter + mock.packages/mcp-server: MCP server exposing action and workflow tools.packages/cli: operator/OpenClaw shell CLI.packages/kvcore-mcp-server: MCP server for KVcore contact/calls/email/text operations.packages/kvcore-cli: KVcore CLI for direct CRM operations.packages/webhooks: inbound instruction gateway (email/SMS/voice).packages/slybroadcast-voicemail: standalone Slybroadcast voicemail CLI + MCP server with ElevenLabs voice plugin support.scripts/demo.ts: end-to-end mock demo for required workflows.
- Inbound execution only from authenticated channels: email/SMS/voice webhook endpoints.
- Outbound-only channels (
imessage,whatsapp) are send-only transport adapters and never used for inbound commands. - Command extraction executes only:
BEGIN_FUB_CMD ... END_FUB_CMDJSON envelope, or/fub ...slash commands.
- Everything else in inbound text is ignored for execution.
- Actions use allowlisted schemas, role checks, and permission scopes.
dry_run=trueis default in MCP tool API; writes requireconfirm=trueanddry_run=false.- Idempotency keys persisted in SQLite; replay returns cached result.
- Webhook replay protection via provider event dedupe table.
- Webhook rate limiting (sliding window).
- Outbound safety policy blocks likely secret exfiltration, command directives, non-allowed region sends, and mass sends by default.
- Outbound logs include content hash and encrypted body.
- Install dependencies:
npm install- Configure env:
cp .env.example .env- Update provider credentials and allowlists in
.env.
npm run build
npm run testnpm run dev:mcpMCP tools:
fub_actionslybroadcast_drop_voicemailslybroadcast_get_audio_listslybroadcast_get_campaign_statusworkflow_text_and_taskworkflow_listing_statusworkflow_hotlead_task
KVcore MCP server:
npm run dev:kvcore-mcpKVcore MCP tools include:
kvcore_capabilitieskvcore_contact_searchkvcore_contact_getkvcore_contact_createkvcore_contact_updatekvcore_contact_tag_addkvcore_contact_tag_removekvcore_note_addkvcore_call_logkvcore_call_schedulekvcore_email_sendkvcore_text_sendkvcore_user_taskskvcore_user_callskvcore_campaigns_refreshkvcore_requesttwilio_call_create
Build first:
npm run buildExamples:
node packages/cli/dist/index.js who "john smith" --pretty
node packages/cli/dist/index.js note --person "+14165550001" --text "Left voicemail" --confirm --pretty
node packages/cli/dist/index.js task create --person "john@example.com" --title "Follow up" --due "2026-02-15" --confirm --pretty
node packages/cli/dist/index.js sms send --to "+14165550001" --body "We got the docs" --person "john@example.com" --confirm --pretty
node packages/cli/dist/index.js idx search --city Toronto --minBeds 2 --maxPrice 900000 --pretty
node packages/cli/dist/index.js plan --from-message ./inbound.txt --dry-run --pretty
node packages/cli/dist/index.js voicemail drop --to "+14165550001,+14165550002" --audio-url "https://example.com/audio.mp3" --campaign-name "Open House Follow-up" --confirm --pretty
node packages/cli/dist/index.js voicemail drop --to "+14165550001" --elevenlabs-text "Hi, this is a quick update about your showing." --confirm --pretty
node packages/cli/dist/index.js voicemail audio-list --confirm --pretty
node packages/cli/dist/index.js voicemail campaign-status --campaign-id 123456 --confirm --prettyKVcore CLI:
node packages/kvcore-cli/dist/index.js contact search --query "john smith" --pretty
node packages/kvcore-cli/dist/index.js email:send --contact-id 123 --subject "Quick update" --body "Following up..." --pretty
node packages/kvcore-cli/dist/index.js text:send --contact-id 123 --body "Can we connect today?" --pretty
node packages/kvcore-cli/dist/index.js call:schedule --json '{"contact_id":123,"user_id":456,"scheduled_at":"2026-02-15 10:00:00"}' --pretty
node packages/kvcore-cli/dist/index.js user tasks --user-id 456 --pretty
node packages/kvcore-cli/dist/index.js call:twilio --to "+14165550001" --twiml "<Response><Say>Hello from your assistant.</Say></Response>" --prettyStart server:
npm run dev:webhooksEndpoints:
POST /inbound/sendhub(SMS)POST /inbound/emailPOST /inbound/voice
Expected controls:
- Shared secret header:
x-webhook-secret - SendHub signature header:
x-sendhub-signature - Event id header for replay defense:
x-event-id
- FUB:
FUB_BASE_URL,FUB_API_KEY,FUB_SOURCE_TAG - IDX:
IDX_PROVIDER(mockor custom HTTP),IDX_BASE_URL,IDX_API_KEY - SendHub:
SENDHUB_BASE_URL,SENDHUB_API_KEY,SENDHUB_WEBHOOK_SECRET - Email:
EMAIL_PROVIDERinsmtp|sendgrid|mailgun|gmail|gog - ElevenLabs optional:
APP_ENABLE_ELEVENLABS=true+ELEVENLABS_API_KEY - Slybroadcast optional:
APP_ENABLE_SLYBROADCAST=true+SLYBROADCAST_EMAIL+SLYBROADCAST_PASSWORD - ElevenLabs for voicemail audio generation:
ELEVENLABS_TTS_VOICE_IDandSLYBROADCAST_PUBLIC_AUDIO_BASE_URL(public URL where generated MP3 files are reachable by Slybroadcast) - KVcore:
KVCORE_BASE_URL,KVCORE_API_TOKEN,KVCORE_TIMEOUT_MS - Twilio fallback (optional):
TWILIO_ACCOUNT_SID,TWILIO_AUTH_TOKEN,TWILIO_FROM_NUMBER
KVcore Public API v2 supports contact operations, notes, call logging, send email/text to contact, schedule call, and read-only user tasks/calls.
Public API v2 does not currently expose generic workflow automation CRUD or task creation/completion endpoints. Use:
kvcore_requestfor newly released endpoints not wrapped yet.twilio_call_createfor direct outbound calls when KVcore calling features are not sufficient.
JSON envelope:
BEGIN_FUB_CMD
{"idempotencyKey":"abc12345","action":"task.create","input":{"person":{"name":"John Smith"},"title":"Call John","dueAt":"2026-02-15T15:00:00Z"}}
END_FUB_CMD
Slash command:
/fub task create "Call John re: offer" due:tomorrow person:"John Smith"
Runs the three required flows using mocks:
npm run demoIt executes:
- Text John + create tomorrow task.
- Query listing status for
123 Main Stfrom IDX mock. - Add
HotLeadtag to Sarah + follow-up task in 2 days.
- FUB adapter is intentionally wrapped behind a stable interface to support future OAuth and endpoint changes.
- IDX adapter is vendor-pluggable.
- iMessage/wacli flows are supported as outbound-only transport boundaries.
- Logging back into FUB is automatic after successful outbound send when a person can be resolved.
A new package is available at packages/skyslope-deal-manager for transaction/deal office workflows:
- CLI runtime:
npm run dev:skyslope-cli -- <command> - MCP server runtime:
npm run dev:skyslope-mcp - Build package:
npm run build:skyslope
See packages/skyslope-deal-manager/README.md for commands and env variables.
Package at packages/slybroadcast-voicemail:
- CLI runtime:
npm run dev:slybroadcast-cli -- <command> - MCP runtime:
npm run dev:slybroadcast-mcp - Build package:
npm run build:slybroadcast-voicemail
See packages/slybroadcast-voicemail/README.md for commands and env variables.