automation
Turn multiple inboxes into one actionable CRM workflow with Notion, Supabase, and Slack.
An inbound CRM automation skill that polls multiple email inboxes, syncs routing logic from Notion, persists contacts and activity in Supabase, and only alerts Slack when there is a real lead or task to handle.
This is the operating system behind my inbound funnel: multiple inboxes, one Notion playbook, Supabase as the record, and Slack only when there is a lead worth acting on.
Walkthrough
Watch the skill in action
This is the operating system behind my inbound funnel: multiple inboxes, one Notion playbook, Supabase as the record, and Slack only when there is a lead worth acting on.
How it works
CRM Inbound Orchestrator
Use this skill for hourly polling CRM workflows across:
info@yourdomain.comsales@yourdomain.comsupport@yourdomain.com
The source-of-truth SOP is synced from Notion page CRM_SOP_PAGE_ID every run.
How to use it
Download the skill package
Hit the Download button in the sidebar (desktop) or the button pinned at the bottom (mobile). You'll get a ZIP.
Add it to your agent
Extract and drop the folder into your agent's plugins directory. For Claude Code / OpenClaw, that's .claude/plugins/ in your project root.
Start prompting
Your agent now knows the skill. Describe the task in plain English — it handles the rest.
Developer & Source DetailsRaw SKILL.md and repository files
Skill Definition (SKILL.md)
The raw instruction document consumed by your AI agent.
CRM Inbound Orchestrator
Use this skill for hourly polling CRM workflows across:
info@yourdomain.comsales@yourdomain.comsupport@yourdomain.com
The source-of-truth SOP is synced from Notion page CRM_SOP_PAGE_ID every run.
Runtime Env Contract
Required:
NOTION_API_KEYCRM_SOP_PAGE_ID(default:31288fb313488013924ade7bf704ab6f)CRM_MONITORED_EMAILS(comma-separated)CRM_POLL_QUERY(default:in:inbox is:unread -in:spam -in:trash -category:promotions -category:social -category:updates -category:forums)CRM_POLL_OVERLAP_MINUTES(default:120)SUPABASE_URLSUPABASE_SECRET_KEY
Optional:
CRM_POLL_MAX_RESULTS(default:200)CRM_POLL_MAX_AGE_HOURS(default:36)CRM_SOP_CACHE_FILE(default:/tmp/crm-inbound-sop-cache.json)CRM_POLL_STATE_TABLE(default:crm_poll_state)CRM_CONTACTS_TABLE(default:crm_contacts)CRM_ACTIVITIES_TABLE(default:crm_activities)CRM_DRAFTS_TABLE(default:crm_drafts)CRM_ACCOUNTING_TABLE(default:accounting_entries)CRM_JOB_RUNS_TABLE(default:crm_job_runs)GOG_ACCOUNT(fallback sender account for approvals)CRM_OUTSTANDING_LOOKBACK_DAYS(default:7)CRM_OUTSTANDING_STALE_HOURS(default:24)CRM_OUTSTANDING_NOTIFY_EMPTY(default:false)CRM_CLASSIFIER_MODEL(default:gpt-5-nano)CRM_REPLY_MODEL(default:gpt-5.2)CRM_USE_MODEL_CLASSIFIER(default:true)CRM_USE_MODEL_REPLY_WRITER(default:true)OPENAI_API_KEY(required to use model classifier/reply writer)CRM_GMAIL_LABEL_APPLY(default:true)CRM_GMAIL_LABEL_LEAD(default:CRM/Lead)
Deterministic Command Surface
1) Fetch Notion SOP
tsx {baseDir}/scripts/fetch-sop.ts fetch_sop
Optional flags:
--page-id <id>--cache-file <path>--output <path>
2) Poll Inboxes Hourly
tsx {baseDir}/scripts/poll-inboxes.ts poll_inboxes
Optional flags:
--accounts <csv>--query <gmail-query>--overlap-minutes <n>--max-age-hours <n>--output <path>
3) Classify + Route + Persist
tsx {baseDir}/scripts/process-inbound.ts process_inbound \
--poll-file /tmp/crm-poll.json
Optional flags:
--sop-file <path>--output <path>
4) Approval Actions
tsx {baseDir}/scripts/approval-action.ts approval_action \
--action approve \
--draft-id <draft_id> \
--approved-by "U052337J8QH"
Also supported:
--action revise --notes "<feedback>"--action reject --reason "<reason>"
5) Morning Outstanding Check (Actionable-Only Report)
tsx {baseDir}/scripts/check-outstanding.ts check_outstanding
Optional flags:
--lookback-days <n>(default:7)--stale-hours <n>(default:24)--output <path>
Slack Output Contract (Non-Technical Friendly)
For each actionable lead, post a simple Slack card containing only:
- Mailbox
- Subject
- Message received
- When it was sent
- Suggested response
Approval/revision happens in the Slack thread, not via command strings in the main message.
Workflow Rules
- Poll hourly from all configured inboxes.
- Deduplicate by
account_email:message_id. - Classify with
gpt-5-nanointoreceipt|sales|support|ignore(fallback to heuristics only if model call fails). - Pull classification policy dynamically from Notion SOP sections (
classification,lead,inbound,routing,qualification) and inject it into the classifier prompt. - Deterministic lead override: expert-network, consulting, sponsorship, partnership, and creator-collaboration outreach is forced to
saleswhen business ask is explicit. - Apply Gmail label
CRM/Lead(orCRM_GMAIL_LABEL_LEAD) tosalesthreads. - Deterministic hard-ignore override: newsletter/digest/vendor-blast patterns (
view in browser,unsubscribe,manage preferences, roundup-style blasts, Gmail promotional categories) are forced toignoreunless explicit lead criteria are met. - Notification gate: only explicit business leads can create drafts and Slack notifications; model-only
salesguesses are downgraded toignore. - Sales path:
- upsert contact
- log activity
- apply SOP context from Notion snapshot
- create draft only for human, direct business inquiries (consulting/sponsorship/partnership intent)
- craft suggested response with
gpt-5.2
- Accounting path:
- parse vendor/date/amount/currency
- upsert accounting entry
- No send side effects until manual approval in Slack thread.
- Slack reporting policy:
- no hourly heartbeat/status spam
- hourly posts only when actionable
- morning 9:20 post provides outstanding summary (including "none" when empty)
Notion SOP Structure (Recommended)
Use clear headings in your Notion page so policy extraction stays deterministic:
Business Context- what Prompt Circle does
- ideal inbound opportunities
Lead Classification Rules- Lead (
sales): person/company reaching out for consulting, sponsorship, partnerships, affiliate opportunities, expert-network interviews, or any paid advisory call - Ignore: newsletters, product updates, system/vendor notifications, job alerts, hiring spam, social digests
- Support: requests for help with your product/service
- Receipt: invoices/payment confirmations
- Lead (
Lead Qualification Checklist- commercial intent present
- human sender (not no-reply/automated digest)
- asks for a call/brief/proposal/timeline/budget or paid expertise
Response Playbook- tone
- what to ask for next (brief, timeline, deliverables, budget)
- when to decline
Out-of-Scope- examples you never want treated as leads
Reference template:
cat {baseDir}/references/notion-inbound-sop-template.md
Data Contract
Tables:
crm_contactscrm_activitiescrm_draftsaccounting_entriescrm_job_runscrm_poll_state
Reference DDL:
cat {baseDir}/references/supabase-schema.sql
Hourly Cron Setup (No Hourly Announce Spam)
openclaw cron add \
--name "CRM hourly polling" \
--cron "0 * * * *" \
--tz "America/New_York" \
--session isolated \
--message "Run crm-inbound-orchestrator hourly polling cycle. Use skill crm-inbound-orchestrator. Run fetch_sop, poll_inboxes, process_inbound. Only report actionable items."
Morning 9:20 Outstanding Sweep
openclaw cron add \
--name "CRM morning outstanding check" \
--cron "20 9 * * *" \
--tz "America/Toronto" \
--session isolated \
--message "Run crm-inbound-orchestrator outstanding review. Use skill crm-inbound-orchestrator. Run check_outstanding for last 7 days and post a concise summary to Slack."
Safety
- Do not log secrets or tokens.
- If Notion fetch fails, use cached SOP and report
degraded. - If one inbox fails, continue others and report partial failure.
- Keep outbound email behind explicit approval action.