#!/bin/bash # Agent Factory — Docker container entrypoint # Validates environment, then runs the heartbeat runner in a loop. # Bash 3.2 compatible. set -e HEALTH_FILE="/tmp/agent-health" LOG_DIR="/home/agent/project/logs" HEARTBEAT_SCRIPT="/home/agent/project/automation/heartbeat-runner.sh" # Graceful shutdown handler shutdown_handler() { echo "[entrypoint] SIGTERM received — shutting down gracefully" if [ -n "$RUNNER_PID" ]; then kill "$RUNNER_PID" 2>/dev/null || true wait "$RUNNER_PID" 2>/dev/null || true fi rm -f "$HEALTH_FILE" echo "[entrypoint] Shutdown complete" exit 0 } trap shutdown_handler TERM INT # Validate required environment variables if [ -z "$ANTHROPIC_API_KEY" ]; then echo "[entrypoint] ERROR: ANTHROPIC_API_KEY is not set" >&2 exit 1 fi # Create required directories mkdir -p "$LOG_DIR" mkdir -p "/home/agent/project/data" mkdir -p "/home/agent/project/memory" mkdir -p "/home/agent/project/budget" mkdir -p "/home/agent/project/pipeline-output" echo "[entrypoint] Starting agent container at $(date)" echo "[entrypoint] Project: $(basename /home/agent/project)" # Verify Claude Code is available if ! command -v claude >/dev/null 2>&1; then echo "[entrypoint] ERROR: claude command not found" >&2 exit 1 fi # Run heartbeat runner in loop while true; do # Write health check timestamp date > "$HEALTH_FILE" if [ -f "$HEARTBEAT_SCRIPT" ]; then echo "[entrypoint] Running heartbeat at $(date)" bash "$HEARTBEAT_SCRIPT" >> "$LOG_DIR/agent.log" 2>&1 & RUNNER_PID=$! wait $RUNNER_PID RUNNER_PID="" else echo "[entrypoint] WARNING: $HEARTBEAT_SCRIPT not found — sleeping" fi # Sleep between beats (default 3600s = 1 hour) BEAT_INTERVAL="${AGENT_BEAT_INTERVAL:-3600}" echo "[entrypoint] Sleeping ${BEAT_INTERVAL}s until next beat" sleep "$BEAT_INTERVAL" & RUNNER_PID=$! wait $RUNNER_PID RUNNER_PID="" done