Skip to main content

Overview

PhoneClaw’s scheduler lets you run automations automatically at specific times or recurring intervals using cron expressions. This is perfect for social media posting, periodic data checks, or any task that needs to run without manual intervention.
Scheduled tasks run in the background even when PhoneClaw isn’t actively open. The scheduler checks for tasks every minute and executes them according to their cron schedule.

The schedule() Function

Schedule tasks using the ClawScript schedule() function:
schedule(taskDescription, cronExpression)
Parameters:
  • taskDescription (string): A description or reference to your automation task
  • cronExpression (string): A cron expression defining when to run
Example:
schedule("Tweet every hour", "0 * * * *")

Creating Scheduled Tasks

1
Write Your Automation
2
First, create the automation logic you want to schedule:
3
const postTweet = () => {
  speakText("Starting scheduled tweet")
  
  // Open Twitter
  magicClicker("Compose tweet button")
  delay(2000)
  
  // Type and post
  magicClicker("Tweet text field")
  delay(500)
  // Type your message here
  
  magicClicker("Post button")
  delay(2000)
  
  speakText("Tweet posted successfully")
}
4
Add the Schedule
5
Wrap your automation with a schedule:
6
const postTweet = () => {
  speakText("Starting scheduled tweet")
  magicClicker("Compose tweet button")
  delay(2000)
  magicClicker("Tweet text field")
  delay(500)
  magicClicker("Post button")
  delay(2000)
  speakText("Tweet posted")
}

// Run every hour
schedule("postTweet", "0 * * * *")
speakText("Scheduled to run every hour")
7
View Scheduled Tasks
8
  • Open PhoneClaw
  • Go to the Scheduled Tasks tab
  • Your task appears with:
    • Task description
    • Cron expression
    • Last execution time
    • Next scheduled run
    • Active status
  • 9
    Clear Schedules
    10
    To remove all scheduled tasks:
    11
    clearSchedule()
    
    12
    Or use the UI:
    13
  • Open PhoneClaw
  • Tap Clear Schedule button
  • Confirm to remove all scheduled tasks
  • Understanding Cron Expressions

    Cron expressions define when tasks run using 5 time fields:
    ┌───────────── minute (0 - 59)
    │ ┌───────────── hour (0 - 23)
    │ │ ┌───────────── day of month (1 - 31)
    │ │ │ ┌───────────── month (1 - 12)
    │ │ │ │ ┌───────────── day of week (0 - 7) (0 and 7 are Sunday)
    │ │ │ │ │
    │ │ │ │ │
    * * * * *
    

    Special Characters

    • * - Any value (every minute, every hour, etc.)
    • , - Value list separator (1,15,30)
    • - - Range of values (1-5)
    • / - Step values (*/15 = every 15 units)

    Common Cron Patterns

    Every Hour

    schedule("Hourly task", "0 * * * *")
    // Runs at: 1:00, 2:00, 3:00, etc.
    

    Every 30 Minutes

    schedule("Half-hourly task", "*/30 * * * *")
    // Runs at: :00 and :30 of every hour
    

    Every Day at 9 AM

    schedule("Morning task", "0 9 * * *")
    // Runs daily at 9:00 AM
    

    Every Weekday at 8 AM

    schedule("Weekday morning", "0 8 * * 1-5")
    // Runs Monday through Friday at 8:00 AM
    

    Every Monday at Noon

    schedule("Weekly Monday task", "0 12 * * 1")
    // Runs every Monday at 12:00 PM
    

    Twice Daily (9 AM and 6 PM)

    schedule("Twice daily", "0 9,18 * * *")
    // Runs at 9:00 AM and 6:00 PM every day
    

    First Day of Every Month

    schedule("Monthly task", "0 0 1 * *")
    // Runs at midnight on the 1st of each month
    

    Every 15 Minutes During Work Hours

    schedule("Work hours", "*/15 9-17 * * 1-5")
    // Runs every 15 minutes from 9 AM to 5 PM on weekdays
    
    Use crontab.guru to test and validate your cron expressions with human-readable descriptions.

    Real-World Scheduling Examples

    Social Media Posting

    Post to multiple platforms throughout the day:
    const postToSocial = () => {
      speakText("Running social media post")
      
      // Post to Twitter
      magicClicker("Compose tweet button")
      delay(2000)
      magicClicker("Tweet text field")
      delay(500)
      // Type content
      magicClicker("Post button")
      delay(3000)
      
      // Switch to Instagram
      // ... Instagram posting logic
      
      speakText("Posted to all platforms")
    }
    
    // Post 3 times per day: 9am, 1pm, 6pm
    schedule("postToSocial", "0 9,13,18 * * *")
    

    Email Check Every 10 Minutes

    const checkEmail = () => {
      speakText("Checking email")
      
      // Open email app
      magicClicker("Inbox or email app")
      delay(2000)
      
      // Check for urgent emails
      const hasUrgent = magicScraper("Are there any unread urgent emails?")
      
      if (hasUrgent.toLowerCase().includes("yes")) {
        speakText("Urgent email detected")
        // Handle urgent email
      }
      
      speakText("Email check complete")
    }
    
    // Check every 10 minutes during work hours
    schedule("checkEmail", "*/10 9-17 * * 1-5")
    

    Nightly Backup

    const backupData = () => {
      speakText("Starting nightly backup")
      
      // Export data from various apps
      // Upload to cloud storage
      // Verify backup completed
      
      speakText("Backup completed successfully")
    }
    
    // Run every night at 2 AM
    schedule("backupData", "0 2 * * *")
    

    Weekend Morning Routine

    const weekendRoutine = () => {
      speakText("Good morning! Starting weekend routine")
      
      // Check weather
      const weather = magicScraper("What is today's weather forecast?")
      speakText("Today's weather: " + weather)
      
      // Check calendar
      magicClicker("Calendar app")
      delay(2000)
      
      const events = magicScraper("What events are scheduled for today?")
      speakText("Today's events: " + events)
      
      speakText("Weekend routine complete")
    }
    
    // Run Saturday and Sunday at 8 AM
    schedule("weekendRoutine", "0 8 * * 0,6")
    

    Combining Multiple Schedules

    Run different tasks on different schedules:
    // Frequent: Check notifications every 5 minutes
    const checkNotifications = () => {
      magicClicker("Notifications")
      delay(1000)
      const count = magicScraper("How many unread notifications?")
      speakText(count + " notifications")
    }
    schedule("checkNotifications", "*/5 * * * *")
    
    // Hourly: Post social media updates
    const postUpdate = () => {
      magicClicker("Create post")
      delay(2000)
      // Post content
    }
    schedule("postUpdate", "0 * * * *")
    
    // Daily: Generate report at end of day
    const generateReport = () => {
      speakText("Generating daily report")
      // Collect and compile data
    }
    schedule("generateReport", "0 17 * * 1-5")
    
    // Weekly: Clean up on Sundays
    const weeklyCleanup = () => {
      speakText("Running weekly cleanup")
      // Archive old data
    }
    schedule("weeklyCleanup", "0 0 * * 0")
    
    speakText("All schedules configured")
    

    Managing Scheduled Tasks

    View All Tasks

    From the MainActivity code, scheduled tasks are stored with:
    {
      id: "unique-task-id",
      taskDescription: "Your task description",
      cronExpression: "0 * * * *",
      createdAt: 1234567890,
      lastExecuted: 1234567890,
      isActive: true
    }
    

    Task Status

    Each task shows:
    • Created At: When the schedule was created
    • Last Executed: When it last ran
    • Next Run: Calculated from cron expression
    • Active Status: Whether it’s currently enabled

    Disable vs Delete

    To temporarily pause without deleting:
    // This requires accessing task management
    // Currently, use clearSchedule() to remove all
    clearSchedule()
    
    // Then re-add only the ones you want
    schedule("Keep this one", "0 * * * *")
    
    clearSchedule() removes ALL scheduled tasks. There’s no way to selectively remove individual tasks in the current ClawScript API.

    Scheduler Behavior

    How the Scheduler Works

    From the PhoneClaw source code:
    1. Cron Checker runs continuously in a coroutine
    2. Checks every minute if any tasks are due
    3. Compares current time against cron expressions
    4. Executes matching tasks
    5. Updates lastExecuted timestamp
    6. Schedules next check

    Execution Guarantees

    • Tasks run within 1 minute of scheduled time
    • If the device is asleep, tasks run when it wakes
    • Missed tasks don’t run retroactively
    • Only one instance of a task runs at a time

    Battery Considerations

    Frequent scheduled tasks can drain battery. Use reasonable intervals:
    • Every 5+ minutes is generally safe
    • Every 1-2 minutes may impact battery life
    • Every few seconds is not recommended for production

    Debugging Scheduled Tasks

    Test Your Cron Expression

    Before scheduling, verify your cron works:
    // Set to run in 2 minutes from now
    schedule("Test task", "*/2 * * * *")
    speakText("Test scheduled for 2 minutes")
    
    // Watch the Scheduled Tasks tab to verify it executes
    

    Add Logging

    Include speech feedback to confirm execution:
    const myTask = () => {
      const now = new Date().toLocaleTimeString()
      speakText("Task running at " + now)
      
      // Your automation logic
      
      speakText("Task completed")
    }
    
    schedule("myTask", "*/15 * * * *")
    

    Check Last Execution

    View the Scheduled Tasks tab to see:
    • When the task last ran
    • If it’s running on schedule
    • Any execution errors

    Best Practices

    Use Reasonable Intervals

    schedule("Check", "* * * * *") // Every minute
    

    Add Error Handling

    const robustTask = () => {
      try {
        speakText("Task starting")
        
        magicClicker("Some button")
        delay(2000)
        
        const result = magicScraper("Did it work?")
        if (result.includes("success")) {
          speakText("Task succeeded")
        } else {
          speakText("Task may have failed")
        }
      } catch (error) {
        speakText("Error in scheduled task")
      }
    }
    
    schedule("robustTask", "0 * * * *")
    

    Clear Old Schedules

    Before creating new schedules, clear old ones:
    // Remove all previous schedules
    clearSchedule()
    
    // Add new schedules
    schedule("newTask1", "0 9 * * *")
    schedule("newTask2", "0 18 * * *")
    

    Use Descriptive Names

    schedule("task1", "0 * * * *")
    

    Troubleshooting

    Task Not Running

    • Verify cron expression at crontab.guru
    • Check device isn’t in aggressive battery saving mode
    • Ensure PhoneClaw accessibility service is enabled
    • Check Scheduled Tasks tab for error messages

    Task Runs at Wrong Time

    • Verify device time zone is correct
    • Cron uses 24-hour format (0-23 for hours)
    • Day of week: 0 and 7 both mean Sunday
    • Check if you meant AM vs PM

    Multiple Tasks Conflict

    • Stagger schedules by a few minutes
    • Don’t schedule two tasks at exact same time
    • Add delays between app switches

    Battery Drain

    • Reduce task frequency
    • Combine multiple checks into one task
    • Schedule during specific hours only
    • Use */15 instead of */5 for intervals

    Next Steps

    Multi-App Workflows

    Chain scheduled tasks across apps

    ClawScript Functions

    See all available automation functions

    Voice Commands

    Generate schedules with voice