Introduction
StateSet Schedules transform your agents from reactive responders to proactive assistants. By automating time-based actions, your agents can anticipate needs, follow up on conversations, perform routine maintenance, and ensure nothing falls through the cracks. This guide shows you how to build sophisticated scheduling systems that work 24/7.
What are Agent Schedules?
Agent Schedules are intelligent automation rules that trigger actions based on time. Unlike simple cron jobs, StateSet Schedules are context-aware, can adapt to business logic, and integrate seamlessly with your agent’s capabilities.
Key Features
Flexible Timing Cron expressions, intervals, or business calendar rules
Smart Execution Conditional logic, timezone awareness, and holiday handling
Reliable Delivery Guaranteed execution with retry logic and monitoring
Use Cases
Customer Success Operations Proactive Support
Follow up 24 hours after purchase
Check in weekly with VIP customers
Send satisfaction surveys after support tickets close
Remind about expiring subscriptions
Follow up 24 hours after purchase
Check in weekly with VIP customers
Send satisfaction surveys after support tickets close
Remind about expiring subscriptions
Daily inventory checks
Hourly order status updates
Weekly performance reports
Monthly billing reconciliation
Monitor for abandoned carts
Check unresolved tickets
Escalate aging issues
Perform health checks
Getting Started
Prerequisites
StateSet account with scheduling enabled
At least one configured agent
Understanding of cron expressions (optional)
Installation
npm install stateset-node @stateset/scheduler
Creating Schedules
Basic Schedule Example
import { StateSetClient } from 'stateset-node' ;
const client = new StateSetClient ({
apiKey: process . env . STATESET_API_KEY
});
async function createDailyCheckIn () {
const schedule = await client . schedules . create ({
agent_id: 'agent_123' ,
name: 'daily_customer_check_in' ,
description: 'Check in with customers who have open issues' ,
schedule: {
type: 'cron' ,
expression: '0 9 * * 1-5' , // 9 AM weekdays
timezone: 'America/New_York'
},
action: {
type: 'function' ,
function: 'check_open_issues' ,
parameters: {
priority: 'high' ,
age_days: 2
}
},
enabled: true ,
metadata: {
category: 'customer_success' ,
owner: 'support_team'
}
});
console . log ( 'Schedule created:' , schedule . id );
return schedule ;
}
Advanced Schedule with Conditions
async function createSmartFollowUp () {
const schedule = await client . schedules . create ({
agent_id: 'agent_123' ,
name: 'smart_purchase_follow_up' ,
description: 'Intelligent post-purchase follow-up based on order value and customer type' ,
// Complex scheduling rules
schedule: {
type: 'event_based' ,
trigger: 'order.completed' ,
delay: {
unit: 'hours' ,
value: 24 ,
business_hours_only: true
},
conditions: [
{
field: 'order.total' ,
operator: 'greater_than' ,
value: 100
},
{
field: 'customer.lifetime_value' ,
operator: 'greater_than' ,
value: 500
}
]
},
// Dynamic action based on context
action: {
type: 'workflow' ,
steps: [
{
type: 'evaluate' ,
condition: 'order.total > 1000' ,
true_action: {
type: 'send_message' ,
template: 'vip_thank_you' ,
channel: 'email'
},
false_action: {
type: 'send_message' ,
template: 'standard_thank_you' ,
channel: 'email'
}
},
{
type: 'wait' ,
duration: '7d'
},
{
type: 'send_message' ,
template: 'product_review_request' ,
channel: 'sms'
}
]
},
// Error handling
error_handling: {
retry_attempts: 3 ,
retry_delay: '5m' ,
on_failure: 'create_ticket'
}
});
return schedule ;
}
Schedule Types
1. Cron-Based Schedules
// Common cron patterns
const cronPatterns = {
// Every hour
hourly: '0 * * * *' ,
// Every day at 9 AM
daily_morning: '0 9 * * *' ,
// Every Monday at 10 AM
weekly_monday: '0 10 * * 1' ,
// First day of month at midnight
monthly_start: '0 0 1 * *' ,
// Every 15 minutes during business hours
business_quarter_hour: '*/15 9-17 * * 1-5' ,
// Last Friday of month at 5 PM
monthly_last_friday: '0 17 * * 5L'
};
// Create schedule with cron
const cronSchedule = await client . schedules . create ({
agent_id: 'agent_123' ,
name: 'hourly_metrics_check' ,
schedule: {
type: 'cron' ,
expression: cronPatterns . hourly ,
timezone: 'UTC'
},
action: {
type: 'function' ,
function: 'collect_hourly_metrics'
}
});
2. Interval-Based Schedules
const intervalSchedule = await client . schedules . create ({
agent_id: 'agent_123' ,
name: 'continuous_monitoring' ,
schedule: {
type: 'interval' ,
every: {
unit: 'minutes' ,
value: 30
},
start_time: '2024-01-01T00:00:00Z' ,
end_time: '2024-12-31T23:59:59Z'
},
action: {
type: 'function' ,
function: 'monitor_system_health'
}
});
3. Event-Triggered Schedules
const eventSchedule = await client . schedules . create ({
agent_id: 'agent_123' ,
name: 'abandoned_cart_recovery' ,
schedule: {
type: 'event_based' ,
trigger: 'cart.abandoned' ,
delay: {
unit: 'hours' ,
value: 2
},
conditions: [
{
field: 'cart.value' ,
operator: 'greater_than' ,
value: 50
}
]
},
action: {
type: 'workflow' ,
workflow_id: 'abandoned_cart_recovery_flow'
}
});
4. Business Calendar Schedules
const businessSchedule = await client . schedules . create ({
agent_id: 'agent_123' ,
name: 'quarterly_business_review' ,
schedule: {
type: 'business_calendar' ,
calendar: 'fiscal_2024' ,
events: [
'quarter_end' ,
'quarter_start'
],
offset: {
days: - 5 ,
business_days_only: true
}
},
action: {
type: 'function' ,
function: 'prepare_quarterly_report'
},
notifications: {
on_start: [ 'email:manager@company.com' ],
on_complete: [ 'slack:#reports' ]
}
});
Complex Workflows
Multi-Step Customer Journey
async function createCustomerJourneySchedule () {
const journey = await client . schedules . create ({
agent_id: 'agent_123' ,
name: 'new_customer_onboarding' ,
description: 'Automated 30-day onboarding journey' ,
schedule: {
type: 'journey' ,
trigger: 'customer.created' ,
steps: [
{
delay: '1h' ,
action: 'send_welcome_email'
},
{
delay: '1d' ,
action: 'check_first_login' ,
condition: 'customer.logins == 0' ,
true_action: 'send_login_reminder'
},
{
delay: '3d' ,
action: 'send_getting_started_guide'
},
{
delay: '7d' ,
action: 'schedule_onboarding_call' ,
condition: 'customer.plan == "enterprise"'
},
{
delay: '14d' ,
action: 'send_feature_highlights'
},
{
delay: '30d' ,
action: 'send_feedback_survey'
}
]
},
tracking: {
metrics: [ 'completion_rate' , 'engagement_score' ],
report_to: 'customer_success_dashboard'
}
});
return journey ;
}
Intelligent Escalation System
async function createEscalationSchedule () {
const escalation = await client . schedules . create ({
agent_id: 'agent_123' ,
name: 'ticket_escalation_system' ,
schedule: {
type: 'continuous' ,
check_interval: '15m'
},
rules: [
{
name: 'urgent_escalation' ,
condition: {
all: [
{ field: 'ticket.priority' , operator: 'equals' , value: 'urgent' },
{ field: 'ticket.age_minutes' , operator: 'greater_than' , value: 30 },
{ field: 'ticket.status' , operator: 'not_equals' , value: 'resolved' }
]
},
action: {
type: 'escalate' ,
to: 'senior_support' ,
notification: 'immediate'
}
},
{
name: 'standard_escalation' ,
condition: {
all: [
{ field: 'ticket.priority' , operator: 'equals' , value: 'normal' },
{ field: 'ticket.age_hours' , operator: 'greater_than' , value: 4 }
]
},
action: {
type: 'escalate' ,
to: 'support_lead' ,
notification: 'email'
}
},
{
name: 'vip_escalation' ,
condition: {
all: [
{ field: 'customer.tier' , operator: 'equals' , value: 'vip' },
{ field: 'ticket.age_minutes' , operator: 'greater_than' , value: 15 }
]
},
action: {
type: 'escalate' ,
to: 'vip_support' ,
notification: 'phone'
}
}
]
});
return escalation ;
}
Schedule Management
Monitoring and Analytics
class ScheduleMonitor {
async getScheduleMetrics ( scheduleId , timeframe = '7d' ) {
const metrics = await client . schedules . getMetrics ({
schedule_id: scheduleId ,
timeframe: timeframe ,
metrics: [
'execution_count' ,
'success_rate' ,
'average_duration' ,
'failure_reasons'
]
});
return {
health: this . calculateHealth ( metrics ),
performance: {
executions: metrics . execution_count ,
success_rate: ` ${ metrics . success_rate } %` ,
avg_duration: ` ${ metrics . average_duration } ms` ,
reliability: this . calculateReliability ( metrics )
},
issues: this . identifyIssues ( metrics ),
recommendations: this . generateRecommendations ( metrics )
};
}
calculateHealth ( metrics ) {
if ( metrics . success_rate >= 99 ) return 'excellent' ;
if ( metrics . success_rate >= 95 ) return 'good' ;
if ( metrics . success_rate >= 90 ) return 'fair' ;
return 'poor' ;
}
identifyIssues ( metrics ) {
const issues = [];
if ( metrics . success_rate < 95 ) {
issues . push ({
type: 'reliability' ,
severity: 'high' ,
message: `Success rate ${ metrics . success_rate } % is below threshold`
});
}
if ( metrics . average_duration > 5000 ) {
issues . push ({
type: 'performance' ,
severity: 'medium' ,
message: 'Schedule execution taking longer than expected'
});
}
return issues ;
}
}
Bulk Schedule Operations
// Pause all schedules for maintenance
async function pauseAllSchedules ( reason ) {
const schedules = await client . schedules . list ({
filter: { enabled: true }
});
const results = await Promise . all (
schedules . map ( schedule =>
client . schedules . update ({
id: schedule . id ,
enabled: false ,
pause_reason: reason ,
paused_at: new Date (). toISOString ()
})
)
);
console . log ( `Paused ${ results . length } schedules` );
return results ;
}
// Migrate schedules to new timezone
async function migrateScheduleTimezones ( fromTz , toTz ) {
const schedules = await client . schedules . list ({
filter: {
'schedule.timezone' : fromTz ,
'schedule.type' : 'cron'
}
});
for ( const schedule of schedules ) {
const updatedCron = convertCronTimezone (
schedule . schedule . expression ,
fromTz ,
toTz
);
await client . schedules . update ({
id: schedule . id ,
schedule: {
... schedule . schedule ,
expression: updatedCron ,
timezone: toTz
}
});
}
}
Testing Schedules
Test Framework
class ScheduleTester {
async testSchedule ( scheduleId , options = {}) {
const testRun = await client . schedules . test ({
schedule_id: scheduleId ,
mode: options . mode || 'dry_run' ,
test_data: options . testData || {},
simulate_time: options . simulateTime || new Date ()
});
return {
would_execute: testRun . would_execute ,
execution_time: testRun . execution_time ,
action_preview: testRun . action_preview ,
validation_errors: testRun . validation_errors ,
estimated_duration: testRun . estimated_duration
};
}
async simulateScheduleRun ( scheduleId , days = 7 ) {
const simulations = [];
const schedule = await client . schedules . get ( scheduleId );
for ( let i = 0 ; i < days * 24 ; i ++ ) {
const simulatedTime = new Date ();
simulatedTime . setHours ( simulatedTime . getHours () + i );
const wouldRun = this . evaluateCron (
schedule . schedule . expression ,
simulatedTime ,
schedule . schedule . timezone
);
if ( wouldRun ) {
simulations . push ({
time: simulatedTime ,
action: schedule . action
});
}
}
return {
schedule_id: scheduleId ,
simulation_period: ` ${ days } days` ,
expected_runs: simulations . length ,
run_times: simulations
};
}
}
// Usage
const tester = new ScheduleTester ();
const results = await tester . simulateScheduleRun ( 'schedule_123' , 30 );
console . log ( `Schedule would run ${ results . expected_runs } times in 30 days` );
Error Handling & Recovery
Robust Error Handling
const resilientSchedule = await client . schedules . create ({
agent_id: 'agent_123' ,
name: 'critical_daily_task' ,
schedule: {
type: 'cron' ,
expression: '0 2 * * *' // 2 AM daily
},
action: {
type: 'function' ,
function: 'process_daily_reports'
},
error_handling: {
retry_strategy: {
max_attempts: 5 ,
delays: [ 30 , 60 , 300 , 900 , 1800 ], // seconds
backoff_type: 'exponential'
},
failure_actions: [
{
after_attempts: 3 ,
action: {
type: 'notify' ,
channel: 'email' ,
recipients: [ 'oncall@company.com' ],
template: 'schedule_failure_warning'
}
},
{
after_attempts: 5 ,
action: {
type: 'escalate' ,
create_incident: true ,
severity: 'high' ,
assign_to: 'oncall_engineer'
}
}
],
recovery: {
type: 'compensating_action' ,
action: 'run_backup_process' ,
notify_on_recovery: true
}
},
monitoring: {
alert_on_miss: true ,
alert_on_delay: {
threshold_minutes: 15
},
health_check_endpoint: 'https://status.company.com/schedules/daily_task'
}
});
Schedule Dependencies
async function createDependentSchedules () {
// Parent schedule
const parentSchedule = await client . schedules . create ({
agent_id: 'agent_123' ,
name: 'data_collection' ,
schedule: { type: 'cron' , expression: '0 1 * * *' },
action: { type: 'function' , function: 'collect_daily_data' }
});
// Child schedule that depends on parent
const childSchedule = await client . schedules . create ({
agent_id: 'agent_123' ,
name: 'data_processing' ,
schedule: {
type: 'dependent' ,
depends_on: parentSchedule . id ,
trigger: 'on_success' ,
delay: '30m'
},
action: { type: 'function' , function: 'process_collected_data' }
});
// Grandchild schedule
const reportSchedule = await client . schedules . create ({
agent_id: 'agent_123' ,
name: 'report_generation' ,
schedule: {
type: 'dependent' ,
depends_on: childSchedule . id ,
trigger: 'on_complete' ,
conditions: [
{ field: 'output.record_count' , operator: 'greater_than' , value: 0 }
]
},
action: { type: 'function' , function: 'generate_report' }
});
return { parentSchedule , childSchedule , reportSchedule };
}
Best Practices
1. Design for Reliability
// Good: Idempotent actions with proper error handling
const reliableSchedule = {
action: {
type: 'function' ,
function: 'process_orders' ,
parameters: {
mode: 'idempotent' ,
check_processed: true ,
batch_size: 100
}
},
error_handling: {
retry_attempts: 3 ,
alert_on_failure: true
}
};
// Bad: Non-idempotent actions without safeguards
const unreliableSchedule = {
action: {
type: 'function' ,
function: 'send_emails' ,
parameters: {
send_all: true // Could send duplicates
}
}
};
2. Timezone Awareness
// Good: Explicit timezone handling
const timezoneAwareSchedule = {
schedule: {
type: 'cron' ,
expression: '0 9 * * 1-5' ,
timezone: 'America/New_York' ,
observe_dst: true
},
metadata: {
business_hours: '9 AM - 5 PM EST/EDT' ,
skip_holidays: true
}
};
// Bad: Ambiguous timing
const ambiguousSchedule = {
schedule: {
type: 'cron' ,
expression: '0 9 * * *' // Which 9 AM?
}
};
class ScheduleOptimizer {
// Batch similar schedules
async optimizeSchedules () {
const schedules = await client . schedules . list ();
// Group schedules by execution time
const grouped = this . groupByExecutionTime ( schedules );
// Create batch processors
for ( const [ time , group ] of Object . entries ( grouped )) {
if ( group . length > 5 ) {
await this . createBatchSchedule ( time , group );
}
}
}
async createBatchSchedule ( time , schedules ) {
return client . schedules . create ({
name: `batch_processor_ ${ time } ` ,
schedule: { type: 'cron' , expression: time },
action: {
type: 'batch' ,
actions: schedules . map ( s => s . action ),
parallel: true ,
max_concurrent: 10
}
});
}
}
Troubleshooting
Common Issues
Schedule Not Executing
Verify timezone settings
Check schedule is enabled
Validate cron expression
Review execution logs
Missed Executions
Check system time sync
Review resource limits
Verify agent availability
Check for conflicting schedules
Performance Issues
Batch similar operations
Optimize action execution
Use appropriate intervals
Monitor resource usage
// Schedule debugger
async function debugSchedule ( scheduleId ) {
const debug = await client . schedules . debug ({
schedule_id: scheduleId ,
include: [ 'execution_history' , 'next_runs' , 'conflicts' ]
});
console . log ( 'Schedule Debug Info:' );
console . log ( '- Status:' , debug . status );
console . log ( '- Last run:' , debug . last_execution );
console . log ( '- Next 5 runs:' , debug . next_runs . slice ( 0 , 5 ));
console . log ( '- Conflicts:' , debug . conflicts );
console . log ( '- Error rate:' , debug . error_rate );
return debug ;
}
Next Steps
Pro Tip : Start with simple schedules and gradually add complexity. Always test schedules in a staging environment before deploying to production.
For schedule templates and examples, visit our GitHub repository or contact support@stateset.com .