Skip to content

Hello World Bot

Let’s build a simple “Greeter” bot from scratch. By the end, you’ll have a working bot that greets users and remembers their names.

Prerequisites

  • Flexus running (either self-hosted or SaaS)
  • Python 3.10+ installed
  • flexus-client-kit package installed:
    Terminal window
    pip install flexus-client-kit
  • API key from your Flexus instance

Project Setup

  1. Create the directory structure:

    Terminal window
    mkdir -p greeter
    cd greeter
    touch __init__.py greeter_bot.py greeter_prompts.py greeter_install.py
  2. Set environment variables:

    Terminal window
    export FLEXUS_API_BASEURL=http://localhost:8000/ # or https://flexus.team/
    export FLEXUS_API_KEY=your-api-key
    export FLEXUS_WORKSPACE=your-workspace-id

Step 1: Define the Prompts

Create greeter_prompts.py:

greeter_prompts.py
"""
System prompts for the Greeter bot.
Kept separate from runtime code for easy editing and versioning.
"""
SYSTEM_PROMPT_DEFAULT = """You are Greeter, a friendly bot that welcomes users.
## Your Personality
- Warm and welcoming
- Remembers user names
- Uses appropriate greeting based on time of day
## Your Tools
### greet
Use this to generate a personalized greeting. Always use this tool when the user introduces themselves or asks for a greeting.
### remember_name
Use this to store the user's name for future conversations.
## How to Respond
1. When someone says hello, use the `greet` tool
2. If they tell you their name, use `remember_name` to save it
3. Be friendly but not overly enthusiastic
"""

Step 2: Create the Bot

Create greeter_bot.py:

greeter_bot.py
"""
Greeter Bot - A simple hello world bot for learning Flexus.
"""
import asyncio
from datetime import datetime
from typing import Dict, Any
from flexus_client_kit import ckit_client
from flexus_client_kit import ckit_cloudtool
from flexus_client_kit import ckit_bot_exec
from flexus_client_kit import ckit_shutdown
from greeter import greeter_install
BOT_NAME = "greeter"
BOT_VERSION = "1.0.0"
# --- Tool Definitions ---
# Tools must be defined with strict=True for OpenAI compatibility.
# All parameters go in "required", use ["type", "null"] for optional ones.
GREET_TOOL = ckit_cloudtool.CloudTool(
strict=True,
name="greet",
description="Generate a personalized greeting for a user.",
parameters={
"type": "object",
"properties": {
"name": {
"type": ["string", "null"],
"description": "The user's name. Null if unknown.",
},
"style": {
"type": "string",
"enum": ["formal", "casual", "enthusiastic"],
"description": "The greeting style to use.",
},
},
"required": ["name", "style"],
"additionalProperties": False,
},
)
REMEMBER_NAME_TOOL = ckit_cloudtool.CloudTool(
strict=True,
name="remember_name",
description="Store the user's name for future conversations.",
parameters={
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "The name to remember.",
},
},
"required": ["name"],
"additionalProperties": False,
},
)
# All tools this bot provides
TOOLS = [GREET_TOOL, REMEMBER_NAME_TOOL]
# --- Helper Functions ---
def get_time_of_day() -> str:
"""Returns 'morning', 'afternoon', or 'evening' based on current hour."""
hour = datetime.now().hour
if hour < 12:
return "morning"
elif hour < 17:
return "afternoon"
else:
return "evening"
def generate_greeting(name: str | None, style: str) -> str:
"""Generate a greeting based on name, style, and time of day."""
tod = get_time_of_day()
name_part = name if name else "friend"
greetings = {
"formal": {
"morning": f"Good morning, {name_part}. I hope you have a productive day.",
"afternoon": f"Good afternoon, {name_part}. How may I assist you?",
"evening": f"Good evening, {name_part}. How can I help you this evening?",
},
"casual": {
"morning": f"Hey {name_part}! Morning!",
"afternoon": f"Hi {name_part}! What's up?",
"evening": f"Hey {name_part}! How's it going?",
},
"enthusiastic": {
"morning": f"GOOD MORNING {name_part.upper()}! What an AMAZING day!",
"afternoon": f"HEY {name_part.upper()}! So great to see you!",
"evening": f"EVENING {name_part.upper()}! Let's make this evening AWESOME!",
},
}
return greetings.get(style, greetings["casual"]).get(tod, "Hello!")
# --- Main Bot Loop ---
async def greeter_main_loop(fclient: ckit_client.FlexusClient, rcx: ckit_bot_exec.RobotContext) -> None:
"""
Main loop for the Greeter bot.
rcx (RobotContext) provides:
- rcx.persona: The bot's persona configuration
- rcx.latest_threads: Active threads
- rcx.latest_tasks: Kanban tasks
- Decorators for event handlers
"""
# Merge default setup with user overrides
setup = ckit_bot_exec.official_setup_mixing_procedure(
greeter_install.greeter_setup_schema,
rcx.persona.persona_setup
)
# In-memory storage for names (in production, use MongoDB)
remembered_names: Dict[str, str] = {}
# --- Tool Handlers ---
# Each tool in TOOLS must have a handler decorated with @rcx.on_tool_call
@rcx.on_tool_call(GREET_TOOL.name)
async def handle_greet(toolcall: ckit_cloudtool.FCloudtoolCall, args: Dict[str, Any]) -> str:
"""
Handle the greet tool call.
Args:
toolcall: Contains fcall_id, fcall_ft_id (thread), etc.
args: The arguments the LLM provided
Returns:
String result that the LLM will see
"""
name = args.get("name")
style = args.get("style", "casual")
# Check if we have a remembered name for this thread
if not name:
name = remembered_names.get(toolcall.fcall_ft_id)
greeting = generate_greeting(name, style)
return greeting
@rcx.on_tool_call(REMEMBER_NAME_TOOL.name)
async def handle_remember_name(toolcall: ckit_cloudtool.FCloudtoolCall, args: Dict[str, Any]) -> str:
"""Store a user's name."""
name = args["name"]
remembered_names[toolcall.fcall_ft_id] = name
return f"Got it! I'll remember that your name is {name}."
# --- Event Handlers (optional) ---
@rcx.on_updated_message
async def on_message(msg):
"""Called when a new message arrives or is updated."""
pass # We don't need to do anything special here
@rcx.on_updated_thread
async def on_thread(thread):
"""Called when a thread is updated."""
pass
# --- Main Loop ---
# This loop runs until shutdown, processing events as they arrive
try:
while not ckit_shutdown.shutdown_event.is_set():
# This processes all queued events (messages, tool calls, etc.)
# and sleeps for up to 10 seconds if there's nothing to do
await rcx.unpark_collected_events(sleep_if_no_work=10.0)
finally:
# Cleanup code runs on shutdown
print(f"Greeter bot {rcx.persona.persona_id} shutting down")
# --- Entry Point ---
def main():
"""Entry point for running the bot."""
# Parse command line args (--scenario, --group, etc.)
scenario_fn = ckit_bot_exec.parse_bot_args()
# Create Flexus client
fclient = ckit_client.FlexusClient(
ckit_client.bot_service_name(BOT_NAME, BOT_VERSION),
endpoint="/v1/jailed-bot"
)
# Run the bot
asyncio.run(ckit_bot_exec.run_bots_in_this_group(
fclient,
marketable_name=BOT_NAME,
marketable_version_str=BOT_VERSION,
bot_main_loop=greeter_main_loop,
inprocess_tools=TOOLS,
scenario_fn=scenario_fn,
install_func=greeter_install.install,
))
if __name__ == "__main__":
main()

Step 3: Create the Install Script

Create greeter_install.py:

greeter_install.py
"""
Installation script for Greeter bot.
Run with: python greeter_install.py --ws=your_workspace_id
"""
import json
from flexus_client_kit import ckit_bot_install
from flexus_client_kit.ckit_bot_install import FMarketplaceExpertInput
from flexus_simple_bots import prompts_common
from greeter import greeter_bot, greeter_prompts
# Setup schema - defines user-configurable options
# These appear in the bot's setup dialog in the UI
greeter_setup_schema = {
"default_style": {
"bs_type": "string_short",
"bs_default": "casual",
"bs_group": "behavior",
"bs_description": "Default greeting style (formal, casual, enthusiastic)",
},
}
# Convert tools to JSON for expert definition
tools_json = json.dumps([t.openai_style_tool() for t in greeter_bot.TOOLS])
def install(ws_id: str):
"""Install the bot to the marketplace."""
return ckit_bot_install.marketplace_upsert_dev_bot(
ws_id=ws_id,
marketable_name="greeter",
marketable_version="1.0.0",
marketable_title1="Greeter",
marketable_title2="A friendly bot that welcomes users",
marketable_occupation="Welcomer",
marketable_author="Flexus Team",
marketable_description="""
Greeter is a simple bot that demonstrates Flexus bot development.
## Features
- Personalized greetings based on time of day
- Remembers user names
- Multiple greeting styles (formal, casual, enthusiastic)
## Example Usage
Just say hello and introduce yourself!
""",
marketable_typical_group="Assistants / Demo",
marketable_tags=["demo", "greeting", "hello-world"],
marketable_setup_schema=json.dumps(greeter_setup_schema),
# For demo, we'll skip images - in real bot, load them:
# marketable_picture_big_b64=ckit_bot_install.load_image_b64(__file__, "greeter-1024x1536.webp"),
# marketable_picture_small_b64=ckit_bot_install.load_image_b64(__file__, "greeter-256x256.webp"),
marketable_picture_big_b64="",
marketable_picture_small_b64="",
marketable_experts=[
("default", FMarketplaceExpertInput(
fexp_system_prompt=greeter_prompts.SYSTEM_PROMPT_DEFAULT,
fexp_app_capture_tools=tools_json,
)),
],
marketable_schedule=[
# This bot doesn't need schedules - it only responds to direct chat
],
)
if __name__ == "__main__":
ckit_bot_install.main_install_dev_bot(install)

Step 4: Install and Run

  1. Install to marketplace:

    Terminal window
    python greeter_install.py --ws=your_workspace_id

    You should see output like:

    Installed greeter version 1.0.0
  2. Hire the bot in UI:

    Go to Marketplace in the Flexus UI, find “Greeter”, and click “Hire”.

  3. Run the bot:

    Terminal window
    python greeter_bot.py

    The bot will connect and start listening for events.

  4. Test it:

    Open a chat with Greeter in the UI and say:

    Hello! My name is Alex.

    The bot should greet you and remember your name.

Understanding What Happened

  1. You sent a message — Stored in PostgreSQL, published to Redis
  2. Advancer picked it up — Called the LLM with your system prompt and tools
  3. LLM decided to use tools — Called remember_name then greet
  4. Tool calls routed to your bot — Via GraphQL subscription
  5. Your handlers executed — Returned results to backend
  6. LLM received results — Generated final response
  7. Response sent to you — Streamed back to the UI

Adding Persistence

The example stores names in memory. For real bots, use MongoDB:

from pymongo import AsyncMongoClient
from flexus_client_kit import ckit_mongo
async def greeter_main_loop(fclient, rcx):
# Get MongoDB credentials
mongo_conn_str = await ckit_mongo.mongo_fetch_creds(fclient, rcx.persona.persona_id)
mongo = AsyncMongoClient(mongo_conn_str)
db = mongo[rcx.persona.persona_id + "_db"]
names_collection = db["remembered_names"]
@rcx.on_tool_call(REMEMBER_NAME_TOOL.name)
async def handle_remember_name(toolcall, args):
name = args["name"]
await names_collection.update_one(
{"thread_id": toolcall.fcall_ft_id},
{"$set": {"name": name}},
upsert=True
)
return f"Got it! I'll remember that your name is {name}."
# ... rest of the code

Next Steps

Congratulations! You’ve built your first Flexus bot. Next: