Set up or manage a heartbeat for autonomous Claude Code task processing.
Also apply hierarchical_memory and obsidian for reading context and persisting results.
Setup
Recommended: make install-heartbeat handles steps 1-3 automatically.
1. Create the task file
Tasks live in the obsidian vault at $CLAUDE_OBSIDIAN_DIR/heartbeat/tasks.md:
mkdir -p $CLAUDE_OBSIDIAN_DIR/heartbeat cat > $CLAUDE_OBSIDIAN_DIR/heartbeat/tasks.md << 'EOF' # Heartbeat Tasks Tasks for Claude to process on each heartbeat cycle. Before processing, read today's memory notes and decide the highest-value activity. ## Pending - [ ] Example: Check for new GitHub issues in myrepo ## Completed EOF
2. Set up auth for cron
Cron doesn't source ~/.zshrc, so API keys aren't available. Create a dedicated env file:
echo 'export ANTHROPIC_API_KEY=sk-ant-...' > ~/.claude/heartbeat.env chmod 600 ~/.claude/heartbeat.env
The heartbeat script sources this file automatically on startup.
3. Add a cron entry
# Install (idempotent — removes old entry first, then adds)
(crontab -l 2>/dev/null || true) | sed '/CLAUDE_HEARTBEAT/d' | { cat; echo "0 */4 * * * SKILL_DIR/scripts/heartbeat.sh >> $HOME/claude/obsidian/heartbeat/heartbeat.log 2>&1 # CLAUDE_HEARTBEAT"; } | crontab -
The # CLAUDE_HEARTBEAT marker is a shell comment (harmless at runtime) that lets pause/stop/resume target only this entry.
Verify with crontab -l.
Heartbeat Behavior
On each cycle, the heartbeat agent should:
- •Read hierarchical memory (
read-current) and obsidian vault for full context - •Read the task queue for pending items
- •Decide: is there a high-value task, or should it save its powder and wait?
- •If it has a question for the user, write it to
$CLAUDE_OBSIDIAN_DIR/heartbeat/questions.md - •Process at most ONE task per cycle
- •Update hierarchical memory with what was done
- •Commit to the obsidian repo
Task Queue
Edit $CLAUDE_OBSIDIAN_DIR/heartbeat/tasks.md — add tasks as - [ ] description under Pending, completed tasks get marked - [x] timestamp: description and moved to Completed.
Managing
All commands use sed (not grep -v) to avoid exit code 1 on empty output breaking pipelines.
- •Check log:
tail -20 $CLAUDE_OBSIDIAN_DIR/heartbeat/heartbeat.log - •Pause:
(crontab -l 2>/dev/null || true) | sed '/CLAUDE_HEARTBEAT/ { /^[[:space:]]*#/! s/^/# / }' | crontab - - •Resume:
(crontab -l 2>/dev/null || true) | sed '/CLAUDE_HEARTBEAT/ s/^[[:space:]]*# *//' | crontab - - •Stop:
(crontab -l 2>/dev/null || true) | sed '/CLAUDE_HEARTBEAT/d' | crontab -