LuaJob allows you to define scheduled tasks that run automatically without user interaction. Unlike the Jobs API which creates jobs dynamically, LuaJob is for pre-defined jobs that are part of your agent configuration.
import { LuaJob, User } from 'lua-cli';const dailyReport = new LuaJob({ name: 'daily-sales-report', description: 'Generate daily sales summary', metadata: { userId: 'user_abc123' // Store user ID to notify }, schedule: { type: 'cron', expression: '0 9 * * *' // Every day at 9 AM }, execute: async (job) => { // Generate report const report = await generateSalesReport(); // ⚠️ Pre-defined jobs have NO conversational context // Get user by ID from metadata const user = await User.get(job.metadata.userId); await user.send([{ type: 'text', text: report }]); }});
No Conversational Context: LuaJob executes outside of user conversations. You MUST use User.get(userId) with a userId from metadata. The job does NOT have jobInstance.user() - that’s only for dynamic jobs.
New in v3.0.0: Pre-defined jobs that are part of your agent configuration. Use with LuaAgent.
Key Difference: Pre-defined LuaJob has NO user context. Use User.get(userId) with ID from metadata. Dynamic jobs (Jobs API) automatically have user context via jobInstance.user().
// Every day at 9 AMschedule: { type: 'cron', expression: '0 9 * * *'}// Every Monday at 8 AM ESTschedule: { type: 'cron', expression: '0 8 * * 1', timezone: 'America/New_York'}// Every hour on the hourschedule: { type: 'cron', expression: '0 * * * *'}// First day of every month at midnightschedule: { type: 'cron', expression: '0 0 1 * *'}
import { LuaJob, Data, User } from 'lua-cli';const weeklyCleanup = new LuaJob({ name: 'weekly-cleanup', description: 'Clean up old data every Sunday', metadata: { adminUserId: 'user_admin123' // Store admin userId to notify }, schedule: { type: 'cron', expression: '0 0 * * 0' // Every Sunday at midnight }, execute: async (jobInstance) => { // Delete old entries (older than 30 days) const thirtyDaysAgo = new Date(); thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30); const oldEntries = await Data.get('temp-data', 1000); let deletedCount = 0; for (const entry of oldEntries) { const createdAt = new Date(entry.createdAt); if (createdAt < thirtyDaysAgo) { await Data.delete('temp-data', entry.id); deletedCount++; } } // Send summary to admin // ⚠️ Pre-defined jobs have NO user context // Get user by ID from metadata const user = await User.get(jobInstance.metadata.adminUserId); await user.send([{ type: 'text', text: `🧹 Weekly cleanup complete. Deleted ${deletedCount} old entries.` }]); return { success: true, deletedCount, timestamp: new Date().toISOString() }; }});export default weeklyCleanup;
import { LuaJob, Data, User } from 'lua-cli';const userReminders = new LuaJob({ name: 'check-reminders', description: 'Check and send due reminders every 5 minutes', schedule: { type: 'interval', seconds: 300 // Every 5 minutes }, execute: async (jobInstance) => { // Get reminders due now const now = new Date(); const reminders = await Data.get('reminders', 100); let sentCount = 0; for (const reminder of reminders) { const dueTime = new Date(reminder.data.dueAt); if (dueTime <= now && !reminder.data.sent) { // ⚠️ Pre-defined jobs have NO user context // Each reminder must store the userId to send to const user = await User.get(reminder.data.userId); await user.send([{ type: 'text', text: `⏰ Reminder: ${reminder.data.message}` }]); // Mark as sent await Data.update('reminders', reminder.id, { ...reminder.data, sent: true, sentAt: now.toISOString() }); sentCount++; } } return { success: true, checked: reminders.length, sent: sentCount, timestamp: now.toISOString() }; }});export default userReminders;
Manually triggers the job execution (ignores schedule). Uses the active version by default.Parameters:
versionId (optional): Specific version to execute. Defaults to activeVersion.
Returns:Promise<JobExecution>
// Trigger with default active versionconst execution = await jobInstance.trigger();console.log('Execution ID:', execution.id);// Trigger with specific versionconst execution = await jobInstance.trigger('version_abc123');
Use Agents.invoke to delegate work to a conversational agent from inside a scheduled job. Pre-defined jobs have no ambient user, so pass a userId when you have one (e.g. from job metadata). When no userId is available, omit it and the invocation runs without user identity — no conversation history is stored.
import { LuaJob, Agents, User } from 'lua-cli';// With a known user — invocation runs in their contextconst userReminderJob = new LuaJob({ name: 'weekly-summary', schedule: { type: 'cron', expression: '0 9 * * 1' }, metadata: { userId: 'user_abc123' }, execute: async (job) => { const result = await Agents.invoke('summary-agent', { prompt: 'Generate the weekly activity summary for this user.', userId: job.metadata.userId, // conversation history stored for this user }); const user = await User.get(job.metadata.userId); await user.send([{ type: 'text', text: result.text }]); return { sent: true }; },});// Without a user — no conversation history storedconst dailyDigestJob = new LuaJob({ name: 'daily-digest-generator', schedule: { type: 'cron', expression: '0 6 * * *' }, execute: async (job) => { const result = await Agents.invoke('digest-agent', { prompt: 'Generate the daily digest.', // userId omitted — invocation runs without user identity }); return { digest: result.text }; },});
Agents API Reference
Full documentation for Agents.invoke — options, output shape, error handling, and more examples