Temporals
Temporals
Temporals are mentu's scheduling primitive. A temporal binds a script or formula to a cron schedule and wraps it with resilience features: circuit breakers, cooldowns, TTL, auto-recovery, and execution history.
What is a temporal?
A temporal definition is a JSON file that tells mentu: "run this thing on this schedule, and handle failures intelligently."
{
"name": "daily-health",
"description": "Run system health check every hour",
"schedule": "0 * * * *",
"script": "daily-health",
"enabled": true,
"cooldown": 60,
"circuit_breaker_threshold": 3,
"circuit_breaker_reset_ttl": 3600,
"notify": true,
"workspace": "/Users/you/project"
}The schedule field is a standard 5-field cron expression: minute, hour, day-of-month, month, day-of-week. The target is either a script (TypeScript, run via mentu script run) or a formula (recipe, run via mentu run). Exactly one must be set.
Temporal definition fields
| Field | Type | Description |
|---|---|---|
name |
string | Unique identifier |
description |
string | Human-readable description |
schedule |
string | 5-field cron expression |
formula |
string | Recipe name to execute (mutually exclusive with script) |
script |
string | Script name to execute (mutually exclusive with formula) |
enabled |
boolean | Whether the temporal is active |
cooldown |
int | Minimum seconds between runs |
ttl |
int | Evidence TTL in seconds — results expire after this |
on_ttl_expire |
string | Action on expiry: rerun, notify, or decay |
catch_up |
string | Missed-run policy: skip, run_once, or run_all |
jitter |
int | Max random delay in seconds before fire |
max_budget |
float | USD budget cap per execution |
circuit_breaker_threshold |
int | Consecutive failures before circuit breaks (default: 3) |
circuit_breaker_reset_ttl |
int | Seconds after break before attempting a probe run |
notify |
boolean | Send macOS notification on completion |
expires_at |
string | ISO 8601 date — temporal auto-removes after this |
history_limit |
int | Max history entries to retain |
model |
string | Model override for formula execution |
backend |
string | Backend provider override |
workspace |
string | Project root for formula/script execution |
Resilience features
Circuit breaker
The circuit breaker prevents a failing temporal from running endlessly and wasting resources. After circuit_breaker_threshold consecutive failures (default: 3), the temporal's circuit breaks — it stops firing until manually re-enabled or auto-recovery kicks in.
Run 1: success ✓ (consecutive_failures: 0)
Run 2: success ✓ (consecutive_failures: 0)
Run 3: failure ✗ (consecutive_failures: 1)
Run 4: failure ✗ (consecutive_failures: 2)
Run 5: failure ✗ (consecutive_failures: 3) → CIRCUIT BROKENWhen the circuit breaks, the temporal stays in the schedule but does not fire. Its status shows circuit_broken: true.
Auto-recovery
If circuit_breaker_reset_ttl is set, the temporal attempts a single probe run after that many seconds. If the probe succeeds, the circuit resets and normal scheduling resumes. If it fails, the circuit stays broken and the timer restarts.
Circuit broken at 14:00
circuit_breaker_reset_ttl: 3600 (1 hour)
15:00 → probe run → failure → circuit stays broken, timer resets
16:00 → probe run → success → circuit reset, normal scheduling resumesCooldown
The cooldown field prevents re-fire during execution. If a temporal's script takes 45 seconds and the cooldown is 60 seconds, the next run won't start until at least 60 seconds after the previous one began, even if the cron schedule says it should.
TTL and evidence decay
The ttl field sets how long a temporal's results are considered valid. When the TTL expires, the on_ttl_expire action fires:
rerun— immediately re-execute the temporalnotify— send a notification that evidence has expireddecay— mark the evidence as decayed in CIR
Managing temporals
CLI commands
# List all temporals
mentu temporal list
# Check status of a specific temporal
mentu temporal status daily-health
# Enable a disabled temporal
mentu temporal enable daily-health
# Disable an active temporal
mentu temporal disable daily-health
# Fire a temporal immediately (regardless of schedule)
mentu temporal fire daily-healthSDK access (in scripts)
// List all temporal definitions
const temporals = mentu.temporal.list();
// Check status
const status = mentu.temporal.status('daily-health');
// Enable/disable
mentu.temporal.enable('daily-health');
mentu.temporal.disable('daily-health');
// Fire immediately
const output = mentu.temporal.fire('daily-health');Script integration
Setting "script": "daily-health" in a temporal definition means the temporal fires mentu script run daily-health on every scheduled execution. The script has full SDK access — it can query CIR, read vault secrets, trigger sequences, and capture new signals.
This is scheduled intelligence: a TypeScript script with access to the entire mentu platform, running on a cron schedule, with automatic circuit breaking and recovery.
Example: Hourly health check with circuit breaker
Temporal definition (~/.mentu/temporals/hourly-health.json):
{
"name": "hourly-health",
"description": "Run health check script every hour, break after 3 failures, auto-recover after 1 hour",
"schedule": "0 * * * *",
"script": "daily-health",
"enabled": true,
"cooldown": 120,
"circuit_breaker_threshold": 3,
"circuit_breaker_reset_ttl": 3600,
"notify": true,
"workspace": "/Users/you/project"
}Script (~/.mentu/scripts/daily-health.ts):
const health = mentu.health.check();
const stats = mentu.cir.stats();
const contradictions = mentu.cir.contradictions();
const ledger = mentu.ledger.verify();
const issues: string[] = [];
if (contradictions.length > 3) {
issues.push(`${contradictions.length} contradictions in CIR`);
}
if (!ledger.valid) {
issues.push('Ledger integrity check failed');
}
if (issues.length > 0) {
mentu.notify.send('Health Alert', issues.join('; '));
mentu.cir.capture(`Health check found ${issues.length} issue(s): ${issues.join(', ')}`, {
type: 'observation',
domain: 'health',
source: 'daily-health',
confidence: 1.0,
});
} else {
console.log(`All clear: ${stats.signals} signals, ${ledger.entries} ledger entries`);
}
return { healthy: issues.length === 0, issues, stats };Every hour, the temporal fires the script. If the script fails 3 times in a row, the circuit breaks. One hour later, a probe run tests whether the issue resolved. If it passes, the schedule resumes automatically.