boxlang-scheduled-tasks — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited boxlang-scheduled-tasks (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
BoxLang is the AI-native software productivity platform for building, modernizing and running applications, with developers and AI agents working together.
BoxLang offers two scheduling models:
BaseScheduler and ScheduledTaskUse the Scheduler DSL for rich in-process logic and task callbacks. Use bx:schedule for simple persistent URL triggers.
You can register scheduler classes directly in Application.bx so they are auto-discovered for the app context.
For full descriptor behavior (app discovery, multi-app isolation, lifecycle), see application-descriptor.
class {
this.name = "MyApp"
// Auto-register scheduler classes for this application
this.schedulers = [
"schedulers.DailyMaintenance",
"schedulers.HourlyReports"
]
}Use this when scheduler lifecycle should be managed with application startup/shutdown rather than ad-hoc schedulerStart() calls.
A scheduler class wraps BaseScheduler and registers tasks fluently in configure().
class {
property name="scheduler"
property name="logger"
function configure() {
scheduler
.setSchedulerName( "reporting-scheduler" )
.setTimezone( "America/Chicago" )
scheduler.task( "daily-report", "reports" )
.call( () => generateDailyReport() )
.everyDayAt( "02:00" )
.onFailure( ( task, exception ) => {
logger.error( "Task #task.getName()# failed: #exception.message#" )
} )
}
}// Start from class path (creates, configures, registers, and starts)
schedulerStart( className = "schedulers.ReportingScheduler", name = "reporting", force = true )
// Lookup / control
schedulerGet( "reporting" )
schedulerStats( "reporting" )
schedulerRestart( "reporting", force = false, timeout = 30 )
schedulerShutdown( "reporting", force = false, timeout = 30 )bx:schedule Component (HTTP-Driven)bx:schedule persists task definitions (default: ${boxlang-home}/config/tasks.json) and executes scheduled HTTP GET requests.
bx:schedule action="create"
task="nightlyCleanup"
url="https://myapp.example/tasks/cleanup"
cronTime="0 2 * * *";
bx:schedule action="pause" task="nightlyCleanup";
bx:schedule action="run" task="nightlyCleanup";
bx:schedule action="delete" task="nightlyCleanup";Use this approach for webhooks, callback endpoints, and operational pings.
Core scheduler lifecycle BIFs:
schedulerStart( className, name?, force=true )schedulerGet( name )schedulerGetAll()schedulerList()schedulerStats( name? )schedulerRestart( name, force=false, timeout=30 )schedulerShutdown( name, force=false, timeout=30 )Notes:
schedulerStart() instantiates the BoxLang class, wraps it in BoxScheduler, calls configure(), then registers/starts it.schedulerRestart() and schedulerShutdown() validate scheduler existence and throw if missing.Use meaningful names and optional groups for operational clarity.
scheduler.task( "cleanup-expired-sessions", "maintenance" )
.call( () => cleanupSessions() )
.every( 15, "minutes" )
scheduler.task( "send-weekly-digest", "notifications" )
.call( () => sendDigest() )
.everyWeekOn( "Monday", "08:30" )Disable-at-registration for debugging:
scheduler.xtask( "experimental-task", "debug" )
.call( () => runExperiment() )
.everyMinute()every( period, timeUnit )spacedDelay( delay, timeUnit ) (no overlap style)cron( expression )everySecond(), everyMinute(), everyHour(), everyHourAt( minute )everyDay(), everyDayAt( "HH:mm" )everyWeek(), everyWeekOn( day, time )everyMonth(), everyMonthOn( day, time )everyYear(), everyYearOn( month, day, time )onWeekdays( time ), onWeekends( time )everyMonthOn( day ) clamps to the last day of shorter months (v1.18+), so everyMonthOn( 31 ) runs once in February instead of every day.
When the same scheduler is deployed to every node, each node runs every task. Call .onOneServer() so only one node runs each execution. BoxLang uses the scheduler's cacheName cache as a distributed lock, so point it at a cache the servers share (for example Redis via bx-redis).
task( "nightly-cleanup" )
.call( () => cleanupOldRecords() )
.everyDayAt( "02:00" )
.onOneServer()Time units supported in scheduler APIs include: days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds.
Supported formats:
minute hour day-of-month month day-of-weeksecond minute hour day-of-month month day-of-weekExamples:
// Every day at 2:00 AM
scheduler.task( "nightly" )
.call( () => nightlyJob() )
.cron( "0 2 * * *" )
// Every weekday at 8:30:00 AM
scheduler.task( "weekday-digest" )
.call( () => digestJob() )
.cron( "0 30 8 * * MON-FRI" )name and timezone.onFailure hooks and centralized logging for observability.spacedDelay() or no-overlap patterns when tasks can run longer than their interval..onOneServer() for cluster-wide jobs that must run once (v1.18+).boxlang schedule and boxlang schedule --json (v1.18+).schedulerStart() was called and schedulerList() contains the name..onOneServer() and use a shared cacheName (v1.18+).schedulerStats() counters (totalFailures, lastResult).~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.