How to Implement Recurring Jobs with cron-parser in Agent-Native

Agent-Native provides a lightweight wrapper around the cron-parser library in packages/core/src/jobs/cron.ts that exposes three pure functions—nextOccurrence, isValidCron, and describeCron—to validate, describe, and schedule cron-based recurring jobs within the framework's job queue system.

BuilderIO/agent-native includes a robust job scheduling system that leverages the cron-parser library for recurring task execution. The framework provides pure utility functions in packages/core/src/jobs/cron.ts that handle cron expression parsing, validation, and human-readable description generation, allowing developers to implement recurring jobs safely without side effects.

Understanding the Cron Utilities in Agent-Native

The cron wrapper exports three pure functions that form the foundation of recurring job handling in Agent-Native.

Core Functions Overview

The wrapper in packages/core/src/jobs/cron.ts provides:

  • nextOccurrence(cronExpr, after?): Returns a Date object representing the next execution time for a given cron expression, optionally calculated after a specific date
  • isValidCron(cronExpr): Validates whether a cron expression is parseable by attempting to parse it within a try-catch block
  • describeCron(cronExpr): Generates human-readable descriptions like "Every weekday at 9 AM" by normalizing and analyzing the expression's fields

These utilities are completely side-effect free and covered by comprehensive unit tests in packages/core/src/jobs/cron.spec.ts.

Creating Recurring Jobs in Agent-Native

Recurring jobs in Agent-Native are stored in the jobs table within the core SQL schema. Each record contains the cron expression, target action name, payload, and computed nextRunAt timestamp.

Validating and Describing Cron Expressions

Before persisting a job, use isValidCron to validate the expression and describeCron to generate a user-friendly description for admin interfaces:

// src/actions/recurring.ts
import { defineAction } from '@agent-native/core/actions';
import {
  isValidCron,
  describeCron,
  nextOccurrence,
} from '@agent-native/core/jobs/cron';

interface ReportPayload {
  reportId: string;
}

export const createDailyReportJob = defineAction({
  name: 'createDailyReportJob',
  input: { reportId: 'string' },
  async run({ reportId }) {
    const cron = '0 9 * * *'; // 09:00 UTC every day
    
    if (!isValidCron(cron)) {
      throw new Error('Invalid cron expression');
    }

    const description = describeCron(cron); // "Every day at 9 AM"
    const firstRun = nextOccurrence(cron);

    await db.insert('jobs', {
      cron,
      targetAction: 'sendDailyReport',
      payload: { reportId } as ReportPayload,
      nextRunAt: firstRun,
      description,
    });

    return { ok: true, nextRunAt: firstRun, description };
  },
});

Processing Recurring Jobs with a Scheduler

The scheduler service queries the jobs table for entries where nextRunAt is less than or equal to the current time, dispatches the target action using Agent-Native's invocation API, and recomputes the next occurrence.

The Tick Loop Implementation

See templates/brain/jobs/process-ingest-queue.ts for a reference implementation of a job processor. Your recurring job worker should follow this pattern:

// src/server/jobs/worker.ts
import { db } from '@agent-native/server/db';
import { nextOccurrence } from '@agent-native/core/jobs/cron';
import { invokeAction } from '@agent-native/core/actions';

export async function processDueJobs() {
  const now = new Date();
  
  const dueJobs = await db.select('jobs', {
    where: { nextRunAt: { lte: now } },
  });

  for (const job of dueJobs) {
    await invokeAction(job.targetAction, job.payload);
    
    const nextRun = nextOccurrence(job.cron, now);
    await db.update('jobs', job.id, { nextRunAt: nextRun });
  }
}

This function runs at your desired interval—whether via setInterval in a Nitro plugin or a cloud-scheduled task—to continuously process the recurring job queue.

Summary

  • Agent-Native wraps cron-parser in packages/core/src/jobs/cron.ts to provide three pure functions: nextOccurrence, isValidCron, and describeCron
  • Job creation involves validating the cron expression, computing the first run time, and persisting to the jobs table with the target action and payload
  • Job processing requires a tick loop that queries due jobs, invokes the target action, and updates nextRunAt using nextOccurrence
  • The wrapper normalizes the @midnight alias and handles timezone considerations automatically
  • All utilities are pure functions with no side effects, making them safe to use in plugins, extensions, or frontend code for previewing schedules

Frequently Asked Questions

How does Agent-Native handle invalid cron expressions?

The isValidCron function in packages/core/src/jobs/cron.ts wraps the parser in a try-catch block and returns a boolean indicating validity. This allows you to reject malformed expressions at job creation time before they reach the database, preventing scheduler errors downstream.

What is the @midnight alias and why does it need normalization?

The @midnight alias is a historic cron shorthand that cron-parser v5 misinterprets. Agent-Native includes an internal ALIAS_MAP in the cron wrapper that normalizes this alias to the correct expression before parsing, ensuring consistent behavior across different versions of the underlying library.

Can I use these cron utilities on the frontend?

Yes. Because nextOccurrence, isValidCron, and describeCron are pure functions with no side effects, you can import them from @agent-native/core/jobs/cron into frontend code to preview schedule descriptions or validate expressions before submitting them to the server, reducing unnecessary API calls.

How do I test recurring jobs in Agent-Native?

Unit tests for the cron utilities are located in packages/core/src/jobs/cron.spec.ts and cover expression normalization, timezone handling, and description generation. For integration testing, you can mock the nextOccurrence function to return specific dates, or use the patterns shown in templates/brain/jobs/process-ingest-queue.ts to test your job processor logic independently of the actual clock.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →