Building a Fitness Workout Planner Agent in typescript with HazelJS
The Fitness Planning Challenge
When someone asks for a workout plan, they're not just requesting exercises. They need:
- Goal alignment: Weight loss, muscle gain, endurance, or flexibility require different approaches
- Personalization: Fitness level, injuries, and available equipment vary dramatically
- Progression: Plans must evolve as users get stronger
- Motivation: Tracking progress and celebrating achievements keeps users engaged
- Safety: Exercises must match ability levels to prevent injury
A single AI model trying to handle all these aspects often produces generic recommendations. Agentic AI, however, allows us to create specialized agents that excel at specific tasks while collaborating seamlessly.
Why Agentic AI for Fitness Planning?
Agentic AI is particularly well-suited for fitness planning because:
- Specialized expertise: Different aspects of fitness require different knowledge bases-exercise physiology, nutrition science, progress tracking methodologies
- Iterative refinement: A fitness plan isn't created in one step; it requires intake, research, planning, and tracking
- Human-in-the-loop: Users need to provide feedback, adjust goals, and report progress
- Multi-modal reasoning: Combining exercise databases, user preferences, and progress data requires different reasoning approaches
HazelJS makes this natural by providing the building blocks for multi-agent systems: the @Agent decorator for defining agents, @Tool for capabilities, and @Delegate for orchestration.
Architecture Overview
Our fitness planner uses five specialized agents, each with a clear responsibility:
- FitnessIntakeAgent: Extracts structured information from natural language-goals, fitness level, equipment, time constraints
- ExerciseSearchAgent: Uses RAG to find exercises matching specific criteria from a knowledge base
- WorkoutPlannerAgent: Creates day-by-day workout plans with balanced exercises, proper rest, and logical progression
- ProgressTrackerAgent: Calculates metrics, unlocks achievements, and provides improvement recommendations
- FitnessCoachAgent: Orchestrates the workflow using supervisor routing, delegating to specialists as needed
This separation of concerns makes each agent simpler, more testable, and easier to improve independently. When we want better exercise recommendations, we only need to enhance the ExerciseSearchAgent without touching the workout planning logic.
HazelJS Features in Action
Multi-Agent Orchestration
HazelJS's @Delegate decorator makes agent collaboration straightforward. The FitnessCoachAgent doesn't need to know how to search exercises or track progress-it simply delegates to specialists:
@Delegate({
agent: 'ExerciseSearchAgent',
description: 'Retrieve exercises based on goals, muscle groups, and equipment.',
inputField: 'input',
})
async getExercises(input: string): Promise<string> {
return '';
}
This declarative approach means the orchestrator stays focused on coordination while specialists handle domain expertise.
RAG for Exercise Discovery
Finding the right exercise isn't just keyword matching-it requires understanding muscle groups, equipment needs, and difficulty levels. We use HazelJS's RAG capabilities with a MemoryVectorStore for semantic search:
const rag = new RAGPipeline({
vectorStore: this.vectorStore,
embeddingProvider: this.embeddings,
topK: 3,
});
When a user asks for "chest exercises without equipment," the RAG system understands the semantic meaning and returns relevant exercises like push-ups, even if the exact phrase doesn't appear in the exercise description.
Production Resilience
Fitness apps need to be reliable. HazelJS provides built-in resilience patterns:
- Circuit breaker: Prevents cascading failures when external services are down
- Retry logic: Handles transient failures gracefully
- Rate limiting: Protects against abuse and ensures fair usage
- Observability: Built-in metrics and tracing for monitoring
These features are configured once in the AgentModule and apply across all agents automatically:
AgentModule.forRoot({
runtime: {
enableRetry: true,
enableCircuitBreaker: true,
rateLimitPerMinute: 120,
enableObservability: true,
},
})
Guardrails for Safety
Fitness recommendations can have real-world consequences if incorrect. HazelJS's guardrails provide:
- PII redaction: Automatically removes personal information from logs
- Injection blocking: Prevents prompt injection attacks
- Toxicity filtering: Ensures recommendations remain appropriate
This is especially important for fitness apps where users might share sensitive health information.
Implementation Highlights
Structured Data Extraction
The FitnessIntakeAgent transforms natural language into structured data. Instead of parsing "I want to lose weight, beginner level, 30 min workouts, no equipment" manually, we use tool-based extraction:
@Tool({
name: 'extractFitnessProfile',
description: 'Extract structured fitness planning information from a user request.',
parameters: [
{
name: 'message',
type: 'string',
description: 'The raw user request',
required: true,
},
],
})
async extractFitnessProfile(input: { message: string }) {
return {
goal: this.extractGoal(input.message),
fitnessLevel: this.extractFitnessLevel(input.message),
equipment: this.extractEquipment(input.message),
// ... more fields
};
}
This structured output becomes the foundation for all subsequent agents, ensuring consistency across the workflow.
Goal-Aware Workout Planning
The WorkoutPlannerAgent doesn't just pick random exercises-it considers the user's goals:
- Weight loss: Prioritizes cardio and high-intensity intervals
- Muscle gain: Focuses on compound movements with progressive overload
- Endurance: Emphasizes steady-state cardio and duration progression
- Flexibility: Centers on stretching and mobility work
The agent also balances exercises across muscle groups, ensures adequate rest periods, and provides notes for each day (like "Start with proper warm-up" or "Active recovery day").
Progress Tracking with Achievements
The ProgressTrackerAgent goes beyond simple logging-it calculates meaningful metrics and unlocks achievements:
const achievements = [
{
id: 'first-workout',
title: 'First Workout',
description: 'Completed your first workout session',
unlocked: true,
},
{
id: 'consistent-week',
title: 'Consistent Week',
description: 'Completed workouts for 7 days',
unlocked: false,
},
];
Gamification elements like achievements keep users motivated, while metrics provide concrete feedback on progress.
Real-World Applications
This architecture extends beyond personal fitness:
- Corporate wellness programs: Companies can provide personalized fitness plans to employees
- Physical therapy: Therapists can create progressive rehabilitation plans
- Sports coaching: Coaches can design sport-specific training programs
- Senior fitness: Adapted plans for different age groups and mobility levels
The multi-agent approach makes these adaptations straightforward-swap the exercise knowledge base, adjust the goal categories, and the same architecture works.
Running the Project
npm install --legacy-peer-deps
npm run build
npm run eval
npm run dev
The eval tests verify each agent works correctly before integration. The development server starts on port 3000 with the HazelJS Inspector available at /__hazel for real-time monitoring.
Testing the API
# Fitness intake
curl -s -X POST http://localhost:3000/fitness/intake \
-H 'content-type: application/json' \
-d '{"message":"I want to lose weight, beginner level, 30 min workouts, no equipment"}'
# Supervisor orchestration
curl -s -X POST http://localhost:3000/fitness/supervisor \
-H 'content-type: application/json' \
-d '{"message":"I want to lose weight, beginner level, 30 min workouts, no equipment. Plan my week."}'
The supervisor endpoint demonstrates the full workflow: intake → exercise search → workout planning → progress tracking, all orchestrated automatically.
Key Takeaways
- Specialization beats generalization: Multiple focused agents produce better results than one monolithic agent
- RAG enables semantic understanding: Exercise search works because it understands intent, not just keywords
- Resilience is essential: Fitness apps need to be reliable-built-in circuit breakers and retries matter
- Observability drives improvement: The HazelJS Inspector makes debugging and optimization straightforward
- Guardrails protect users: Safety features are non-negotiable when health recommendations are involved
- Progress tracking maintains engagement: Metrics and achievements keep users motivated long-term
What's Next?
For production deployment, consider:
- Real LLM integration: Replace the local provider with OpenAI or Anthropic for more sophisticated reasoning
- Persistent storage: Use
@hazeljs/memoryto save user preferences and workout history - Advanced workflows: Implement
@hazeljs/flowfor complex multi-step processes - Notifications: Add
@hazeljs/pubsubfor workout reminders and progress updates - Real exercise APIs: Connect to comprehensive exercise databases for dynamic content
- Monitoring: Use
@hazeljs/observabilityfor OpenTelemetry integration with Datadog or New Relic
Conclusion
This fitness workout planner demonstrates how HazelJS enables building sophisticated AI applications with production-ready patterns. The multi-agent architecture, RAG-powered search, and built-in resilience features make it possible to create reliable, observable, and scalable fitness applications.
More importantly, it shows that agentic AI isn't just theoretical-it solves real problems better than traditional approaches. By breaking complex tasks into specialized components that collaborate, we get systems that are more maintainable, more testable, and ultimately more effective.
Comments
No comments yet. Start the discussion.