Scheduler
WASP's scheduler runs 41 background jobs that keep the agent active, learning, and aware — even when no user is interacting. Jobs are registered in src/main.py and each implements a simple async callable interface.
Job Registry
| Job Name | Interval | Purpose |
|---|---|---|
health_check | 5 min | Monitor Redis, Postgres, Ollama, disk, RAM, CPU |
reflection | 6 hours | LLM-driven memory reflection and synthesis |
memory_cleanup | 24 hours | Remove old episodic memories, orphaned data |
audit_retention | 24 hours | Delete audit_log entries older than 30 days (bounded batch) |
db_maintenance | 7 days | VACUUM ANALYZE to reclaim dead-row space and update planner stats |
snapshot | 24 hours | Full memory snapshot to /data/memory/ |
reminder_checker | 30 sec | Fire due reminders, trigger agent goals for recurring reminders |
monitor_checker | 5 min | Check price/RSS monitors for threshold violations |
proactive | 1 hour | Send proactive suggestions based on user context |
promotion | 12 hours | Promote frequent episodic memories to semantic |
checkin | 1 hour | Periodic user check-in messages |
custom_task_runner | 1 min | Execute user-defined scheduled tasks |
subscription_checker | 5 min | Check price/RSS subscriptions for alerts |
goal_tick | 15 sec | Advance active goal execution (up to 3 steps per tick) |
goal_meta_reflection | 5 min | Analyze goal health, detect storms, log meta-state |
agent_tick | 15 sec | Advance active sub-agent goals |
dream | 1 hour (gated) | Consolidate memories, reflect, prefetch data, analyze failure patterns |
autonomous | 30 min | Evaluate system state and generate proactive goals |
digest | 24 hours | Generate daily digest for user |
cpi_monitor | 5 min | Compute Cognitive Pressure Index |
self_integrity | 6 hours | Cross-check self-model vs actual performance |
perception | 15 min | Monitor crypto prices for significant moves |
behavioral_learner | 2 min | Process user corrections into behavioral rules |
world_model | 15 min | Update entity states from world_timeline |
skill_evolution | 6 hours | Synthesize new skills from recurring patterns |
vector_index | 30 min | Index new memory entries into memory_embeddings for semantic search |
capability_evolution | 1 hour | Evolve and merge capability definitions in the Capability Engine index |
capability_learner | 1 hour | Learn new capabilities from successful multi-step executions in audit_log |
opportunity_engine | 2 hours | Scan episodic memory for automation opportunities |
opportunities_processor | 5 min | Process and emit queued opportunity suggestions |
execution_knowledge_sync | 5 min | Flush Redis execution knowledge cache to PostgreSQL for durability |
execution_intelligence_monitor | 10 min | Detect evidence-based patterns in recent executions |
kg_insights_updater | 30 min | Update KG node salience scores and tool pattern cache |
procedural_pruner | 24 hours | Remove stale/unused procedural memory entries |
kg_pruner | 24 hours | Control Knowledge Graph node count (cap oldest low-salience nodes) |
learning_pruner | 7 days | Trim learning_examples table to bounded size |
behavioral_pruner | 30 days | Archive old behavioral rules that haven't been applied recently |
execution_reflection_pruner | 6 hours | Clean up old execution reflection records |
browser_session_cleanup | 7 days | Remove stale Chromium session profile directories |
screenshot_cleanup | 24 hours | Delete old screenshots from /data/screenshots/ |
kg_insights_updater | 30 min | Update KG salience + tool pattern cache |
Job Architecture
Jobs implement a simple async callable:
class DbMaintenanceJob:
async def __call__(self) -> str:
# execute maintenance logic
return "ok"
Registered in main.py:
scheduler.register("db_maintenance", 604800, DbMaintenanceJob())
The Scheduler manages all jobs:
- Tracks last run time per job in Redis (
scheduler:last_run:{job}) - Logs
scheduler.job_completewith job name and duration in ms - Handles exceptions without crashing other jobs
- CPI guard: skips
autonomous,dream,perceptionwhenagent:cpi_highis set
Key Jobs Explained
health_check (5 min)
Uses HealthMonitor to check:
- Redis: PING
- PostgreSQL: simple SELECT
- Ollama:
/api/tagsendpoint - Disk: usage percentage
- RAM: percent used
- CPU: percent used
When thresholds exceeded, SelfHealer triggers remediation (disk cleanup, Ollama restart, etc.).
audit_retention (24 hours)
AuditRetentionJob keeps the audit_log table bounded. Runs daily. Deletes entries older than 30 days using a bounded batch strategy:
DELETE FROM audit_log
WHERE id IN (
SELECT id FROM audit_log
WHERE timestamp < NOW() - INTERVAL '30 days'
ORDER BY timestamp ASC
LIMIT 5000
)
This avoids table locks that a single large DELETE would cause. Configure retention:
AUDIT_RETENTION_DAYS=90 # default: 30
db_maintenance (weekly)
DbMaintenanceJob runs VACUUM ANALYZE weekly to keep PostgreSQL healthy:
- Reclaims dead-row space for the free-space map
- Updates planner statistics for better query plans
- Does not lock tables (unlike
VACUUM FULL) - Runs outside a transaction (
AUTOCOMMITisolation)
Note:
VACUUM FULL(used in Panic Reset) rewrites the entire table for maximum disk reclamation but requires an exclusive lock.VACUUM ANALYZE(weekly) is the non-disruptive version for ongoing maintenance.
reminder_checker (30 sec)
Checks Redis for due reminders. For recurring reminders with an agent_id, calls agent_orchestrator.create_agent_goal() to restart the cycle. Regular reminders fire a Telegram message.
dream (1 hour, gated)
The Dream Mode job activates only when:
- User has been inactive for more than 2 hours
- Time is between 1 AM and 7 AM local, OR inactive for 4+ hours
- Has not run in the last 6 hours
- CPI is not high (
agent:cpi_highis not set)
When activated, Dream Mode runs 7 steps:
PromotionEngine(episodic → semantic promotion)- KG entity extraction from recent memories
- LLM reflection on recent events
- Pre-fetch crypto prices for monitored assets
- Log to
dream_logtable, updateagent:dream_state - Memory consolidation via
MemoryManager - Failure pattern analysis — queries
audit_logfor 7-day errors, classifies intotimeout / slow_response / repeated_failure / error, upserts intoself_model["known_failures"]
autonomous (30 min)
The AutonomousGoalGeneratorJob evaluates system state:
- Checks critical thresholds (disk >95%, RAM >95%) — no LLM needed
- For non-critical situations, asks the LLM for proactive recommendations
- If action warranted: calls
goal_orchestrator.create_goal()with priority=3 - Rate-limited: max 1 autonomous goal per hour, 5 per day
- Skipped when
agent:cpi_highis set
perception (15 min)
BackgroundPerceptionJob monitors crypto assets in the Knowledge Graph:
- Fetches current prices
- Compares vs last known price in the temporal model
- If change >4%, asks LLM whether to notify
- Sends Telegram alert if notable (max 3/day, respects quiet hours)
- Skipped when
agent:cpi_highis set
behavioral_learner (2 min)
Checks Redis behavioral:pending queue for user corrections:
- Correction detection patterns: "estás alucinando", "eso está mal", etc.
- LLM analyzes correction and extracts a rule
- Rule saved to
behavioral_rulestable - New rules cross-checked for conflicts with existing rules before saving
- Rule injected into every future system prompt
skill_evolution (6 hours)
Analyzes skill_patterns table for recurring multi-skill sequences:
- Minimum 5 occurrences required (configurable)
- LLM synthesizes a new composite skill from the pattern
- AST validation ensures generated code is safe
- New skill registered and available immediately
Pruner Jobs
A set of lightweight maintenance jobs keep tables bounded:
| Job | Interval | What it prunes |
|---|---|---|
procedural_pruner | 24h | Stale/unused procedural memory entries |
kg_pruner | 24h | Low-salience KG nodes over the cap |
learning_pruner | 7 days | Oldest learning_examples over the cap |
behavioral_pruner | 30 days | Old inactive behavioral rules |
execution_reflection_pruner | 6h | Old execution reflection records |
browser_session_cleanup | 7 days | Stale Chromium session profile directories |
screenshot_cleanup | 24h | Old screenshots in /data/screenshots/ |
Scheduler State
View job status in the dashboard at /scheduler.
Query last run times:
docker exec agent-redis redis-cli KEYS "scheduler:last_run:*" | sort
Quiet Hours
Jobs that send Telegram notifications respect quiet hours:
- Default: no notifications between 11 PM and 8 AM
- Configurable via
PROACTIVE_QUIET_STARTandPROACTIVE_QUIET_END
Disabling Jobs
Individual jobs can be skipped by disabling their feature flag:
SKILL_EVOLUTION_ENABLED=false # Skips skill_evolution job
WORLD_MODEL_ENABLED=false # Skips world_model job
VECTOR_MEMORY_ENABLED=false # Skips vector_index job
BEHAVIORAL_LEARNING_ENABLED=false # Skips behavioral_learner job
Disable the entire scheduler:
SCHEDULER_ENABLED=false