Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 2 additions & 15 deletions flexus_simple_bots/karen/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
### Job description

Karen is your all-in-one customer support, sales, and marketing agent. She answers support questions with precision and full context, sells consultatively using the C.L.O.S.E.R. framework, manages your CRM, runs outreach through email, and nurtures leads with automated follow-ups. She qualifies with BANT, reads sentiment to adapt her approach, and knows when to hand off to a human.
Karen is your customer support agent. She answers support questions with precision and full context, manages your CRM, reads sentiment to adapt her approach, and knows when to hand off to a human.

### How Karen can help you:

Expand All @@ -10,24 +10,11 @@ Karen is your all-in-one customer support, sales, and marketing agent. She answe
- Escalates to the right person when she can't resolve it
- Tracks patterns and flags repeated issues

*Marketing:*
*CRM & Marketing:*
- Manages your CRM and imports contacts from CSV files or landing pages
- Sends automatic welcome emails to new contacts
- Runs outreach campaigns through email integration
- Builds CRM automations with custom triggers and actions
- Handles company and product setup so your CRM reflects your actual business

*Sales:*
- Sells consultatively using the C.L.O.S.E.R. Framework
- Qualifies leads with BANT (Budget, Authority, Need, Timeline)
- Detects sentiment in conversations and adapts accordingly
- Executes smart handoffs to human agents when the moment calls for it

*Nurturing:*
- Runs lightweight automated tasks to keep leads warm between touchpoints
- Sends emails using pre-built templates for consistent, on-brand communication
- Triggers follow-ups based on CRM activity so no lead goes cold by accident

*Shopify (optional):*
- Connects your Shopify store and syncs products, orders, and payments automatically
- Creates draft orders with checkout links directly from conversations
17 changes: 1 addition & 16 deletions flexus_simple_bots/karen/karen_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
from flexus_client_kit import erp_schema
from flexus_client_kit import ckit_mongo
from flexus_client_kit.integrations import fi_mongo_store
from flexus_client_kit.integrations import fi_crm_automations
from flexus_client_kit.integrations import fi_resend
from flexus_client_kit.integrations import fi_shopify
from flexus_client_kit.integrations import fi_telegram
Expand All @@ -45,7 +44,6 @@
KAREN_SETUP_SCHEMA = json.loads((KAREN_ROOTDIR / "setup_schema.json").read_text())
KAREN_SETUP_SCHEMA += (
fi_shopify.SHOPIFY_SETUP_SCHEMA
+ fi_crm_automations.CRM_AUTOMATIONS_SETUP_SCHEMA
+ fi_crm.CRM_SETUP_SCHEMA
+ fi_resend.RESEND_SETUP_SCHEMA
+ fi_slack.SLACK_SETUP_SCHEMA
Expand Down Expand Up @@ -196,9 +194,7 @@

TOOLS = [
fi_mongo_store.MONGO_STORE_TOOL,
fi_crm_automations.CRM_AUTOMATION_TOOL,
fi_shopify.SHOPIFY_TOOL,
fi_shopify.SHOPIFY_CART_TOOL,
fi_sched.SCHED_TOOL,
fi_repo_reader.REPO_READER_TOOL,
SUPPORT_STATUS_TOOL,
Expand Down Expand Up @@ -386,9 +382,6 @@ async def karen_main_loop(fclient: ckit_client.FlexusClient, rcx: ckit_bot_exec.
setup = ckit_bot_exec.official_setup_mixing_procedure(KAREN_SETUP_SCHEMA, rcx.persona.persona_setup)

integrations = await ckit_integrations_db.main_loop_integrations_init(KAREN_INTEGRATIONS, rcx, setup)
automations_integration = fi_crm_automations.IntegrationCrmAutomations(
fclient, rcx, setup, available_erp_tables=ERP_TABLES,
)
pdoc_integration: fi_pdoc.IntegrationPdoc = integrations["flexus_policy_document"]
email_respond_to = set(a.strip().lower() for a in setup.get("EMAIL_RESPOND_TO", "").split(",") if a.strip())
shopify = fi_shopify.IntegrationShopify(fclient, rcx)
Expand Down Expand Up @@ -452,18 +445,10 @@ async def handle_email(emsg):
async def toolcall_mongo_store(toolcall: ckit_cloudtool.FCloudtoolCall, model_produced_args: Dict[str, Any]) -> str:
return await fi_mongo_store.handle_mongo_store(rcx, toolcall, model_produced_args)

@rcx.on_tool_call(fi_crm_automations.CRM_AUTOMATION_TOOL.name)
async def toolcall_crm_automation(toolcall: ckit_cloudtool.FCloudtoolCall, model_produced_args: Dict[str, Any]) -> str:
return await automations_integration.handle_crm_automation(toolcall, model_produced_args)

@rcx.on_tool_call(fi_shopify.SHOPIFY_TOOL.name)
async def toolcall_shopify(toolcall: ckit_cloudtool.FCloudtoolCall, model_produced_args: Dict[str, Any]) -> str:
return await shopify.called_by_model(toolcall, model_produced_args)

@rcx.on_tool_call(fi_shopify.SHOPIFY_CART_TOOL.name)
async def toolcall_shopify_cart(toolcall: ckit_cloudtool.FCloudtoolCall, model_produced_args: Dict[str, Any]) -> str:
return await shopify.handle_cart(toolcall, model_produced_args)

@rcx.on_tool_call(fi_sched.SCHED_TOOL.name)
async def toolcall_sched(toolcall: ckit_cloudtool.FCloudtoolCall, model_produced_args: Dict[str, Any]) -> str:
return await sched.called_by_model(toolcall, model_produced_args)
Expand Down Expand Up @@ -567,7 +552,7 @@ async def on_task_update(action: str, old_task: Optional[ckit_kanban.FPersonaKan
await ckit_kanban.bot_kanban_post_into_inbox(
await fclient.use_http_on_behalf(rcx.persona.persona_id, ""),
rcx.persona.persona_id,
title="Read linked thread, find/create contact, log activity, score BANT: %s" % new_task.ktask_title[:60],
title="Read linked thread, find/create contact, log activity: %s" % new_task.ktask_title[:60],
details_json=json.dumps({
"spawned_from_ktask_id": new_task.ktask_id,
"spawned_from_title": new_task.ktask_title,
Expand Down
50 changes: 10 additions & 40 deletions flexus_simple_bots/karen/karen_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,8 @@
"mongo_store",
"flexus_fetch_skill",
"print_widget",
"crm_automation",
"flexus_schedule",
"shopify",
"shopify_cart",
"erp_table_meta",
"erp_table_data",
"erp_table_crud",
Expand All @@ -38,7 +36,7 @@

TOOLS_SUPPORT_AND_SALES = {
"flexus_policy_document", "mongo_store", "flexus_fetch_skill",
"product_catalog", "shopify_cart",
"product_catalog",
"crm_contact_info", "verify_email",
"email_reply",
"magic_desk", "slack", "telegram", "discord",
Expand All @@ -49,15 +47,6 @@
"erp_table_meta", "erp_table_data", "erp_table_crud",
} | ckit_cloudtool.KANBAN_SAFE

TOOLS_NURTURING = {
"flexus_policy_document", "mongo_store", "flexus_fetch_skill",
"shopify_cart",
"erp_table_meta", "erp_table_data", "erp_table_crud",
"crm_contact_info",
"email_send",
"magic_desk", "slack", "telegram", "discord",
} | ckit_cloudtool.KANBAN_TRIAGE | ckit_cloudtool.CLOUDTOOLS_VECDB | ckit_cloudtool.CLOUDTOOLS_WEB | ckit_cloudtool.CLOUDTOOLS_MCP


KAREN_DESC = (karen_bot.KAREN_ROOTDIR / "README.md").read_text()

Expand Down Expand Up @@ -108,14 +97,11 @@
fexp_allow_tools=",".join(TOOLS_DEFAULT),
fexp_nature="NATURE_INTERACTIVE",
fexp_inactivity_timeout=3600,
fexp_description="Marketing assistant for CRM management, contact import, automated outreach, company/product setup, and support knowledge base configuration.",
fexp_description="Support assistant for CRM management, contact import, company/product setup, and support knowledge base configuration.",
fexp_builtin_skills=ckit_skills.read_name_description(karen_bot.KAREN_ROOTDIR, [
"stall-deals",
"collect-support-knowledge-base",
"store-setup",
"welcome-email-setup",
"resend-email-setup",
"sales-pipeline-setup",
"crm-import-landing-pages",
"crm-automations",
]),
Expand All @@ -136,7 +122,7 @@
fexp_nature="NATURE_AUTONOMOUS",
fexp_inactivity_timeout=600,
fexp_model_class="cheap",
fexp_description="Customer-facing expert: answers support questions from knowledge base, conducts sales conversations using C.L.O.S.E.R. framework, qualifies leads with BANT.",
fexp_description="Customer-facing expert: answers support questions from knowledge base, handles pre-purchase recommendations using C.L.O.S.E.R. framework.",
)),
("post_conversation", ckit_bot_install.FMarketplaceExpertInput(
fexp_system_prompt=karen_prompts.KAREN_POST_CONVERSATION,
Expand All @@ -145,21 +131,8 @@
fexp_nature="NATURE_AUTONOMOUS",
fexp_inactivity_timeout=300,
fexp_model_class="cheap",
fexp_description="Runs after customer conversations to log CRM activities, create/update contacts, and record BANT scores.",
fexp_builtin_skills=ckit_skills.read_name_description(karen_bot.KAREN_ROOTDIR, [
"log-crm-activity",
]),
)),
("nurturing", ckit_bot_install.FMarketplaceExpertInput(
fexp_system_prompt=karen_prompts.KAREN_NURTURING,
fexp_python_kernel="",
fexp_allow_tools=",".join(TOOLS_NURTURING),
fexp_nature="NATURE_SEMI_AUTONOMOUS",
fexp_inactivity_timeout=600,
fexp_description="Lightweight expert for automated tasks: sending templated emails, follow-ups, stall deal recovery, and simple CRM operations.",
fexp_model_class="cheap",
fexp_description="Runs after customer conversations to log CRM activities and create/update contacts.",
fexp_builtin_skills=ckit_skills.read_name_description(karen_bot.KAREN_ROOTDIR, [
"stall-recovery",
"log-crm-activity",
]),
)),
Expand All @@ -186,30 +159,27 @@ async def install(client: ckit_client.FlexusClient):
bot_dir=karen_bot.KAREN_ROOTDIR,
marketable_accent_color="#6252A4",
marketable_title1="Karen",
marketable_title2="Your 24/7 support, sales & marketing agent — empathetic, accurate, and always closing.",
marketable_title2="Your 24/7 support agent — empathetic, accurate, and always helpful.",
marketable_author="Flexus",
marketable_occupation="Support, Sales & Marketing",
marketable_occupation="Support & CRM",
marketable_description=KAREN_DESC,
marketable_typical_group="Sales",
marketable_typical_group="Support",
marketable_setup_default=karen_bot.KAREN_SETUP_SCHEMA,
marketable_featured_actions=[
{"feat_question": "Collect Support Knowledge Base"},
{"feat_question": "Test How Karen Answers Support Questions"},
{"feat_question": "Add Karen to Your Website"},
{"feat_question": "Set Up Human Escalation"},
{"feat_question": "Connect WhatsApp, Telegram, or Email"},
# {"feat_question": "Set Up Welcome Emails"},
# {"feat_question": "Set Up Sales Pipeline"},
# {"feat_question": "Work on Stalled-Deal Strategy"},
],
marketable_intro_message="Hi! I'm Karen — your support, sales, and marketing assistant. I can answer customer questions, manage your CRM, run email automations, import contacts, and handle sales conversations. What would you like to work on?",
marketable_intro_message="Hi! I'm Karen — your support assistant. I can answer customer questions, manage your CRM, run email automations, and import contacts. What would you like to work on?",
marketable_preferred_model_expensive="grok-4-1-fast-reasoning",
marketable_preferred_model_cheap="gpt-5.4-nano",
marketable_daily_budget_default=10_000_000,
marketable_default_inbox_default=1_000_000,
marketable_max_inprogress=10,
marketable_experts=[(name, exp.filter_tools(karen_bot.TOOLS)) for name, exp in EXPERTS],
marketable_tags=["Customer Support", "Sales", "Marketing", "CRM", "Email", "Automation", "Shopify", "E-commerce"],
marketable_tags=["Customer Support", "CRM", "Email", "Automation", "Shopify", "E-commerce"],
marketable_schedule=[
prompts_common.SCHED_TASK_SORT_10M | {"sched_when": "EVERY:1m", "sched_fexp_name": "messages_triage"},
prompts_common.SCHED_TODO_5M | {"sched_when": "EVERY:1m"},
Expand All @@ -233,7 +203,7 @@ async def install(client: ckit_client.FlexusClient):
"im:read",
],
},
marketable_required_policydocs=["/company/summary", "/company/sales-strategy", "/support/summary"],
marketable_required_policydocs=["/company/summary", "/support/summary"],
marketable_features=["magic_desk"],
add_integrations_into_expert_system_prompt=karen_bot.KAREN_INTEGRATIONS,
)
Expand Down
59 changes: 1 addition & 58 deletions flexus_simple_bots/karen/karen_prompts.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,15 +182,6 @@

Match energy: if positive and engaged, deepen and move toward close. If frustrated (curt, ALL CAPS), acknowledge and offer alternatives or a human. If skeptical, validate caution, provide proof. If confused, simplify.

## BANT Lead Qualification

During sales conversations, naturally gather BANT signals — you don't need to store them, another expert
handles CRM after the conversation ends. Just make sure the conversation surfaces this info:

- **Budget**: do they have budget allocated or willingness to invest?
- **Authority**: are they the decision-maker or a strong influencer?
- **Need**: is there an urgent problem or are they just browsing?
- **Timeline**: are they buying within 0-3 months?
"""

KAREN_POST_CONVERSATION = """
Expand All @@ -204,55 +195,7 @@
- email:user@example.com → erp_table_data(table_name="crm_contact", options={"filters": "contact_email:CIEQL:user@example.com"})
3. No contact found? Create one with whatever info you can get from the conversation.
4. Log the activity (fetch log-crm-activity skill).
5. If the conversation has enough info for BANT qualification, update the contact.
Set contact_bant_score to the sum of the four 0/1 scores (0-4), and contact_details.bant, example:
```json
{
"budget": 0,
"budget_reason": "No budget mentioned, seems to be exploring",
"authority": 1,
"authority_reason": "CTO, makes purchasing decisions",
"need": 1,
"need_reason": "Complained about current solution being slow",
"timeline": 0,
"timeline_reason": "Vague about timing, no commitment"
}
```
- **Budget** (0/1): do they have budget allocated or willingness to invest?
- **Authority** (0/1): are they the decision-maker or a strong influencer?
- **Need** (0/1): is there an urgent problem or are they just browsing?
- **Timeline** (0/1): are they buying within 0-3 months?
6. If the contact has a deal, move it forward between stages if the conversation justifies it.
7. Resolve the task.
5. Resolve the task.

Be fast. Don't overthink. Don't ask questions.
"""


KAREN_NURTURING = KAREN_PERSONALITY + "\n" + KAREN_KB + "\n" + EMAIL_GUARDRAILS + "\n" + """
# Task Executor

You execute marketing and sales tasks quickly and autonomously: send emails from templates, follow up with
contacts who haven't replied, simple status checks. Act immediately, don't overthink.

## Where to Find Information

Email templates and company info are in policy documents under /sales-pipeline and /company.
When a task involves a contact, check if they have a deal and whether it should move stages.
Move deals forward when it makes sense, especially if there are rules or guidelines for it.
Don't move deals backward unless explicitly told to.

## Follow-up Logic

1. Check contact's last activity
2. If there's no Outbound activity at all, skip follow-up - nothing to follow up on
3. If no reply/response (CRM Activity in Inbound direction, after last Outbound contact/conversation), send follow-up
4. Activities are logged automatically

## Execution Style

- Use templates as-is, only substitute variables (name, company, etc.)
- Report completion briefly
- Don't manually add tags for welcome/follow-up emails - automations handle that
- Never ignore client inquiries from webchat, messaging platforms, or DMs
"""
28 changes: 0 additions & 28 deletions flexus_simple_bots/karen/skills/sales-pipeline-setup/SKILL.md

This file was deleted.

Loading