Chapter 4: Implementation - Step-by-Step Build
Build the automation pipeline in 30 minutes with detailed instructions
Let's build the automation pipeline. I'll show you exactly what I do, with every command explained.
Step 1: Create the Utility Functions (10 minutes)
First, we create a library of reusable functions.
Create wake-utils.sh:
cd ~/automation-projects/claude-pipeline/scripts
cat > wake-utils.sh << 'EOF'
#!/bin/bash
# wake-utils.sh - Utility functions for wake automation
# Logging function
log_message() {
local message="$1"
local log_file="${LOG_FILE:-$HOME/automation-projects/claude-pipeline/logs/automation.log}"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $message" | tee -a "$log_file"
}
# Calculate next occurrence of target hour
calculate_next_wake() {
local target_hour="$1" # e.g., 18 for 6pm
local current_hour=$(date +%H)
local current_date=$(date +%Y-%m-%d)
# If target hour hasn't passed today, use today
if [ "$current_hour" -lt "$target_hour" ]; then
echo "${current_date} ${target_hour}:00:00"
else
# Otherwise use tomorrow
echo "$(date -v+1d +%Y-%m-%d) ${target_hour}:00:00"
fi
}
# Check current pmset schedule
get_current_schedule() {
pmset -g sched 2>/dev/null || echo "No schedules found"
}
# Cancel all pmset schedules
cancel_all_schedules() {
log_message "Canceling all pmset schedules..."
sudo pmset schedule cancelall 2>/dev/null
log_message "All schedules canceled"
}
# Get running caffeinate processes
get_caffeinate_processes() {
ps aux | grep caffeinate | grep -v grep
}
# Stop all caffeinate processes
stop_all_caffeinate() {
log_message "Stopping all caffeinate processes..."
pkill -f caffeinate
log_message "Caffeinate processes stopped"
}
# Show system status
show_system_status() {
echo "=== System Status ==="
echo ""
echo "Current Time: $(date)"
echo ""
echo "Scheduled Wakes:"
get_current_schedule
echo ""
echo "Running Caffeinate:"
get_caffeinate_processes || echo "None"
echo ""
echo "LaunchAgent Status:"
launchctl list | grep claude-automation || echo "Not loaded"
echo ""
}
# Export functions for use in other scripts
export -f log_message
export -f calculate_next_wake
export -f get_current_schedule
export -f cancel_all_schedules
export -f get_caffeinate_processes
export -f stop_all_caffeinate
export -f show_system_status
EOF
chmod +x wake-utils.shWhat this does: Creates reusable functions for logging, scheduling, and system control. Exports functions so other scripts can use them. Provides debugging utilities (show_system_status).
Test it:
source wake-utils.sh
show_system_statusYou should see current system status with scheduled wakes, running processes, and LaunchAgent status.
Step 2: Build the Wake Handler (10 minutes)
This script runs when the system wakes and orchestrates the automation.
Create automation-handler.sh:
cd ~/automation-projects/claude-pipeline/scripts
cat > automation-handler.sh << 'EOF'
#!/bin/bash
# automation-handler.sh - Handles wake events and runs automation tasks
# Setup
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
export LOG_FILE="$HOME/automation-projects/claude-pipeline/logs/automation.log"
# Source utilities
source "$SCRIPT_DIR/wake-utils.sh"
# Detect current time and determine action
detect_wake_time() {
local hour=$(date +%H)
local minute=$(date +%M)
# 6pm wake (18:00)
if [ "$hour" -eq 18 ] && [ "$minute" -lt 10 ]; then
echo "6pm"
# 7pm wake (19:00)
elif [ "$hour" -eq 19 ] && [ "$minute" -lt 10 ]; then
echo "7pm"
else
echo "unknown"
fi
}
# Calculate caffeinate duration
calculate_caffeinate_duration() {
local wake_time="$1"
case "$wake_time" in
"6pm")
echo 1800 # 30 minutes
;;
"7pm")
echo 300 # 5 minutes
;;
*)
echo 60 # 1 minute default
;;
esac
}
# Run caffeinate with logging
run_caffeinate() {
local duration="$1"
local wake_time="$2"
log_message "[$wake_time wake] Starting caffeinate for $duration seconds"
# Run caffeinate in background
caffeinate -t "$duration" &
local caffeinate_pid=$!
log_message "[$wake_time wake] Caffeinate running (PID: $caffeinate_pid)"
# Wait for caffeinate to complete
wait $caffeinate_pid
log_message "[$wake_time wake] Caffeinate completed"
}
# Schedule next wake
schedule_next_wake() {
local next_hour="$1"
local next_time=$(calculate_next_wake "$next_hour")
log_message "Scheduling next wake: $next_time"
sudo pmset schedule wake "$next_time" 2>&1 | tee -a "$LOG_FILE"
}
# Main execution flow
main() {
log_message "=== Automation Handler Started ==="
# Detect wake time
local wake_time=$(detect_wake_time)
log_message "Detected wake time: $wake_time"
case "$wake_time" in
"6pm")
# Schedule 7pm wake immediately
schedule_next_wake 19
# Run 30-minute caffeinate
local duration=$(calculate_caffeinate_duration "6pm")
run_caffeinate "$duration" "6pm"
# Add your 6pm automation tasks here
log_message "[6pm wake] Running automation tasks..."
# Example: Run a backup script
# /path/to/backup-script.sh
log_message "[6pm wake] Automation complete"
;;
"7pm")
# Run 5-minute caffeinate
local duration=$(calculate_caffeinate_duration "7pm")
run_caffeinate "$duration" "7pm"
# Add your 7pm automation tasks here
log_message "[7pm wake] Running automation tasks..."
# Example: Run a data processing script
# /path/to/process-data.sh
log_message "[7pm wake] Automation complete"
;;
*)
log_message "Unknown wake time - no action taken"
;;
esac
log_message "=== Automation Handler Finished ==="
}
# Handle command line arguments
case "${1:-}" in
test-6pm)
log_message "=== TESTING 6PM SEQUENCE ==="
schedule_next_wake 19
run_caffeinate 10 "6pm-test" # 10 seconds for testing
;;
test-7pm)
log_message "=== TESTING 7PM SEQUENCE ==="
run_caffeinate 10 "7pm-test" # 10 seconds for testing
;;
*)
main
;;
esac
EOF
chmod +x automation-handler.shWhat this does: Detects whether it's a 6pm or 7pm wake, schedules the next wake in the sequence, runs caffeinate to keep system awake, provides hooks for your automation tasks, and includes test modes for debugging.
Test it:
# Test 6pm sequence (won't actually schedule, just logs)
./automation-handler.sh test-6pm
# Check the log
tail -20 ~/automation-projects/claude-pipeline/logs/automation.logStep 3: Create the Main Setup Script (5 minutes)
This script sets up the entire system.
Create setup-automation.sh:
cd ~/automation-projects/claude-pipeline/scripts
cat > setup-automation.sh << 'EOF'
#!/bin/bash
# setup-automation.sh - Setup and control the automation pipeline
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PLIST_DIR="$HOME/automation-projects/claude-pipeline/launchagents"
PLIST_FILE="$PLIST_DIR/com.user.claude-automation.plist"
export LOG_FILE="$HOME/automation-projects/claude-pipeline/logs/automation.log"
source "$SCRIPT_DIR/wake-utils.sh"
# Create LaunchAgent plist
create_launch_agent() {
log_message "Creating LaunchAgent plist..."
cat > "$PLIST_FILE" << PLIST
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.user.claude-automation</string>
<key>ProgramArguments</key>
<array>
<string>$SCRIPT_DIR/automation-handler.sh</string>
</array>
<key>StartCalendarInterval</key>
<array>
<dict>
<key>Hour</key>
<integer>18</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
<dict>
<key>Hour</key>
<integer>19</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
</array>
<key>StandardOutPath</key>
<string>/tmp/claude-automation.out</string>
<key>StandardErrorPath</key>
<string>/tmp/claude-automation.err</string>
<key>RunAtLoad</key>
<false/>
</dict>
</plist>
PLIST
log_message "LaunchAgent plist created: $PLIST_FILE"
}
# Install LaunchAgent
install_launch_agent() {
log_message "Installing LaunchAgent..."
# Copy to system LaunchAgents directory
cp "$PLIST_FILE" ~/Library/LaunchAgents/
# Load the agent
launchctl unload ~/Library/LaunchAgents/com.user.claude-automation.plist 2>/dev/null
launchctl load ~/Library/LaunchAgents/com.user.claude-automation.plist
log_message "LaunchAgent installed and loaded"
}
# Setup initial wake schedule
setup_initial_wake() {
log_message "Setting up initial wake schedule..."
local next_6pm=$(calculate_next_wake 18)
log_message "Scheduling first wake: $next_6pm"
sudo pmset schedule wake "$next_6pm" 2>&1 | tee -a "$LOG_FILE"
log_message "Initial wake scheduled"
}
# Main setup
setup() {
log_message "=== Starting Claude Automation Setup ==="
# Create plist
create_launch_agent
# Install LaunchAgent
install_launch_agent
# Schedule initial wake
setup_initial_wake
log_message "=== Setup Complete ==="
log_message ""
log_message "Next steps:"
log_message "1. System will wake at 6pm"
log_message "2. Caffeinate will run for 30 minutes"
log_message "3. System will wake again at 7pm"
log_message ""
log_message "To check status: $0 status"
log_message "To cancel all: $0 cancel"
}
# Show status
status() {
show_system_status
echo "Recent logs:"
tail -15 "$LOG_FILE"
}
# Cancel everything
cancel() {
log_message "=== Canceling all automation ==="
# Unload LaunchAgent
launchctl unload ~/Library/LaunchAgents/com.user.claude-automation.plist 2>/dev/null
# Cancel schedules
cancel_all_schedules
# Stop caffeinate
stop_all_caffeinate
log_message "=== All automation canceled ==="
}
# Command line interface
case "${1:-}" in
status)
status
;;
cancel)
cancel
;;
*)
setup
;;
esac
EOF
chmod +x setup-automation.shWhat this does: Creates and installs the LaunchAgent, schedules the initial 6pm wake, provides status and cancel commands, and ties everything together.
Step 4: Run the Setup (5 minutes)
Now we bring it all together.
Execute setup:
cd ~/automation-projects/claude-pipeline/scripts
./setup-automation.shYou'll be prompted for your password (for sudo pmset). Enter it.
Expected output:
[2025-10-03 14:45:23] === Starting Claude Automation Setup ===
[2025-10-03 14:45:23] Creating LaunchAgent plist...
[2025-10-03 14:45:23] LaunchAgent plist created: /Users/you/automation-projects/claude-pipeline/launchagents/com.user.claude-automation.plist
[2025-10-03 14:45:23] Installing LaunchAgent...
[2025-10-03 14:45:24] LaunchAgent installed and loaded
[2025-10-03 14:45:24] Setting up initial wake schedule...
[2025-10-03 14:45:24] Scheduling first wake: 2025-10-03 18:00:00
[2025-10-03 14:45:25] Initial wake scheduled
[2025-10-03 14:45:25] === Setup Complete ===Verify installation:
./setup-automation.sh statusYou should see:
- Scheduled wake at 6pm today (or tomorrow if it's after 6pm)
- LaunchAgent loaded
- Recent log entries
Test the automation (without waiting for 6pm):
./automation-handler.sh test-6pmCheck the logs:
tail -30 ~/automation-projects/claude-pipeline/logs/automation.logYou should see:
- Handler started
- 7pm wake scheduled
- Caffeinate running for 10 seconds (test mode)
- Caffeinate completed
- Handler finished
Congratulations! You've built a complete automation pipeline in 30 minutes.