Mentu

Scheduling Scripts

Scheduling Scripts

This guide walks you through scheduling a script to run on a cron schedule using temporals.

1. Create the script

First, write the script you want to schedule. Save it as ~/.mentu/scripts/daily-report.ts:

const stats = mentu.cir.stats();
const recent = mentu.cir.query({ since: '24h', limit: 100 });
const contradictions = mentu.cir.contradictions();
const ledger = mentu.ledger.verify();
 
console.log('=== Daily Report ===');
console.log(`Signals (24h): ${recent.length}`);
console.log(`Total signals: ${stats.signals}`);
console.log(`Contradictions: ${contradictions.length}`);
console.log(`Ledger: ${ledger.valid ? 'valid' : 'INVALID'} (${ledger.entries} entries)`);
 
// Capture the report as a CIR signal
mentu.cir.capture(`Daily report: ${recent.length} signals (24h), ${contradictions.length} contradictions`, {
  type: 'observation',
  domain: 'reporting',
  source: 'daily-report',
  confidence: 1.0,
});
 
if (contradictions.length > 0 || !ledger.valid) {
  mentu.notify.send('Daily Report', `${contradictions.length} contradictions, ledger ${ledger.valid ? 'OK' : 'INVALID'}`);
}
 
return { recent: recent.length, contradictions: contradictions.length, ledger };

Test it manually first:

mentu script run daily-report

2. Create the temporal definition

Save the temporal definition as ~/.mentu/temporals/daily-report.json:

{
  "name": "daily-report",
  "description": "Generate a daily CIR status report every morning at 8 AM",
  "schedule": "0 8 * * *",
  "script": "daily-report",
  "enabled": false,
  "cooldown": 300,
  "circuit_breaker_threshold": 3,
  "circuit_breaker_reset_ttl": 7200,
  "notify": true,
  "history_limit": 30,
  "workspace": "/Users/you/project"
}

Key fields:

  • schedule: "0 8 * * *" — runs at 8:00 AM every day
  • script: "daily-report" — targets the script we just wrote
  • enabled: false — starts disabled so we can test first
  • circuit_breaker_threshold: 3 — breaks circuit after 3 consecutive failures
  • circuit_breaker_reset_ttl: 7200 — attempts auto-recovery after 2 hours

3. Test with manual fire

Before enabling the schedule, fire the temporal manually to verify everything works:

mentu temporal fire daily-report

This executes the script immediately, regardless of the schedule. Check the output to make sure it works as expected.

4. Enable the temporal

Once you've verified the script works:

mentu temporal enable daily-report

The temporal is now active. It will fire according to its cron schedule.

5. Monitor the temporal

Check the status at any time:

mentu temporal status daily-report

This shows:

  • Whether it's enabled and whether the circuit is broken
  • Last run time and next scheduled run
  • Consecutive failure count
  • Execution history

List all temporals:

mentu temporal list

6. Circuit breaker behavior

If the script fails 3 times in a row, the circuit breaks:

Run at 08:00 → failure (consecutive_failures: 1)
Run at 08:00 next day → failure (consecutive_failures: 2)
Run at 08:00 next day → failure (consecutive_failures: 3) → CIRCUIT BROKEN

When the circuit is broken:

  • The temporal stays in the schedule but does not fire
  • mentu temporal status shows circuit_broken: true
  • If circuit_breaker_reset_ttl is set, a probe run happens after that interval

Auto-recovery

With circuit_breaker_reset_ttl: 7200 (2 hours), the temporal attempts one probe run 2 hours after the circuit broke:

  • If the probe succeeds: circuit resets, normal scheduling resumes
  • If the probe fails: circuit stays broken, timer restarts

Manual recovery

You can manually re-enable a circuit-broken temporal:

mentu temporal enable daily-report

This resets the failure count and circuit state.

Common cron schedules

Schedule Cron expression
Every hour 0 * * * *
Every 6 hours 0 */6 * * *
Daily at 8 AM 0 8 * * *
Daily at midnight 0 0 * * *
Weekdays at 9 AM 0 9 * * 1-5
Every Monday at 6 AM 0 6 * * 1
First of month at midnight 0 0 1 * *

Managing temporals from scripts

You can manage temporals programmatically using the SDK:

const temporals = mentu.temporal.list();
const broken = temporals.filter(t => t.circuit_broken);
 
if (broken.length > 0) {
  console.log(`${broken.length} temporals have broken circuits:`);
  for (const t of broken) {
    console.log(`  ${t.name}: ${t.consecutive_failures} failures`);
    // Optionally re-enable
    mentu.temporal.enable(t.name);
  }
}

This pattern lets you build a "temporal manager" script that monitors and recovers other temporals — and schedule that script as a temporal too.

Next steps

© 2026 Mentu.