Phase 5: Daemon ✅ COMPLETED¶
Goal: Build the main daemon process that ties everything together.
Status: ✅ Completed on 2026-01-22 (Commit: b9b9714)
Tasks¶
- Daemon Class (
src/reeve/pulse/daemon.py) ✅ - Implemented
PulseDaemonclass (273 lines) - Implemented
_scheduler_loop()- polls every 1 second - Implemented
_execute_pulse()- async pulse execution with error handling - Handles prompt building with sticky notes via PulseExecutor
- Graceful shutdown (SIGTERM/SIGINT) with 30-second grace period
-
See Daemon & API
-
Logging (
src/reeve/utils/logging.py) ✅ - Implemented
setup_logging()function (72 lines) - RotatingFileHandler with 10MB max, 5 backups
- Structured logging format
-
Console + file output (configurable)
-
Entry Point (
src/reeve/pulse/__main__.py) ✅ - Implemented module entry point (59 lines)
- Configuration loading and logging setup
-
Graceful KeyboardInterrupt handling
-
Testing ✅
- 21 comprehensive unit tests (tests/test_pulse_daemon.py)
- 2 integration/validation tests (tests/test_phase5_validation.py)
- All tests pass: 94/94
Deliverables¶
- ✅ Functional daemon process
- ✅ Pulse execution working end-to-end
- ✅ Proper logging with file rotation
- ✅ Comprehensive test suite
Validation¶
# Terminal 1: Start daemon
uv run python -m reeve.pulse
# Terminal 2: Schedule pulse via MCP (in Claude Code)
schedule_pulse(
scheduled_at="in 10 seconds",
prompt="Test pulse execution",
priority="high"
)
# Terminal 1: Watch logs for execution
# Should see: "Executing pulse X: Test pulse execution..."
# Should see: "Pulse X completed successfully in Yms"
Demo¶
Step 1: Start the daemon¶
# Terminal 1: Start daemon in foreground
uv run python -m reeve.pulse
# Expected output:
# 2026-01-19 10:30:00 | INFO | Starting Pulse Daemon...
# 2026-01-19 10:30:00 | INFO | Database: ~/.reeve/pulse_queue.db
# 2026-01-19 10:30:00 | INFO | Scheduler loop started (polling every 1s)
# 2026-01-19 10:30:00 | INFO | Ready to execute pulses
Step 2: Schedule pulses via MCP (in Claude Code or via demo script)¶
# Terminal 2: Run the demo script
uv run python demos/phase5_daemon_demo.py
# The script will:
# 1. Schedule 3 pulses with different priorities and timing
# 2. Watch the daemon execute them in priority order
# 3. Verify retry logic on simulated failures
# 4. Test graceful shutdown
Expected daemon output¶
2026-01-19 10:30:05 | INFO | Found 3 due pulses
2026-01-19 10:30:05 | INFO | Executing pulse #1 (CRITICAL): "Emergency system check"
2026-01-19 10:30:05 | INFO | Launching Hapi session...
2026-01-19 10:30:08 | INFO | Pulse #1 completed successfully (3.2s)
2026-01-19 10:30:10 | INFO | Executing pulse #2 (HIGH): "Morning briefing"
2026-01-19 10:30:10 | INFO | Launching Hapi session...
2026-01-19 10:30:13 | INFO | Pulse #2 completed successfully (2.8s)
2026-01-19 10:30:15 | INFO | Executing pulse #3 (NORMAL): "Check calendar"
2026-01-19 10:30:15 | INFO | Launching Hapi session...
2026-01-19 10:30:18 | INFO | Pulse #3 completed successfully (2.1s)
Step 3: Test retry logic¶
# The demo script will schedule a pulse that intentionally fails
# Expected daemon output:
2026-01-19 10:31:00 | INFO | Executing pulse #4 (HIGH): "Flaky task"
2026-01-19 10:31:00 | INFO | Launching Hapi session...
2026-01-19 10:31:02 | ERROR | Pulse #4 failed: Hapi returned error code 1
2026-01-19 10:31:02 | INFO | Scheduling retry #1 in 2 minutes
2026-01-19 10:33:02 | INFO | Executing pulse #5 (HIGH): "Flaky task (retry 1)"
2026-01-19 10:33:02 | INFO | Launching Hapi session...
2026-01-19 10:33:05 | INFO | Pulse #5 completed successfully (2.5s)
Step 4: Test graceful shutdown¶
# In Terminal 1, press Ctrl+C
^C2026-01-19 10:35:00 | INFO | Received shutdown signal
2026-01-19 10:35:00 | INFO | Waiting for 1 running pulse to complete...
2026-01-19 10:35:02 | INFO | All pulses completed
2026-01-19 10:35:02 | INFO | Daemon shut down gracefully
Previous: Phase 4: Pulse Executor
Next: Phase 6: HTTP API