Removed redundant/outdated files: - docs/HEARTBEAT_HOOKS.md (legacy, disabled by default) - docs/QUICK_START_PULSE.md (merged into PULSE_BRAIN.md) - docs/MONITORING_COMPARISON.md (merged into PULSE_BRAIN.md) Consolidated monitoring docs: - Merged 3 monitoring files into comprehensive PULSE_BRAIN.md - Added Quick Start section to PULSE_BRAIN.md - Added "Why Pulse & Brain?" comparison section - Added deprecation notices for Heartbeat system Updated README.md: - Clarified Haiku is default model (12x cheaper) - Added prompt caching info (90% savings on Sonnet) - Removed duplicate setup instructions - Linked to SETUP.md for detailed instructions - Added model switching commands section Simplified WINDOWS_QUICK_REFERENCE.md: - Reduced from 224 lines to ~160 lines - Removed redundant development/deployment sections - Kept essential quick commands - Added model switching commands Updated docs/README.md navigation: - Removed references to deleted files - Added deprecation notice for Heartbeat - Updated learning paths - Cleaned up file organization section Result: - Removed 300+ lines of redundant documentation - Consolidated 3 monitoring files into 1 - Improved accuracy and clarity - Easier navigation and maintenance Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
19 KiB
Pulse & Brain Architecture
⭐ The most efficient way to run an agent with proactive monitoring.
Note: The old Heartbeat system is now legacy and disabled by default. Use Pulse & Brain for all new deployments.
🚀 Quick Start
Copy-paste ready setup in under 50 lines:
Basic Monitoring (Zero-cost pulse, conditional agent)
from agent import Agent
from pulse_brain import PulseBrain
# Initialize agent (disable old heartbeat)
agent = Agent(provider="claude", enable_heartbeat=False)
# Create Pulse & Brain with 60-second pulse interval
pb = PulseBrain(agent, pulse_interval=60)
# Start monitoring
pb.start()
With Slack/Telegram Integration
from adapters.runtime import AdapterRuntime
from adapters.slack.adapter import SlackAdapter
from pulse_brain import PulseBrain
agent = Agent(provider="claude", enable_heartbeat=False)
# Set up messaging adapters
slack = SlackAdapter(bot_token="xoxb-...", channel="C_MONITORING")
runtime = AdapterRuntime(agent)
runtime.add_adapter(slack)
# Create Pulse & Brain with adapter support
pb = PulseBrain(agent, pulse_interval=60)
pb.add_adapter("slack", slack)
# Start both systems
await runtime.start()
pb.start()
Custom Pulse Check (Zero Cost)
from pulse_brain import PulseCheck, BrainTask, CheckType
def check_my_server():
"""Pure Python check - no agent, no cost."""
import requests
try:
r = requests.get("http://localhost:8000/health", timeout=5)
return {"status": "ok" if r.status_code == 200 else "error"}
except:
return {"status": "error", "message": "Server down"}
# Add to Pulse & Brain
pb = PulseBrain(agent)
pb.add_pulse_check(PulseCheck("my-server", check_my_server, interval_seconds=60))
# Only invoke agent when server is down
pb.add_brain_task(BrainTask(
name="server-fixer",
check_type=CheckType.CONDITIONAL,
prompt_template="Server is down! What should I check?",
condition_func=lambda data: data.get("status") == "error"
))
pb.start()
That's it! Your agent now monitors your system 24/7 at ~$1-2/month.
🎯 The Problem
Running an agent in a loop is expensive:
# ❌ EXPENSIVE: Agent asks "What should I do?" every loop
while True:
response = agent.chat("What should I do?") # Costs tokens!
time.sleep(60)
Cost: If you check every minute for 24 hours:
- 1,440 API calls/day
- ~50,000 tokens/day
- ~$0.50/day just to ask "nothing to do"
✅ The Solution: Pulse & Brain
Think of it like a security guard:
- Pulse (Guard): Walks the perimeter every 60 seconds. Checks doors (pure Python). Cost: $0
- Brain (Manager): Only called when guard sees a problem or it's time for the morning report. Cost: Only when needed
# ✅ EFFICIENT: Agent only invoked when needed
while True:
# Pulse: Pure Python checks (zero cost)
disk_check = check_disk_space() # $0
log_check = check_for_errors() # $0
task_check = check_stale_tasks() # $0
# Brain: Only if something needs attention
if disk_check.status == "error":
agent.chat("Disk space critical!") # Costs tokens (but only when needed)
if current_time == "08:00":
agent.chat("Morning briefing") # Costs tokens (scheduled)
time.sleep(60)
📊 Cost Comparison
Old Heartbeat System (Always Uses Agent)
# Every 30 minutes, agent processes checklist
while True:
response = agent.chat(checklist) # ~1000 tokens
time.sleep(1800) # 30 min
Cost per day:
- 48 checks/day
- ~48,000 tokens/day
- ~$0.48/day
Pulse & Brain (Conditional Agent)
# Every 60 seconds, pure Python checks (zero cost)
# Agent only invoked when:
# 1. Error detected (~2x/day)
# 2. Scheduled briefings (2x/day)
# = ~4 agent calls/day
Cost per day:
- 1,440 pulse checks (pure Python) = $0
- 4 brain invocations (~4,000 tokens) = $0.04/day
Savings: 92% 💰
🏗️ Architecture
┌─────────────────────────────────────────────────────┐
│ PULSE LOOP │
│ (Pure Python, $0 cost) │
│ │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
│ │ Disk Space│ │ Log Errors│ │ Tasks │ │
│ │ Check │ │ Check │ │ Check │ ... │
│ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ │
│ │ │ │ │
│ └──────────────┼──────────────┘ │
│ │ │
│ ┌───────▼───────┐ │
│ │ Conditions? │ │
│ └───────┬───────┘ │
│ │ │
│ ┌──────────────┴──────────────┐ │
│ │ │ │
│ ┌────▼────┐ ┌────▼────┐ │
│ │ Error? │ │ 8:00 AM?│ │
│ └────┬────┘ └────┬────┘ │
│ │ YES │ YES │
└────────┼─────────────────────────────┼──────────────┘
│ │
└──────────┬──────────────────┘
│
┌──────────▼──────────┐
│ BRAIN │
│ (Agent/SDK) │
│ COSTS TOKENS │
└─────────────────────┘
📝 Default Checks
Pulse Checks (Zero Cost)
| Check | Interval | What It Does |
|---|---|---|
disk-space |
5 min | Checks disk usage, warns >80% |
memory-tasks |
10 min | Counts pending tasks |
log-errors |
1 min | Scans logs for errors |
Brain Tasks (Uses Tokens)
| Task | Type | Trigger |
|---|---|---|
disk-space-advisor |
Conditional | Disk >90% used |
error-analyst |
Conditional | Errors found in logs |
morning-briefing |
Scheduled | Daily at 8:00 AM |
evening-summary |
Scheduled | Daily at 6:00 PM |
🎨 Custom Configuration
Create config/pulse_brain_config.py:
from pulse_brain import PulseCheck, BrainTask, CheckType
def check_my_server() -> dict:
"""Pure Python check (zero cost)."""
import requests
try:
r = requests.get("http://localhost:8000/health")
return {
"status": "ok" if r.status_code == 200 else "error",
"message": f"Server: {r.status_code}"
}
except:
return {"status": "error", "message": "Server down"}
CUSTOM_PULSE_CHECKS = [
PulseCheck("my-server", check_my_server, interval_seconds=60)
]
CUSTOM_BRAIN_TASKS = [
BrainTask(
name="server-medic",
check_type=CheckType.CONDITIONAL,
prompt_template="Server is down! {message}\n\nWhat should I check?",
condition_func=lambda data: data.get("status") == "error"
)
]
🌟 Real-World Examples
Example 1: Homelab Monitoring (from Gemini)
The "Morning Briefing" (Scheduled Brain):
BrainTask(
name="homelab-morning",
check_type=CheckType.SCHEDULED,
schedule_time="08:00",
prompt_template="""Good morning Jordan!
Overnight summary:
- Plex: {plex_status}
- Star Citizen: {game_status}
- UniFi: {network_status}
Any restarts or patches detected?""",
send_to_platform="slack",
send_to_channel="C_HOMELAB"
)
Cost: 1 API call/day = ~$0.01
The "Medic" (Conditional Brain):
def check_logs():
"""Pure Python log scanner."""
with open("/var/log/syslog") as f:
recent = f.readlines()[-100:]
errors = [line for line in recent if "ERROR" in line]
return {
"status": "error" if errors else "ok",
"error_lines": errors
}
BrainTask(
name="error-medic",
check_type=CheckType.CONDITIONAL,
prompt_template="""Errors detected in logs:
{error_lines}
What does this mean and should I fix it?""",
condition_func=lambda data: data.get("status") == "error"
)
Cost: Only when errors found = ~$0.01 per error
The "Resource Manager" (Conditional Brain):
BrainTask(
name="disk-cleanup",
check_type=CheckType.CONDITIONAL,
prompt_template="""Disk space is low: {gb_free:.1f} GB free.
Please:
1. Scan temp folders
2. Recommend what to delete (>7 days old)
3. Provide cleanup commands""",
condition_func=lambda data: data.get("gb_free", 100) < 10
)
Cost: Only when disk < 10GB = ~$0.02 per trigger
Example 2: Docker Monitoring
def check_docker():
import subprocess
result = subprocess.run(
["docker", "ps", "--format", "{{.Status}}"],
capture_output=True, text=True
)
unhealthy = sum(1 for line in result.stdout.split("\n")
if "unhealthy" in line)
return {
"status": "error" if unhealthy > 0 else "ok",
"unhealthy_count": unhealthy
}
PULSE_CHECK = PulseCheck("docker", check_docker, interval_seconds=60)
BRAIN_TASK = BrainTask(
name="docker-fixer",
check_type=CheckType.CONDITIONAL,
prompt_template="{unhealthy_count} containers unhealthy. What should I do?",
condition_func=lambda data: data.get("unhealthy_count", 0) > 0
)
Pulse runs every 60s: $0 Brain only when unhealthy: ~$0.01 per incident
💡 Why Pulse & Brain?
The Evolution of Monitoring
Ajarbot has had three different monitoring systems. Here's how they compare:
| Feature | Pulse & Brain ⭐ | TaskScheduler | Old Heartbeat ⚠️ |
|---|---|---|---|
| Cost per day | ~$0.04 | ~$0.10-0.30 | ~$0.48 |
| Cost per month | ~$1.20 | ~$3-9 | ~$14.40 |
| Agent usage | Only when needed | Every scheduled task | Every interval |
| Scheduling | Cron + Conditional | Cron only | Interval only |
| Monitoring | ✅ Zero-cost pulse | ❌ None | ❌ Uses agent |
| Messaging | ✅ Slack/Telegram | ✅ Slack/Telegram | ❌ None |
| Best for | Production monitoring | Content generation | ⚠️ Legacy (deprecated) |
| Status | ✅ Recommended | ✅ Active | ⚠️ Disabled by default |
Why Pulse & Brain Wins
1. Zero-Cost Monitoring
# Pulse checks run constantly at zero cost
Pulse (60s intervals, pure Python):
├─ Check disk space $0
├─ Check log errors $0
├─ Check stale tasks $0
├─ Check server health $0
└─ ... (add infinite checks, still $0)
# Brain only invoked when needed
Brain (Agent/SDK):
├─ Condition: disk > 90% → $0.01 (only if triggered)
├─ Condition: errors found → $0.01 (only if triggered)
├─ Scheduled: 8:00 AM briefing → $0.01 (once per day)
└─ Scheduled: 6:00 PM summary → $0.01 (once per day)
2. Smarter Than TaskScheduler
TaskScheduler always invokes the agent, even if there's nothing to report:
# ❌ TaskScheduler: Always uses agent
- 08:00 Weather report → Agent ($0.01) even if no change
- 12:00 Midday standup → Agent ($0.01) even if no updates
- 18:00 Evening summary → Agent ($0.01) even if nothing happened
# ✅ Pulse & Brain: Conditional intelligence
- Pulse checks for changes → Python ($0)
- Brain only if updates → Agent ($0.01) only when needed
3. More Flexible Than Old Heartbeat
Old Heartbeat was simple but wasteful:
# ❌ Old Heartbeat: Every 30 minutes, always uses agent
while True:
agent.chat("Check everything") # ~$0.01
time.sleep(1800) # 48 calls/day = $0.48/day
# ✅ Pulse & Brain: Smart triggers
while True:
# 1,440 pulse checks/day (pure Python) = $0
# Only 4 brain calls/day (when needed) = $0.04/day
Decision Tree: Which System to Use?
Start here:
↓
Do you need real-time monitoring? (disk, logs, health checks)
├─ YES → Use Pulse & Brain ⭐
└─ NO → Go to next question
↓
Do you need scheduled content? (weather, summaries, reports)
├─ YES → Use TaskScheduler
└─ NO → Go to next question
↓
Do you need simple periodic checks?
└─ YES → Migrate from old Heartbeat to Pulse & Brain
Most users should: Use Pulse & Brain (+ optionally TaskScheduler for content)
Hybrid Approach (Best of Both)
For maximum efficiency:
# Pulse & Brain handles:
# - Health monitoring (disk, logs, tasks)
# - Morning briefing with system status
# - Evening summary
# - Error alerts
pb = PulseBrain(agent, pulse_interval=60)
pb.start()
# TaskScheduler handles ONLY:
# - Weekly newsletter (Friday 5pm)
# - Monthly metrics report (1st of month)
# - Custom scheduled content (unique reports)
scheduler = TaskScheduler(agent)
scheduler.tasks = [weekly_newsletter, monthly_report]
scheduler.start()
Cost: ~$2-3/month (vs $15/month with old heartbeat) 💰
Real-World Cost Examples
| Use Case | System | Monthly Cost |
|---|---|---|
| Homelab monitoring | Pulse & Brain only | ~$1-2 |
| Dev team bot | Pulse & Brain + TaskScheduler | ~$4-6 |
| Solo developer | Pulse & Brain only | ~$0.50-1 |
| Content bot | TaskScheduler only | ~$4-8 |
| Old heartbeat | ⚠️ Legacy system | ~$15 |
Migration Guide
From Old Heartbeat → Pulse & Brain
# Old (heartbeat.py) ❌
agent = Agent(enable_heartbeat=True)
# New (pulse_brain.py) ✅
agent = Agent(enable_heartbeat=False)
pb = PulseBrain(agent)
pb.start()
Benefit: 92% cost reduction
From TaskScheduler → Pulse & Brain
If your "scheduled tasks" are really monitoring checks:
# Old (scheduled_tasks.yaml) ❌
- name: health-check
schedule: "hourly"
prompt: "Check system health"
# New (pulse_brain.py) ✅
def check_health(): # Pure Python, zero cost
return {"status": "ok", "message": "Healthy"}
PulseCheck("health", check_health, interval_seconds=3600)
Benefit: 96% cost reduction
Why Not Just Use TaskScheduler?
TaskScheduler is great for content generation, but wasteful for monitoring:
# Example: Check disk space every hour with TaskScheduler
# Cost: 24 calls/day × 30 days = 720 calls/month = ~$7/month
# Same with Pulse & Brain:
# Pulse checks: Unlimited ($0)
# Brain only if disk > 90%: ~2 calls/month = ~$0.02/month
# Savings: $6.98/month (99.7% reduction)
Why Not Just Use Old Heartbeat?
Old Heartbeat was the original system, but it's:
- Expensive: Uses agent for every check
- Inflexible: Only interval-based, no conditionals
- Limited: No messaging platform integration
- Deprecated: Disabled by default, legacy code
Pulse & Brain replaces it entirely with 92% cost savings.
🎯 When to Use What
| System | Best For | Cost |
|---|---|---|
| Pulse & Brain | Production monitoring | ~$1-2/month |
| TaskScheduler | Scheduled content | ~$3-5/month |
| Old Heartbeat | ⚠️ Legacy (don't use) | ~$15/month |
Recommended Stack
For maximum efficiency:
# Pulse & Brain for monitoring (cheapest)
pb = PulseBrain(agent, pulse_interval=60)
pb.start()
# TaskScheduler for scheduled content only
scheduler = TaskScheduler(agent)
# Only enable specific scheduled tasks
scheduler.start()
📊 Monitoring Your Costs
pb = PulseBrain(agent)
pb.start()
# After running for a while
status = pb.get_status()
print(f"Brain invoked {status['brain_invocations']} times")
# Estimate cost
tokens_per_invocation = 1000 # Average
total_tokens = status['brain_invocations'] * tokens_per_invocation
cost = total_tokens * 0.000003 # Claude Sonnet pricing
print(f"Estimated cost: ${cost:.4f}")
💰 Cost Optimization Tips
-
Increase pulse interval if checks don't need to be frequent
pb = PulseBrain(agent, pulse_interval=300) # Every 5 min instead of 60s -
Use conditional brain tasks instead of scheduled
# ❌ Expensive: Always runs BrainTask(schedule="daily 08:00", ...) # ✅ Cheap: Only if there's news BrainTask(condition=lambda: has_updates(), ...) -
Batch briefings instead of multiple schedules
# ❌ Expensive: 3 calls/day - morning-briefing (08:00) - midday-update (12:00) - evening-summary (18:00) # ✅ Cheaper: 2 calls/day - morning-briefing (08:00) - evening-summary (18:00) -
Make pulse checks do more before invoking brain
# Pulse checks can filter, aggregate, and pre-process # Brain only gets invoked with actionable data
🚀 Getting Started
- Edit
config/pulse_brain_config.pywith your checks - Test your pulse checks (they should return
{"status": "ok|warn|error"}) - Configure brain tasks (conditional or scheduled)
- Run
python -m pulse_brain - Monitor brain invocation count
🔥 Pro Tips
- Make pulse checks fast (<1 second each)
- Use conditional brain tasks for errors/warnings
- Use scheduled brain tasks for daily summaries
- Test pulse checks without brain first
- Monitor brain invocations to track costs
⚠️ Legacy System Notice
Old Heartbeat (Deprecated)
The original Heartbeat system is now disabled by default. It has been superseded by Pulse & Brain.
Why it's deprecated:
- Uses agent for every check (expensive)
- No conditional logic (always runs)
- No messaging platform integration
- Replaced entirely by Pulse & Brain
If you're still using it:
# Old (don't use) ❌
agent = Agent(enable_heartbeat=True)
# New (migrate to this) ✅
agent = Agent(enable_heartbeat=False)
pb = PulseBrain(agent)
pb.start()
Migration benefits:
- 92% cost reduction
- Conditional intelligence
- Messaging platform support
- More flexible scheduling
🎉 Summary
Pulse & Brain is the most cost-effective way to run a proactive agent:
✅ Pulse runs constantly - Zero cost ✅ Brain only when needed - Pay for value ✅ 92% cost savings vs always-on agent ✅ Smart monitoring - Python checks + Agent analysis ✅ Scalable - Add more checks without increasing cost
Perfect for:
- Homelab monitoring
- Server health checks
- Log analysis
- Resource management
- Scheduled briefings
Result: An agent that's always watching but only speaks when it has something important to say. 🫀🧠