Final 6-File Prompt Architecture (v3.1 - Simplified)¶
Overview¶
This document consolidates all architectural decisions for the 6-file prompt structure. Version 3.1 simplifies deployment by keeping all files under site paths initially, with a clear migration path to franchise-level sharing when scale demands it. All files remain simple text files (no JSON schemas required) with Pydantic validation through Bedrock tool-calling.
The 6-File Structure (v1.0 - Current Implementation)¶
s3://{bucket}/
└── {franchise}/{siteId}/ # All files under site (for now)
└── prompts/v6/
├── 01-franchise-core.txt # Core instructions & role
├── 02-knowledge.txt # Business knowledge base
├── 03-coaching.txt # Coaching scenarios
├── 04-staff-list.txt # Site staff names
├── 05-studio-output-instructions.txt # Output requirements
└── 06-custom-requirements.txt # Local business context
Future Scaling Strategy (Keep Site-Level Isolation)¶
Instead of moving files to franchise level, maintain site-level structure for better testing and risk management:
s3://{bucket}/
└── {franchise}/{siteId}/ # All files stay under site
└── prompts/v6/
├── 01-franchise-core.txt # Updated via Lambda batch
├── 02-knowledge.txt # Updated via Lambda batch
├── 03-coaching.txt # Updated via Lambda batch
├── 04-staff-list.txt # Site-specific (manual)
├── 05-studio-output-instructions.txt # Site-specific (manual)
└── 06-custom-requirements.txt # Site-specific (manual)
Why This is Better: 1. Isolated Testing: Test changes on one site before rolling out 2. Damage Control: If something breaks, only one site affected 3. Gradual Rollout: Update sites in batches with validation 4. No Complex Path Logic: Simple single-path file loading
Lambda for Batch Updates:
# When updating franchise-wide files (1-3)
def update_franchise_files(franchise, files_to_update):
sites = get_all_sites(franchise)
# Test on pilot site first
update_site(sites[0], files_to_update)
validate_results()
# Roll out to remaining sites
for site in sites[1:]:
update_site(site, files_to_update)
Why Start Simple¶
- Only 2 sites currently - Duplication is minimal
- 20 lines of code vs 60+ - Simpler implementation
- Single path loading - Easier debugging
- No complex fallback logic - Lower risk
- Easy migration later - Just change file paths when ready
File Details and Content Mapping¶
1. 01-franchise-core.txt (Site-Level)¶
Location: s3://{bucket}/{franchise}/{siteId}/prompts/v6/01-franchise-core.txt
From original prompt: Lines 1-165
Note: Duplicated per site for testing isolation, updated via batch Lambda
You are an expert gym business analyst for Orange Theory Fitness.
Your task is to analyze customer service phone calls and extract actionable insights.
CORE RESPONSIBILITIES:
1. Identify call participants and their roles
2. Categorize the primary purpose of the call
3. Assess business outcomes
4. Provide coaching feedback
PROCESSING STEPS:
1. Identify who is on the call (staff vs customer)
2. Determine primary call intent
3. Evaluate outcome success
4. Identify follow-up needs
5. Provide coaching opportunities
[Standard processing logic for all locations]
2. 02-knowledge.txt (Site-Level)¶
Location: s3://{bucket}/{franchise}/{siteId}/prompts/v6/02-knowledge.txt
From original prompt: Lines 168-596
Note: Duplicated per site for testing isolation, updated via batch Lambda
SALES KNOWLEDGE MODULE:
- Membership types: Elite ($189), Premier ($159), Basic ($99)
- Intro offers: First class free, 3-for-$49 intro pack
- Common objections and responses
- Upsell paths: Basic → Premier → Elite
CANCELLATION PROCEDURES:
- 30-day written notice required
- Freeze option as retention alternative
- Win-back strategies
FREEZE/HOLD POLICIES:
- Medical freeze: Unlimited duration with documentation
- Travel freeze: Up to 60 days
- Vacation hold: 30 days max
[Additional franchise-wide knowledge]
3. 03-coaching.txt (Site-Level)¶
Location: s3://{bucket}/{franchise}/{siteId}/prompts/v6/03-coaching.txt
From original prompt: Lines 270-347, 389-402, 527-540, 583-595
Note: Duplicated per site for testing isolation, updated via batch Lambda
COACHING SCENARIOS:
SALES COACHING:
Scenario: Customer says "I need to think about it"
INSTEAD OF: "Okay, take your time"
SAY: "What specifically would you like to think about?"
WHY: Uncovers real objections to address
BILLING ISSUE COACHING:
Scenario: Customer upset about charge
INSTEAD OF: "I can't help with that"
SAY: "Let me review your account and see what happened"
WHY: Shows ownership and care
[Additional coaching scenarios grouped by topic]
4. 04-staff-list.txt (Site-Specific)¶
Location: s3://{bucket}/{franchise}/{siteId}/prompts/v6/04-staff-list.txt
Unique to: Each site
KNOWN STAFF MEMBERS:
The following staff members work at this location:
- Drew (Sales Manager, works M-F mornings)
- Nadia (Head Coach, specializes in strength training)
- Jess (Front Desk Lead, handles billing issues)
- Holly (Assistant Manager, membership specialist)
- Ryanne (Sales Associate, Spanish speaker)
- Ryan (Front Desk, part-time evenings)
- Will (Coach, runs transformation challenges)
- Coach Marcus (Lead Coach, nutrition certified)
STAFF NAME CLARIFICATIONS:
- "Ryan" and "Ryanne" are different people
- "Jessica" is the same person as "Jess"
- "Marcus" should be identified as "Coach Marcus"
IDENTIFICATION RULE:
If you cannot identify the staff member with >80% confidence,
use "unidentified staff member" rather than guessing.
5. 05-studio-output-instructions.txt (Site-Specific)¶
Location: s3://{bucket}/{franchise}/{siteId}/prompts/v6/05-studio-output-instructions.txt
From original prompt: Lines 599-781 (includes TAXONOMY section)
Unique to: Each site
OUTPUT FORMAT AND TRACKING REQUIREMENTS:
CORE OUTPUT STRUCTURE:
All analyses must follow the CallAnalysis schema with these required fields:
- ai_call_analysis
- customer_profile
- primary_topic
- secondary_topics
- revenue_priority
- summary
- follow_up
- practical_coaching
TAXONOMY FOR CATEGORIZATION:
primary_topic.category can be:
- "scheduling" → subcategories: [class_booking, class_reschedule, class_cancellation, waitlist]
- "billing" → subcategories: [charge_inquiry, payment_update, refund_request, freeze_billing]
- "sales" → subcategories: [intro_booking, membership_inquiry, package_purchase, upgrade]
- "retention" → subcategories: [cancellation_request, freeze_request, downgrade]
- "service" → subcategories: [general_inquiry, complaint, equipment_issue, facility_question]
SITE-SPECIFIC TRACKING (populate in site_context field):
promotions_mentioned: List these if discussed:
- "student_discount" (Columbia/City College 20% off)
- "healthcare_special" ($99 for hospital employees)
- "new_year_challenge" (January promotion)
special_programs_discussed: Track if mentioned:
- "6am_warriors" (Early morning program)
- "transformation_challenge" (8-week program)
- "columbia_crew" (Thursday college night)
competitor_mentioned: Note if discussed:
- "equinox", "planet_fitness", "ymca", "crunch"
CUSTOM METRICS (populate in site_specific field):
- "spanish_language_request": true/false
- "parking_concern_raised": true/false
- "student_status_mentioned": true/false
- "morning_preference_expressed": true/false
INSTRUCTIONS: You MUST respond by calling the tool `record_call_analysis`
6. 06-custom-requirements.txt (Site-Specific)¶
Location: s3://{bucket}/{franchise}/{siteId}/prompts/v6/06-custom-requirements.txt
Unique to: Each site
LOCAL BUSINESS CONTEXT FOR WEST HARLEM:
MARKET CHARACTERISTICS:
- Dense urban area with many young professionals
- Columbia University nearby (seasonal student population)
- High competition: Equinox 2 blocks away (premium)
- Limited parking (major customer concern)
- 40% Spanish-speaking community
CURRENT PROMOTIONS (Updated: January 2025):
- Student Special: 20% off unlimited (verify .edu email)
- Healthcare Heroes: $99/month for hospital ID holders
- New Year Challenge: Join in January, get February 50% off
- Corporate rates for 5+ employees from same company
OUR UNIQUE PROGRAMS:
- 6AM Warriors: M/W/F high-intensity for finance professionals
- Transformation Challenge: 8-week program with meal plans ($299)
- Columbia Crew: Thursday 8pm classes with DJ
- Lunch Express: 30-minute classes at noon
SALES PRIORITIES FOR THIS QUARTER:
1. Fill 6AM classes (currently 60% capacity)
2. Convert intro packs to Elite memberships
3. Capture Columbia students before semester starts
4. Upsell transformation challenge to new year members
COMPETITIVE POSITIONING:
- vs Equinox: Emphasize community and coaching over luxury
- vs Planet Fitness: Highlight coaching quality and results
- vs YMCA: Focus on specialized programs and technology
MANAGER NOTES:
- Always mention parking validation for intro classes
- Spanish-speaking staff: Ryanne, Miguel (not always available)
- Peak times: 6-8am and 5-7pm (suggest off-peak for intros)
Pydantic Model with Site Extensions¶
# models.py - Supporting site-specific fields
from pydantic import BaseModel, Field
from typing import Dict, Any, Optional, List
class CallAnalysis(BaseModel):
"""Core fields validated for ALL sites"""
# Standard fields (strict validation)
ai_call_analysis: AICallAnalysis
customer_profile: CustomerProfile
primary_topic: PrimaryTopic
secondary_topics: List[SecondaryTopic] = []
revenue_priority: RevenuePriority
revenue_priority_evidence: str
summary: str
follow_up: FollowUp
practical_coaching: PracticalCoaching
# Site extensions (flexible validation)
site_context: Optional[Dict[str, Any]] = Field(
default_factory=dict,
description="Semi-structured site fields from output-instructions"
)
site_specific: Optional[Dict[str, Any]] = Field(
default_factory=dict,
description="Fully flexible site-specific metrics"
)
Lambda Implementation¶
Current v1.0 Implementation (Simple)¶
def load_prompt_v6(s3_client, bucket, franchise, site_id):
"""
Load and concatenate 6 prompt files from site directory
All files are .txt, no JSON parsing needed
Schema.json not required - Pydantic handles validation
"""
prompt_parts = []
# Simple single-path loading - all files under site
base_path = f"{franchise}/{site_id}/prompts/v6"
files = [
"01-franchise-core.txt",
"02-knowledge.txt",
"03-coaching.txt",
"04-staff-list.txt",
"05-studio-output-instructions.txt",
"06-custom-requirements.txt"
]
# Load each file
for filename in files:
try:
content = s3_client.get_object(
Bucket=bucket,
Key=f"{base_path}/{filename}"
)['Body'].read().decode('utf-8')
prompt_parts.append(content)
logger.info(f"Loaded: {filename}")
except Exception as e:
# Only file 6 is optional - file 5 contains CRITICAL taxonomy
if "06-custom" in filename:
logger.info(f"Optional file not found: {filename}")
else:
logger.error(f"Required file missing: {filename}")
raise ValueError(f"Files 1-5 are mandatory. Missing: {filename}")
# Simple concatenation
return "\n\n".join(prompt_parts)
# Note: schema.json is NOT loaded - Pydantic models define the schema
Future Batch Update Tool (When Scaling)¶
def batch_update_franchise_prompts(franchise, files_to_update, test_site=None):
"""
Update shared files (1-3) across all sites with controlled rollout
Maintains site-level isolation for safe testing
"""
sites = list_all_sites_for_franchise(franchise)
# Phase 1: Test on pilot site
pilot_site = test_site or sites[0]
logger.info(f"[UPDATE] Testing on pilot site: {pilot_site}")
for filename, content in files_to_update.items():
if filename in ['01-franchise-core.txt', '02-knowledge.txt', '03-coaching.txt']:
s3_client.put_object(
Bucket=bucket,
Key=f"{franchise}/{pilot_site}/prompts/v6/{filename}",
Body=content
)
# Phase 2: Validate pilot site
validation_result = validate_site_processing(franchise, pilot_site)
if not validation_result.success:
logger.error(f"[UPDATE] Pilot site validation failed: {validation_result.errors}")
return False
# Phase 3: Gradual rollout
batch_size = 5 # Update 5 sites at a time
for i in range(1, len(sites), batch_size):
batch = sites[i:i+batch_size]
logger.info(f"[UPDATE] Updating batch: {batch}")
for site in batch:
for filename, content in files_to_update.items():
s3_client.put_object(
Bucket=bucket,
Key=f"{franchise}/{site}/prompts/v6/{filename}",
Body=content
)
# Monitor each batch before proceeding
time.sleep(300) # Wait 5 minutes
for site in batch:
if not validate_site_processing(franchise, site).success:
logger.error(f"[UPDATE] Site {site} failed, stopping rollout")
return False
logger.info(f"[UPDATE] Successfully updated all {len(sites)} sites")
return True
def process_transcript(transcript, franchise, site_id):
"""Main processing with Bedrock tool calling"""
# Load 6-file prompt
prompt = load_prompt_v6(s3_client, bucket, franchise, site_id)
# Call Bedrock with tool
result = ask_claude_for_analysis(
transcript=transcript,
prompt_text=prompt
)
# Validate core fields strictly
try:
analysis = CallAnalysis.model_validate(result)
except ValidationError as e:
# Retry once with error feedback
error_prompt = f"{prompt}\n\nFIX THESE ERRORS:\n{e.errors()}"
result = ask_claude_for_analysis(transcript, error_prompt)
analysis = CallAnalysis.model_validate(result)
return analysis
Site-Specific Output Examples¶
West Harlem Output¶
{
"ai_call_analysis": {
"call_state": "human_conversation",
"staff_name": "Ryanne"
},
"primary_topic": {
"category": "sales",
"subcategory": "intro_booking"
},
"site_context": {
"promotions_mentioned": ["student_discount"],
"special_programs_discussed": ["6am_warriors"],
"competitor_mentioned": "equinox"
},
"site_specific": {
"spanish_language_request": false,
"student_status_mentioned": true,
"morning_preference_expressed": true
}
}
Totowa Output (Different Fields)¶
{
"ai_call_analysis": {
"call_state": "human_conversation",
"staff_name": "Jessica"
},
"primary_topic": {
"category": "sales",
"subcategory": "membership_inquiry"
},
"site_context": {
"promotions_mentioned": ["family_package"],
"special_programs_discussed": ["kids_fitness"],
"competitor_mentioned": null
},
"site_specific": {
"parking_availability_asked": true,
"family_membership_interest": true,
"suburban_concerns": true
}
}
Key Architecture Principles¶
1. Separation of Concerns¶
| File | Purpose | Update Frequency | Updated By |
|---|---|---|---|
| 01-franchise-core | Core instructions | Quarterly | Franchise HQ |
| 02-knowledge | Business knowledge | Monthly | Training team |
| 03-coaching | Coaching standards | Monthly | Operations |
| 04-staff-list | Staff names | Weekly | Studio manager |
| 05-studio-output | What to track | As needed | Studio manager |
| 06-custom-requirements | Local context | Weekly | Studio manager |
2. Validation Strategy¶
- Core fields: Strict Pydantic validation (must pass)
- Site context: Flexible Dict (logged if missing expected fields)
- Site specific: Completely open (experimental metrics)
3. Progressive Enhancement Path¶
Month 1: Experiment in site_specific{}
↓
Month 3: Promote to site_context{} (semi-structured)
↓
Month 6: Standardize across franchise (add to core model)
Migration Checklist¶
Phase 1: Current Implementation (v1.0)¶
- Split current prompt into 6 files using line mappings
- Upload all 6 files to
{franchise}/{siteId}/prompts/v6/ - Update Lambda with simple loader function (20 lines)
- Keep existing Pydantic models (no changes needed)
- Test concatenation produces valid prompt
- Deploy to test environment with feature flag
- Validate output with Bedrock tool calling
- Production rollout with monitoring
Phase 2: Future Enhancement (v1.5 - When 10+ sites)¶
- Create franchise-level folder structure
- Move files 1-3 to franchise level
- Update loader with dual-path logic
- Test backward compatibility
- Gradual site migration
Benefits Summary¶
- Simplicity: All text files, no JSON schema files needed
- Flexibility: Sites add fields without code changes
- Standardization: Core fields validated via Pydantic models
- Minimal Changes: Only ~20 lines of code for v1.0
- Maintainability: Clear separation of what each file controls
- Evolution: Start simple, add complexity only when needed
- No Schema.json: Pydantic models handle all validation
Future Considerations¶
v3.1: Industry Expansion¶
When adding non-fitness franchises:
s3://bucket/
├── fitness/orange-theory/prompts/v6/
├── healthcare/mercy-clinic/prompts/v6/
└── banking/wells-fargo/prompts/v6/
v3.2: Dynamic Loading¶
# Load industry-specific base model
if industry == "fitness":
base_model = FitnessCallAnalysis
elif industry == "healthcare":
base_model = HealthcareCallAnalysis
v3.3: A/B Testing¶
# Test different prompt versions
if random.random() < 0.5:
version = "v6"
else:
version = "v6-experimental"
This architecture provides the foundation for growth from 2 sites to 200+ sites across multiple industries while maintaining quality and flexibility.