booking-manager
# Booking Manager
An AI assistant layer that sits on top of any booking system, turning your phone into a
full booking management interface via Telegram, WhatsApp, or any supported channel.
## How It Works
```
Customer books → Data saved (DB/API/Sheet) → Agent polls for new bookings
↓
Notifies owner via phone (Telegram/WhatsApp)
↓
Owner replies: "confirm" / "reschedule" / "delete"
↓
Agent updates data + emails customer
```
## Setup
### 0. First-Run Onboarding
On any booking-related request, check if TOOLS.md contains a `## Business` section
AND a `## Services` section. If either is missing, this is a first-run — begin
onboarding before doing anything else.
**Primary flow (form paste):**
1. Greet the customer:
```
Hi! I'm your new booking assistant. 👋
To get started, please paste the completed onboarding form you received
and I'll set everything up from that.
If you don't have a form, just let me know and I'll walk you through
the setup step by step.
```
2. When the customer pastes the form, parse it for these fields:
| Field | Required | TOOLS.md Section |
|---|---|---|
| Business name | ✅ | `## Business` |
| Business address | Optional | `## Business` |
| Phone number | Optional | `## Business` |
| Website | Optional | `## Business` |
| Timezone | ✅ | `## Business` |
| Services (name, duration, price) | ✅ | `## Services` |
| Operating hours per day | ✅ | `## Operating Hours` |
| Confirmation email (name + address) | ✅ | `## Email` |
| Booking/cancellation policy | Optional | `## Booking Policy` |
| Existing booking system | Optional | `## Booking Data Source` |
| Notification preference | Optional | `## Notifications` |
| Mobile number | Optional | `## Notifications` |
| Additional notes | Optional | `## Notes` |
3. Write the parsed config to TOOLS.md:
```markdown
## Business
- Name: [business name]
- Address: [address]
- Phone: [phone]
- Website: [website]
- Timezone: [timezone]
## Services
- [Service 1]: [duration] min — $[price]
- [Service 2]: [duration] min — $[price]
## Operating Hours
- Monday: [open] – [close]
- Tuesday: [open] – [close]
- ...
- Sunday: Closed
## Email
- From: [Business Name] <[email address]>
## Booking Policy
- [policy text or "No specific policy"]
## Booking Data Source
- Type: [system mentioned or "pending setup"]
- Connection: [pending admin configuration]
## Notifications
- Channel: [preference]
- Mobile: [number]
```
4. Show a summary for confirmation:
```
✅ All set! Here's what I've got:
📋 **[Business Name]**
📍 [address]
🕐 [hours summary]
**Services:**
• [Service 1] — [duration] min — $[price]
• [Service 2] — [duration] min — $[price]
**Confirmations from:** [email]
**Policy:** [policy summary]
Everything look right? If you need to change anything, just tell me.
```
5. Note about data source: "I'll need your booking system connected before I can
see bookings — your admin will set that up for you."
**Security:** The onboarding flow collects business information only (name, services,
hours, policy). It must NEVER ask for or accept credentials (passwords, tokens, API
keys) through chat. Credentials are configured by the admin directly in `openclaw.json`
under `env`. If a customer pastes credentials in chat, do NOT store them — instruct
them to contact their admin instead.
**Fallback flow (step-by-step):**
If the customer says they don't have a form, collect info conversationally:
1. "What's your business called?"
2. "What services do you offer? For each one, I'll need the name, how long it takes, and the price."
3. "What days and hours are you open?"
4. "What timezone are you in?"
5. "What email address should booking confirmations come from?"
6. "Do you have any booking or cancellation policies?"
7. "Anything else I should know about how you run bookings?"
Write to TOOLS.md using the same format and show the same summary.
**Validation:**
- Missing required fields → ask specifically: "I noticed [field] is blank — could you fill that in?"
- Ambiguous services (no duration/price) → ask: "How long does [service] take, and what do you charge?"
- Timezone → accept common formats (AEST, Australia/Melbourne, GMT+10), normalise to IANA
- Hours → accept 9am-5pm, 0900-1700, 9:00 AM - 5:00 PM, normalise consistently
**Edge cases:**
- Partial form pasted → parse what's there, ask for the rest
- Unrelated text pasted → "That doesn't look like the onboarding form. Try pasting it again, or I'll walk you through setup."
- Customer wants to change after setup → "Sure! Just tell me what to change."
- TOOLS.md already has config → skip onboarding, booking-manager handles normally
The onboarding form template is in `references/onboarding-form.md`.
### 1. Identify the data source
Determine how the business stores bookings. Read `references/data-sources.md` for
connection patterns for each supported platform.
### 2. Configure credentials
Store connection details as **environment variables** in `openclaw.json` under `env`,
never in plaintext in TOOLS.md or any workspace file. Reference them in TOOLS.md by
name only:
```markdown
## Booking Data Source
- Type: [turso | postgres | google-sheets | api]
- Env vars configured: yes/no
## Email
- From: [Business Name] <business@email.com>
- SMTP env vars configured: yes/no
```
**Never store credentials in plaintext in TOOLS.md, SOUL.md, or any workspace file.**
See `references/data-sources.md` for which environment variables each data source expects.
### 3. Set up heartbeat polling
Add to HEARTBEAT.md to check for new bookings every 15-30 minutes:
```markdown
## Check for new bookings
- Query the data source for bookings created since last check
- If new bookings found: notify the owner with details and send acknowledgement email
```
### 4. Configure the agent identity
Set SOUL.md with the business context:
```markdown
You are the booking manager for **[Business Name]**.
## Your Role
- Monitor for new booking enquiries and notify the owner on their phone
- Confirm, reschedule, or delete bookings when instructed
- Send professional emails to customers
- Provide schedule summaries on demand
## Rules
- All times in [timezone]
- Always clean up booking locks when confirming or deleting
- Send calendar invites (.ics) when confirming
```
## Core Workflows
### New booking notification
When a new booking is detected, notify the owner:
```
📋 New booking enquiry!
Name: [name]
Service: [service] ([duration] min)
Date: [formatted date and time]
Phone: [phone]
Email: [email]
Reply: "confirm [id]", "reschedule [id] to [date] [time]", or "delete [id]"
```
Send an acknowledgement email to the customer. See `references/email-templates.md`.
### Confirm booking
1. Mark booking as confirmed in data source
2. Remove any booking lock for the customer's email
3. Send confirmation email with .ics calendar invite attached
4. Notify owner: "✅ Booking #[id] confirmed. Email sent to [name]."
### Reschedule booking
1. Update date/time in data source
2. Remove booking lock
3. Delete existing reminder record (so a new reminder sends for the updated time)
4. Send updated confirmation email with new .ics
5. Notify owner: "✅ Booking #[id] rescheduled to [new date/time]. Email sent."
### Delete booking
1. Record the customer email before deleting
2. Delete the booking from data source
3. Remove booking lock
4. Optionally send cancellation email
5. Notify owner: "🗑️ Booking #[id] deleted."
### Schedule queries
Respond naturally to:
- "What bookings do I have today?"
- "Show this week's schedule"
- "How many bookings this month?"
- "Any new bookings?"
## Calendar Invites
Generate .ics files when confirming. See `references/ics-format.md` for the template
and timezone/DST conversion logic.
## Email Sending
Send via Gmail SMTP using environment variables for credentials (never inline).
See `references/email-templates.md` for HTML templates and the secure sending pattern.
## Booking Locks
Many booking systems use a lock/hold mechanism to prevent duplicate pending enquiries
from the same customer. **Always** release locks when confirming or deleting a booking,
otherwise the customer cannot book again.
## Automated Reminder Emails
Send reminder emails to customers 24 hours before their appointment. This feature is
added to the heartbeat/cron polling cycle alongside new booking checks.
### Setup
Add a `booking_reminders` table to the data source to track sent reminders and prevent
duplicates. See `references/data-sources.md` for the schema.
Add reminder configuration to TOOLS.md:
```markdown
## Reminders
- Lead time: 24h (how far before the appointment to send)
- Window: ±1h (send if appointment is 23–25h away — accounts for polling gaps)
- Include cancel/reschedule info: [yes | no]
- Custom footer: [optional policy reminder text, e.g. "Cancellations within 48h..."]
```
The cancel/reschedule option and footer text are **entirely business-specific**. Some
businesses allow changes up until the appointment; others enforce strict late-cancellation
penalties. Configure per client.
### Heartbeat integration
Add to HEARTBEAT.md alongside the new-booking check:
```markdown
## Send appointment reminders
- Query for confirmed bookings with appointments 23–25 hours from now
- Skip any booking IDs already in the booking_reminders table
- For each eligible booking: send reminder email, then record in booking_reminders
- If any reminders sent: notify owner "📬 Sent [n] reminder(s) for tomorrow's appointments"
```
### Workflow
1. Query confirmed bookings where appointment time is 23–25 hours from now
2. Left-join against `booking_reminders` to exclude already-sent reminders
3. For each unsent reminder:
a. Send reminder email (see `references/email-templates.md`)
b. Insert a record into `booking_reminders` with the booking ID and timestamp
4. Notify the owner with a summary (if any were sent)
### Reminder query (Turso/SQLite example)
```sql
SELECT b.*
FROM bookings b
LEFT JOIN booking_reminders r ON b.id = r.booking_id
WHERE b.status = 'confirmed'
AND b.appointment_datetime_utc > datetime('now', '+23 hours')
AND b.appointment_datetime_utc <= datetime('now', '+25 hours')
AND r.booking_id IS NULL;
```
### Edge cases
- **Polling gaps:** The ±1 hour window ensures reminders aren't missed if a heartbeat
runs slightly late or early. The `booking_reminders` table prevents duplicates even
if the same booking falls in the window across multiple polls.
- **Already passed:** If the agent was offline and missed the 24h window, do NOT send
a late reminder — it's confusing. Only send if the appointment is still >22h away.
- **Deleted/rescheduled bookings:** If a booking is rescheduled, the old reminder record
stays (harmless). The new appointment time will trigger a fresh reminder since the
booking ID changes or the UTC time no longer matches. If using the same booking ID
after reschedule, delete the old reminder record when rescheduling so a new one sends.
## Adapting to Different Businesses
Customise these per client:
- Business name and branding in email templates
- Services list with durations (for calendar invite end times)
- Operating hours and timezone
- Booking policy text
- Reminder settings (lead time, cancel/reschedule option, policy footer)
- Data source connection method
标签
skill
ai