mirror of
https://github.com/galoryber/daedalus
synced 2026-06-21 13:51:16 +00:00
813a6a185e
A framework for running Claude Code as a fully autonomous agent via cron, with persistent memory, task management, and session handoff. Core features: - Checkpoint-based session handoff (save game system) - File-based state: tasks, worklog, questions, lessons-learned - Full autonomy with human-in-the-loop via questions + Pushover - PID management with stale session detection - 11-step autonomous workflow prompt - Customizable for any project via CLAUDE.md + ADAPTING.md guide Named for the myth: Daedalus, the master craftsman who built autonomous machines that worked tirelessly without supervision.
92 lines
4.2 KiB
Bash
Executable File
92 lines
4.2 KiB
Bash
Executable File
#!/bin/bash
|
|
# Main cron wrapper — runs the daily prompt against Claude Code
|
|
set -uo pipefail
|
|
|
|
# ─── Environment ──────────────────────────────────────────────────────────────
|
|
# Cron doesn't source /etc/environment (PAM does that for interactive logins).
|
|
# Source it explicitly so env vars (notifications, API tokens, etc.) are available.
|
|
if [ -f /etc/environment ]; then
|
|
set -a
|
|
source /etc/environment
|
|
set +a
|
|
fi
|
|
|
|
# Ensure locally-installed tools (like claude) are on PATH
|
|
export PATH="$HOME/.local/bin:$PATH"
|
|
|
|
# ─── Config ───────────────────────────────────────────────────────────────────
|
|
# IMPORTANT: Update PROJECT_DIR to the absolute path of your Daedalus installation
|
|
PROJECT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
|
PROMPT_FILE="$PROJECT_DIR/prompts/daily.md"
|
|
LOG_DIR="$PROJECT_DIR/logs"
|
|
LOG_FILE="$LOG_DIR/daily-$(date +%Y%m%d-%H%M%S).log"
|
|
MAX_TURNS="${MAX_TURNS:-200}" # Safety limit on agentic loops
|
|
PID_FILE="$PROJECT_DIR/.claude/cron.pid"
|
|
CHECKPOINT_FILE="$PROJECT_DIR/.claude/checkpoint.md"
|
|
|
|
# Maximum age (in minutes) of the checkpoint before we consider the session stale.
|
|
# If the checkpoint was updated within this window, the session is likely still working.
|
|
STALE_THRESHOLD_MINUTES="${STALE_THRESHOLD_MINUTES:-30}"
|
|
|
|
# ─── Previous Session Cleanup ────────────────────────────────────────────────
|
|
if [ -f "$PID_FILE" ]; then
|
|
OLD_PID=$(cat "$PID_FILE")
|
|
if kill -0 "$OLD_PID" 2>/dev/null; then
|
|
# Process is still alive — check if it's actually working
|
|
# by looking at how recently the checkpoint was updated
|
|
SESSION_ACTIVE=false
|
|
if [ -f "$CHECKPOINT_FILE" ]; then
|
|
CHECKPOINT_AGE=$(( ( $(date +%s) - $(stat -c %Y "$CHECKPOINT_FILE") ) / 60 ))
|
|
if [ "$CHECKPOINT_AGE" -lt "$STALE_THRESHOLD_MINUTES" ]; then
|
|
SESSION_ACTIVE=true
|
|
fi
|
|
fi
|
|
|
|
if [ "$SESSION_ACTIVE" = true ]; then
|
|
echo "[$(date)] Previous session (PID $OLD_PID) is still active (checkpoint updated ${CHECKPOINT_AGE}m ago). Skipping this run." >> "$LOG_DIR/cron-skip.log"
|
|
exit 0
|
|
else
|
|
echo "[$(date)] Previous session (PID $OLD_PID) appears stale. Killing." >> "$LOG_DIR/cron-cleanup.log"
|
|
kill "$OLD_PID" 2>/dev/null || true
|
|
sleep 5
|
|
# Force kill if still alive
|
|
if kill -0 "$OLD_PID" 2>/dev/null; then
|
|
kill -9 "$OLD_PID" 2>/dev/null || true
|
|
sleep 2
|
|
fi
|
|
fi
|
|
fi
|
|
rm -f "$PID_FILE"
|
|
fi
|
|
|
|
# ─── Setup ────────────────────────────────────────────────────────────────────
|
|
mkdir -p "$LOG_DIR"
|
|
cd "$PROJECT_DIR"
|
|
|
|
echo "=============================================" >> "$LOG_FILE"
|
|
echo "Daedalus Autonomous Session" >> "$LOG_FILE"
|
|
echo "Started: $(date)" >> "$LOG_FILE"
|
|
echo "Prompt: $PROMPT_FILE" >> "$LOG_FILE"
|
|
echo "Max turns: $MAX_TURNS" >> "$LOG_FILE"
|
|
echo "=============================================" >> "$LOG_FILE"
|
|
|
|
# ─── Run ──────────────────────────────────────────────────────────────────────
|
|
claude -p "$(cat "$PROMPT_FILE")" \
|
|
--dangerously-skip-permissions \
|
|
--max-turns "$MAX_TURNS" \
|
|
--output-format text \
|
|
>> "$LOG_FILE" 2>&1 &
|
|
|
|
CLAUDE_PID=$!
|
|
echo "$CLAUDE_PID" > "$PID_FILE"
|
|
wait "$CLAUDE_PID" && EXIT_CODE=0 || EXIT_CODE=$?
|
|
|
|
rm -f "$PID_FILE"
|
|
|
|
echo "=============================================" >> "$LOG_FILE"
|
|
echo "Finished: $(date)" >> "$LOG_FILE"
|
|
echo "Exit code: $EXIT_CODE" >> "$LOG_FILE"
|
|
echo "=============================================" >> "$LOG_FILE"
|
|
|
|
exit $EXIT_CODE
|