#!/usr/bin/env bash # Exult Agent Performance Monitor # Run periodically (e.g., cron every 30 min) or manually # Reports: response times, error rates, compaction frequency, task completion set -uo pipefail WORKSPACE="/Users/exult/claude-workspace" TODAY=$(date +%Y-%m-%d) DAILY_DIR="$WORKSPACE/sessions/daily/$TODAY" REPORT_FILE="$DAILY_DIR/performance-report.md" mkdir -p "$DAILY_DIR" # Audit log stats AUDIT_FILE="$DAILY_DIR/audit.log" if [[ -f "$AUDIT_FILE" ]]; then TOTAL_ACTIONS=$(wc -l < "$AUDIT_FILE" | tr -d ' ') BASH_ACTIONS=$(grep -c "\[Bash\]" "$AUDIT_FILE" 2>/dev/null || echo 0) PLAYWRIGHT_ACTIONS=$(grep -c "\[mcp__playwright" "$AUDIT_FILE" 2>/dev/null || echo 0) SENDBLUE_REPLIES=$(grep -c "\[mcp__sendblue-channel__reply\]" "$AUDIT_FILE" 2>/dev/null || echo 0) ERRORS=$(grep -ci "error\|fail\|exception" "$AUDIT_FILE" 2>/dev/null || echo 0) else TOTAL_ACTIONS=0; BASH_ACTIONS=0; PLAYWRIGHT_ACTIONS=0; SENDBLUE_REPLIES=0; ERRORS=0 fi # Archive (compaction) count ARCHIVE_COUNT=$(ls -1 "$DAILY_DIR/archive/" 2>/dev/null | wc -l | tr -d ' ') # Subagent count SUBAGENT_COUNT=$(ls -1 "$DAILY_DIR/subagents/" 2>/dev/null | wc -l | tr -d ' ') # Message response analysis MSG_FILE="$DAILY_DIR/messages.json" if [[ -f "$MSG_FILE" ]] && python3 -c "import json; json.load(open('$MSG_FILE'))" 2>/dev/null; then MSG_STATS=$(python3 -c " import json with open('$MSG_FILE') as f: msgs = json.load(f) inbound = [m for m in msgs if not m.get('isOutbound')] outbound = [m for m in msgs if m.get('isOutbound')] print(f'Inbound: {len(inbound)}, Outbound: {len(outbound)}') " 2>/dev/null || echo "Parse error") else MSG_STATS="No valid messages.json" fi # HANDOFF freshness HANDOFF="$WORKSPACE/sessions/HANDOFF/HANDOFF.md" if [[ -f "$HANDOFF" ]]; then HANDOFF_AGE=$(( $(date +%s) - $(stat -f %m "$HANDOFF" 2>/dev/null || echo 0) )) HANDOFF_STATUS="exists (${HANDOFF_AGE}s old)" else HANDOFF_STATUS="MISSING" fi # Summary freshness SUMMARY="$DAILY_DIR/summary.md" if [[ -f "$SUMMARY" ]]; then SUMMARY_STATUS="exists" else SUMMARY_STATUS="MISSING" fi # Write report cat > "$REPORT_FILE" << EOF # Exult Agent Performance Report Generated: $(date -u +%Y-%m-%dT%H:%M:%SZ) Date: $TODAY ## Activity - Total tool actions: $TOTAL_ACTIONS - Bash commands: $BASH_ACTIONS - Playwright actions: $PLAYWRIGHT_ACTIONS - Sendblue replies: $SENDBLUE_REPLIES - Errors detected: $ERRORS - Compaction cycles: $ARCHIVE_COUNT - Subagents spawned: $SUBAGENT_COUNT ## Messages $MSG_STATS ## Session Persistence - HANDOFF.md: $HANDOFF_STATUS - Daily summary: $SUMMARY_STATUS ## Issues EOF # Flag issues ISSUES=0 if [[ "$HANDOFF_STATUS" == "MISSING" ]]; then echo "- HANDOFF.md is missing -- session persistence broken" >> "$REPORT_FILE" ISSUES=$((ISSUES+1)) fi if [[ "$SUMMARY_STATUS" == "MISSING" && $TOTAL_ACTIONS -gt 100 ]]; then echo "- Daily summary missing despite $TOTAL_ACTIONS actions" >> "$REPORT_FILE" ISSUES=$((ISSUES+1)) fi if [[ $ERRORS -gt 50 ]]; then echo "- High error rate: $ERRORS errors in audit log" >> "$REPORT_FILE" ISSUES=$((ISSUES+1)) fi if [[ $ARCHIVE_COUNT -gt 20 ]]; then echo "- Excessive compaction ($ARCHIVE_COUNT cycles) -- context may be too large" >> "$REPORT_FILE" ISSUES=$((ISSUES+1)) fi if [[ $ISSUES -eq 0 ]]; then echo "None detected." >> "$REPORT_FILE" fi echo "$REPORT_FILE"