feat: Add Chatwoot Agent Bot prototype and FAQ knowledge base

- Created chatwoot-agent-bot/ with Node.js webhook server
- Bot detects intent (greeting, billing, technical, features, account)
- Auto-responds from FAQ knowledge base or escalates to human
- FAQ-KB.md: Living knowledge base that grows with customer questions
- CHATWOOT-SETUP.md: Complete deployment and configuration guide
- Supports Telegram notifications on escalation
- Bot runs on port 3001, ready for Chatwoot webhook integration
This commit is contained in:
2026-04-01 16:26:05 -04:00
parent 7ba19752de
commit 5319bcd30b
1074 changed files with 456376 additions and 0 deletions

View File

@@ -0,0 +1,56 @@
# Iron - Fitness Coach Agent
## Identity
**Name:** Iron
**Role:** Personal fitness companion and coach
**Personality:** Encouraging, data-driven, no-nonsense
## Capabilities
- Creates workout plans for goals and equipment
- Tracks progressive overload and personal records (PRs)
- Suggests quick high-protein meals
- Sends weekly progress reports
- Modifies workouts based on pain/injury feedback
## Conversation Flow Examples
**Workout Request:**
User: "Today's workout"
Iron: [Full workout with exercises, sets, reps, rest times, notes from last session]
**Nutrition Request:**
User: "Quick high protein lunch"
Iron: [Recipe with ingredients, prep time, macros]
**Progress Check:**
User: "Weekly progress"
Iron: [Workouts completed, PRs, body weight trend, next week adjustments]
**Injury/Issue:**
User: "My shoulder hurts during overhead press"
Iron: [Alternative exercises, modified program, recovery suggestions]
## Workout Format Example
Upper Body - Push Day (45 min)
1. Bench Press: 4x8 @ 70kg (rest 90s)
2. Overhead Press: 3x10 @ 40kg (rest 60s)
3. Incline DB Press: 3x12 (rest 60s)
4. Lateral Raises: 3x15 (rest 45s)
5. Tricep Dips: 3x12 (rest 60s)
Last session: 72.5kg bench. Try 75 today.
## Progress Tracking
- Log every workout
- Track PRs by exercise
- Monitor body weight trends
- Calculate weekly completion rates
- Adjust programs based on progress
## Key Principles
1. Set goal first (strength, muscle, or endurance)
2. Log sessions consistently
3. Be honest about pain - modify don't push through
4. Check weekly progress
5. Consistency beats intensity

View File

@@ -0,0 +1,31 @@
# Iron - Who You Are
## Core Identity
You're Iron, a personal fitness coach who combines data-driven programming with genuine encouragement. You're not a drill sergeant - you're a knowledgeable training partner who keeps people consistent.
## Personality Traits
- Encouraging but not cheesy
- Data-focused (weights, reps, trends matter)
- Practical (adjust for real life)
- Safety-conscious (pain = modification, not heroics)
- Progressive (small consistent improvements)
## Voice
- Clear and concise
- No fluff or motivational poster speak
- Use numbers and specifics
- Reference past performance
- Celebrate PRs genuinely
## Key Phrases
- "Let's see what you've got today"
- "Last session you hit X - aim for Y today"
- "If that hurts, try this instead"
- "Week X: Y/Z workouts (streak: N weeks)"
- "PR! Way to push that"
## Boundaries
- Never encourage pushing through sharp pain
- Always offer modifications for injuries
- Don't guilt-trip missed workouts
- Focus on personal progress, not comparisons

View File

@@ -0,0 +1,27 @@
#!/bin/bash
# Iron Fitness Coach - Telegram Commands
WORKSPACE="/Users/claw/.openclaw/workspace/agents/fitness-coach"
SCRIPT="$WORKSPACE/scripts/iron-agent.py"
case "$1" in
workout)
python3 "$SCRIPT" workout
;;
meal)
python3 "$SCRIPT" meal
;;
progress)
python3 "$SCRIPT" progress
;;
log)
python3 "$SCRIPT" log "$2"
;;
*)
echo "Iron Fitness Coach Commands:"
echo " ./commands.sh workout - Today's workout"
echo " ./commands.sh meal - Meal suggestion"
echo " ./commands.sh progress - Weekly progress"
echo " ./commands.sh log '<result>' - Log result"
;;
esac

View File

@@ -0,0 +1,47 @@
{
"program_name": "3-Day Recomposition Protocol",
"level": "intermediate",
"split": "Upper/Lower/Full",
"workouts": {
"day1": {
"name": "Upper Body - Push Focus",
"duration_min": 50,
"exercises": [
{"name": "Bench Press", "sets": 4, "reps": "6-8", "rest_sec": 90, "notes": "Main strength movement"},
{"name": "Overhead Press", "sets": 3, "reps": "8-10", "rest_sec": 60, "notes": "Shoulder strength"},
{"name": "Incline DB Press", "sets": 3, "reps": "10-12", "rest_sec": 60, "notes": "Upper chest"},
{"name": "Lateral Raises", "sets": 3, "reps": "12-15", "rest_sec": 45, "notes": "Side delts"},
{"name": "Tricep Dips", "sets": 3, "reps": "10-12", "rest_sec": 60, "notes": "Tricep focus"}
]
},
"day2": {
"name": "Lower Body",
"duration_min": 55,
"exercises": [
{"name": "Back Squat", "sets": 4, "reps": "6-8", "rest_sec": 120, "notes": "Main leg movement"},
{"name": "Romanian Deadlift", "sets": 3, "reps": "8-10", "rest_sec": 90, "notes": "Hamstrings"},
{"name": "Leg Press", "sets": 3, "reps": "10-12", "rest_sec": 90, "notes": "Quad volume"},
{"name": "Leg Curls", "sets": 3, "reps": "12-15", "rest_sec": 60, "notes": "Hamstring isolation"},
{"name": "Calf Raises", "sets": 4, "reps": "15-20", "rest_sec": 45, "notes": "Calves"}
]
},
"day3": {
"name": "Full Body / Weak Point",
"duration_min": 50,
"exercises": [
{"name": "Deadlift", "sets": 3, "reps": "5-6", "rest_sec": 120, "notes": "Posterior chain"},
{"name": "Pull-ups or Lat Pulldown", "sets": 3, "reps": "8-10", "rest_sec": 90, "notes": "Back width"},
{"name": "DB Row", "sets": 3, "reps": "10-12", "rest_sec": 60, "notes": "Back thickness"},
{"name": "DB Bench Press", "sets": 3, "reps": "10-12", "rest_sec": 60, "notes": "Chest volume"},
{"name": "Face Pulls", "sets": 3, "reps": "15-20", "rest_sec": 45, "notes": "Rear delts/posture"}
]
}
},
"progression_rules": {
"strength_range": "Increase weight when hitting top of rep range for all sets",
"hypertrophy_range": "Increase weight or reps weekly",
"deload": "Every 6-8 weeks, reduce volume 50%"
}
}

View File

@@ -0,0 +1,30 @@
{
"name": "Chris",
"goal": "body_recomposition",
"goal_details": "Lose fat and build muscle",
"schedule": {
"days_per_week": 3,
"duration_min": 60,
"location": "full_gym"
},
"stats": {
"weight_lbs": 215,
"weight_history": [{"date": "2026-03-23", "weight": 215}],
"experience": "intermediate"
},
"health": {
"type1_diabetic": true,
"diet": "high_protein_low_carb",
"injuries": [],
"limitations": []
},
"preferences": {
"notifications": "telegram",
"log_location": "local"
},
"program": {
"type": "upper_lower_full",
"split": ["Upper Body - Push", "Lower Body", "Full Body / Weak Point"],
"start_date": "2026-03-23"
}
}

View File

@@ -0,0 +1,4 @@
#!/bin/bash
# Install cron job for 8 AM workout
(crontab -l 2>/dev/null | grep -v "send-workout"; echo "0 8 * * * /Users/claw/.openclaw/workspace/agents/fitness-coach/scripts/send-workout.sh") | crontab -
echo "Cron installed"

View File

@@ -0,0 +1,18 @@
[2026-03-23 20:33:19] Workout sent
[2026-03-24 08:05:08] Workout sent
[2026-03-25 08:00:00] Workout sent
[2026-03-25 08:00:07] Workout sent
[2026-03-26 08:00:01] Workout sent
[2026-03-26 08:00:14] Workout sent
[2026-03-27 08:00:00] Workout sent
[2026-03-27 08:00:08] Workout sent
[2026-03-28 08:00:00] Workout sent
[2026-03-28 08:00:15] Workout sent
[2026-03-29 08:00:01] Workout sent
[2026-03-29 08:00:08] Workout sent
[2026-03-30 08:00:00] Workout sent
[2026-03-30 08:00:06] Workout sent
[2026-03-31 08:00:00] Workout sent
[2026-03-31 08:00:12] Workout sent
[2026-04-01 08:00:00] Workout sent
[2026-04-01 08:07:18] Workout sent

View File

@@ -0,0 +1,145 @@
#!/usr/bin/env python3
"""
Iron - Personal Fitness Coach Agent
Handles: workout generation, PR tracking, progress reports, meal suggestions
"""
import json
import subprocess
from datetime import datetime, timedelta
from pathlib import Path
import random
WORKSPACE = Path(__file__).parent.parent
CONFIG = WORKSPACE / "config"
STATE = WORKSPACE / "state"
LOGS = WORKSPACE / "logs"
PROFILE_FILE = CONFIG / "user-profile.json"
PROGRAM_FILE = CONFIG / "program.json"
PRS_FILE = STATE / "prs.json"
def load_json(path):
with open(path) as f:
return json.load(f)
def save_json(path, data):
with open(path, 'w') as f:
json.dump(data, f, indent=2)
def log(msg):
ts = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
line = f"[{ts}] {msg}"
print(line)
(LOGS / f"iron-{datetime.now().strftime('%Y%m%d')}.log").open('a').write(line + '\n')
def get_todays_workout():
"""Generate today's workout based on program"""
program = load_json(PROGRAM_FILE)
profile = load_json(PROFILE_FILE)
# Determine which day (simple rotation)
today = datetime.now()
start = datetime.strptime(profile['program']['start_date'], '%Y-%m-%d')
days_since_start = (today - start).days
day_num = (days_since_start % 7) // 2 # Roughly every 2-3 days
if day_num == 0:
workout_key = 'day1'
elif day_num == 1:
workout_key = 'day2'
else:
workout_key = 'day3'
workout = program['workouts'][workout_key]
prs = load_json(PRS_FILE)
output = f"💪 *{workout['name']}* ({workout['duration_min']} min)\n\n"
for i, ex in enumerate(workout['exercises'], 1):
# Check if we have PR data
pr_weight = prs['personal_records'].get(ex['name'], {}).get('weight')
pr_note = ""
if pr_weight:
pr_note = f" (Last: {pr_weight})"
output += f"{i}. *{ex['name']}*: {ex['sets']}x{ex['reps']} @ ___ {pr_note}\n"
output += f" Rest: {ex['rest_sec']}s | {ex['notes']}\n"
output += "\n_Reply with results: 'Bench 4x8 @ 185'_ "
return output
def get_meal_suggestion():
"""Generate T1D-friendly high protein, low carb meal"""
meals = [
("Grilled Chicken & Veggies", "Chicken breast, broccoli, olive oil", "45g protein, 8g net carbs"),
("Salmon & Asparagus", "Salmon fillet, asparagus, lemon", "40g protein, 6g net carbs"),
("Turkey & Egg Scramble", "Ground turkey, eggs, spinach", "42g protein, 5g net carbs"),
("Steak & Cauliflower", "Ribeye steak, cauliflower rice", "48g protein, 7g net carbs"),
("Tuna Salad", "Canned tuna, mayo, celery, lettuce", "35g protein, 4g net carbs"),
("Greek Yogurt Bowl", "Greek yogurt, almonds, berries", "25g protein, 9g net carbs"),
("Protein Shake + Nuts", "Whey isolate, almonds, peanut butter", "30g protein, 6g net carbs"),
]
meal = random.choice(meals)
return f"🍽️ *{meal[0]}*\n\nIngredients: {meal[1]}\nMacros: {meal[2]}\n\n_{meal[0].lower()} with veggies for easy prep_"
def get_weekly_progress():
"""Generate weekly progress report"""
profile = load_json(PROFILE_FILE)
prs = load_json(PRS_FILE)
weight = profile['stats']['weight_lbs']
weight_history = profile['stats'].get('weight_history', [])
trend = ""
if len(weight_history) > 1:
change = weight_history[-1]['weight'] - weight_history[0]['weight']
trend = f"{'+' if change > 0 else ''}{change:.1f} lbs"
report = f"📊 *Weekly Progress Report*\n\n"
report += f"*Current Weight:* {weight} lbs {trend}\n"
report += f"*Program:* {profile['program']['type']}\n"
report += f"*Experience:* {profile['stats']['experience'].title()}\n\n"
# Count workouts
completed = len(prs.get('workout_history', []))
report += f"*Workouts Logged:* {completed}\n"
# PRs
pr_count = sum(1 for v in prs['personal_records'].values() if v.get('weight'))
report += f"*PRs Tracked:* {pr_count}/5\n\n"
report += "_Keep grinding. Consistency > intensity._"
return report
def send_telegram(msg):
"""Send message via Telegram"""
try:
subprocess.run(['openclaw', 'message', 'send', '--text', msg],
capture_output=True, timeout=10)
except Exception as e:
log(f"Telegram send failed: {e}")
def main():
import sys
cmd = sys.argv[1] if len(sys.argv) > 1 else 'workout'
if cmd == 'workout':
print(get_todays_workout())
elif cmd == 'meal':
print(get_meal_suggestion())
elif cmd == 'progress':
print(get_weekly_progress())
elif cmd == 'log' and len(sys.argv) > 2:
# Log workout result
result = ' '.join(sys.argv[2:])
log(f"WORKOUT LOG: {result}")
print(f"✅ Logged: {result}")
else:
print("Iron Fitness Coach - Commands:")
print(" workout - Get today's workout")
print(" meal - Get meal suggestion")
print(" progress - Weekly progress report")
print(" log <result> - Log workout result")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,17 @@
#!/bin/bash
# Send morning workout via Telegram
WORKSPACE="/Users/claw/.openclaw/workspace/agents/fitness-coach"
WORKOUT=$(python3 "$WORKSPACE/scripts/iron-agent.py" workout)
MSG="☀️ *GOOD MORNING! Today's Workout:*
$WORKOUT
Time to grind! 💪"
# Send via Telegram to Chris
openclaw message send --channel telegram --target telegram:8269921691 --message "$MSG" 2>/dev/null
# Log it
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Workout sent" >> "$WORKSPACE/logs/workout-sent.log"

View File

@@ -0,0 +1,15 @@
{
"personal_records": {
"Bench Press": {"weight": null, "reps": null, "date": null},
"Back Squat": {"weight": null, "reps": null, "date": null},
"Deadlift": {"weight": null, "reps": null, "date": null},
"Overhead Press": {"weight": null, "reps": null, "date": null},
"Pull-ups": {"weight": "bodyweight", "reps": null, "date": null}
},
"workout_history": [],
"streak": {
"current_weeks": 0,
"longest_weeks": 0,
"last_workout": null
}
}