Picobot has a built-in cron service for recurring tasks, a heartbeat system for periodic work, and daemon mode for running without an open terminal.
Cron Service¶
The cron service runs scheduled jobs through the agent loop. Jobs are persisted to ~/.picobot/data/cron/jobs.json and survive restarts.
Adding Jobs¶
From the CLI:
# Fixed interval (every 30 minutes = 1800 seconds)
picobot cron add "Check for new emails" --every 1800
# Cron expression (weekdays at 9 AM)
picobot cron add "Morning standup review" --cron "0 9 * * 1-5" --name "standup"
# Named job with interval
picobot cron add "Review TODO list" --every 300 --name "todo-check"
From within a conversation (the agent uses the cron tool):
cron(action="add", message="Check for new emails", every_seconds=1800)
cron(action="add", message="Morning standup", cron_expr="0 9 * * 1-5")
Schedule Formats¶
Interval (--every / every_seconds): Fixed interval in seconds.
| Interval | Seconds |
|---|---|
| Every 5 minutes | 300 |
| Every 30 minutes | 1800 |
| Every hour | 3600 |
| Every 6 hours | 21600 |
| Daily | 86400 |
Cron expression (--cron / cron_expr): Standard 5-field format:
┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of month (1-31)
│ │ │ ┌───────────── month (1-12)
│ │ │ │ ┌───────────── day of week (0-6, 0=Sunday)
│ │ │ │ │
* * * * *
| Expression | Meaning |
|---|---|
0 9 * * * |
Daily at 9 AM |
0 9 * * 1-5 |
Weekdays at 9 AM |
0 22 * * 5 |
Friday at 10 PM |
*/15 * * * * |
Every 15 minutes |
0 0 1 * * |
First day of month at midnight |
Managing Jobs¶
picobot cron list # List all enabled jobs
picobot cron list --all # Include disabled jobs
picobot cron remove <id> # Remove a job
picobot cron enable <id> # Enable a disabled job
picobot cron enable <id> -d # Disable a job
picobot cron run <id> # Manually trigger a job
picobot cron run <id> -f # Force-run even if disabled
How Jobs Execute¶
When a job fires, its message field is sent to the agent via process_direct() — exactly as if you typed it. The agent processes the message normally, using all available tools.
The cron service runs automatically in interactive mode (picobot agent). For background execution, use daemon mode.
Heartbeat¶
The heartbeat is a default cron job created during picobot init. It runs every 30 minutes and reads ~/.picobot/workspace/HEARTBEAT.md.
To use it: Add tasks under "Active Tasks":
## Active Tasks
- [ ] Check if any journal entries should be promoted to stable knowledge
- [ ] Review recent tool call logs for inefficiency patterns
If the file has no active tasks, the heartbeat is a no-op.
After completing tasks, the agent stores a brief journal entry in the KB noting what it did. This feeds the self-improvement pipeline.
Daemon Mode¶
The daemon keeps the cron service running without an open terminal.
Quick Start¶
# Run in foreground (for testing or manual use)
picobot daemon run
# Install as an OS service (auto-starts on boot)
picobot daemon install
How It Works¶
picobot daemon run is a foreground process that runs the cron service. It's designed to be supervised by the OS:
- macOS: launchd manages the process via a plist
- Linux: systemd manages it via a unit file
The daemon itself is simple — PID file locking (fcntl.flock) ensures only one instance runs. Signal handling provides graceful shutdown (SIGTERM/SIGINT) and config reload (SIGHUP).
Install/Uninstall¶
picobot daemon install # Generate and install OS service file
picobot daemon uninstall # Stop and remove service file
On macOS, this creates ~/Library/LaunchAgents/com.picobot.agent.plist with RunAtLoad and KeepAlive — the daemon starts on login and restarts if it crashes.
On Linux, this creates ~/.config/systemd/user/picobot.service with Restart=on-failure.
Monitoring¶
picobot daemon status # Check if daemon is running
picobot daemon logs # Tail daemon log (last 50 lines)
picobot daemon logs -n 100 # Last 100 lines
picobot daemon logs -f # Follow log output
Logs are written to ~/.picobot/data/logs/daemon.log with rotation (10MB per file, 3 backups).
Why Not Python Daemonization?¶
The daemon doesn't use python-daemon, double-fork, or any Python-level daemonization. Instead, picobot daemon run is a plain foreground process and the OS service manager handles backgrounding, restart, and lifecycle. This is simpler, more reliable, and works the way OS service managers expect.