6 error spans on 0 routes in the last 7 days.
#!/usr/bin/env bash
# Sherlock — invoke the Cedar debugging agent from the command line.
#
# Usage:
# ./scripts/sherlock.sh "<email> is getting wrong signatures on drafts"
# ./scripts/sherlock.sh --execution exec_abc123 "why did this fail?"
# ./scripts/sherlock.sh --user <email> --notify "#cedar-bugs" "no draft sent"
# ./scripts/sherlock.sh --outstanding (process all pending_investigation monitors)
# ./scripts/sherlock.sh --self-improve (headless gap-detection loop)
#
# Requires: claude CLI (Claude Code), psql (for --outstanding)
set -euo pipefail
REPO_ROOT="$(git rev-parse --show-toplevel)"
SKILL_DIR="$REPO_ROOT/apps/server/.claude/skills/sherlock"
# --- parse flags ---
USER_EMAIL=""
EXECUTION_ID=""
NOTIFY_CHANNEL=""
SELF_IMPROVE=false
OUTSTANDING=false
BUG_REPORT=""
while [[ $# -gt 0 ]]; do
case "$1" in
--user) USER_EMAIL="$2"; shift 2 ;;
--execution) EXECUTION_ID="$2"; shift 2 ;;
--notify) NOTIFY_CHANNEL="$2"; shift 2 ;;
--self-improve) SELF_IMPROVE=true; shift ;;
--outstanding) OUTSTANDING=true; shift ;;
*) BUG_REPORT="${BUG_REPORT:+$BUG_REPORT }$1"; shift ;;
esac
done
# --- check for claude CLI ---
if ! command -v claude &>/dev/null; then
echo "Error: 'claude' CLI not found. Install Claude Code to use Sherlock."
exit 1
fi
SYSTEM_PROMPT="$(cat "$SKILL_DIR/SKILL.md" "$SKILL_DIR/SHERLOCK_SYSTEM_KNOWLEDGE.md" "$SKILL_DIR/report-template.md")"
# ============================================================
# --outstanding: process all pending_investigation monitors
# ============================================================
if [[ "$OUTSTANDING" == "true" ]]; then
if [[ -z "${DATABASE_URL:-}" ]]; then
# Try to load from .env
if [[ -f "$REPO_ROOT/.env" ]]; then
DATABASE_URL="$(grep '^DATABASE_URL=' "$REPO_ROOT/.env" | cut -d= -f2-)"
fi
fi
if [[ -z "${DATABASE_URL:-}" ]]; then
echo "Error: DATABASE_URL not set. Set it in your environment or .env file."
exit 1
fi
echo ""
echo "🔍 Sherlock — processing outstanding monitors..."
echo ""
# Fetch all pending_investigation monitors
MONITORS=$(psql "$DATABASE_URL" -t -A -F'|' -c "
SELECT
sm.id,
sm.user_id,
u.email,
sm.trigger_config->>'verify_condition' AS verify_condition,
ae.run_id AS latest_execution_id
FROM sherlock_monitors sm
LEFT JOIN users u ON sm.user_id = u.id
LEFT JOIN LATERAL (
SELECT run_id FROM agent_executions
WHERE user_id = sm.user_id AND status = 'completed'
ORDER BY created_at DESC LIMIT 1
) ae ON true
WHERE sm.status = 'pending_investigation'
ORDER BY sm.id;
" 2>/dev/null || true)
if [[ -z "$MONITORS" ]]; then
echo "No pending monitors to investigate."
exit 0
fi
TOTAL=0
INVESTIGATED=0
FAILED=0
while IFS='|' read -r MONITOR_ID USER_ID USER_EMAIL_ROW VERIFY_CONDITION LATEST_EXEC_ID; do
[[ -z "$MONITOR_ID" ]] && continue
TOTAL=$((TOTAL + 1))
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Monitor: $MONITOR_ID"
echo "User: ${USER_EMAIL_ROW:-$USER_ID}"
echo "Exec: ${LATEST_EXEC_ID:-(none found)}"
echo ""
PROMPT="Investigating outstanding monitor $MONITOR_ID.
User: ${USER_EMAIL_ROW:-$USER_ID}
${LATEST_EXEC_ID:+Latest execution ID: $LATEST_EXEC_ID}
Condition to verify:
${VERIFY_CONDITION:-(no condition stored)}
This monitor was flagged by the Haiku evaluator as a failure or uncertain. Run a full investigation using the standard Sherlock workflow. After completing:
- If the problem is confirmed: apply the fix (config change directly, code fix via git worktree + PR) and set monitor status to 'failed'
- If the problem is resolved / was a false positive: set monitor status back to 'active'
Update sherlock_monitors SET status = 'active' or 'failed' accordingly via psql when done."
cd "$REPO_ROOT"
if claude --print --system-prompt "$SYSTEM_PROMPT" "$PROMPT"; then
INVESTIGATED=$((INVESTIGATED + 1))
else
FAILED=$((FAILED + 1))
echo "⚠️ Investigation errored for monitor $MONITOR_ID"
fi
echo ""
done <<< "$MONITORS"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Summary: $TOTAL monitors, $INVESTIGATED investigated, $FAILED errored"
exit 0
fi
# ============================================================
# --self-improve mode
# ============================================================
if [[ "$SELF_IMPROVE" == "true" ]]; then
BUG_REPORT="Self-improve mode: scan for observability gaps in the codebase. Do not investigate a specific bug. Instead:
1. Check .stale-sections and refresh any stale knowledge sections
2. Scan recent sherlock_investigations where evidence_confidence = 'gap'
3. For each gap, verify whether the observability patch was committed
4. If not, add the missing createStructuredLog call and open a PR
5. Scan for symptom classes with investigation_count = 0 and propose new query_plan entries in sherlock_symptom_patterns"
fi
# ============================================================
# Standard one-off investigation
# ============================================================
if [[ -z "$BUG_REPORT" ]]; then
echo "Usage: ./scripts/sherlock.sh [--user email] [--execution id] [--notify channel] \"bug description\""
echo " ./scripts/sherlock.sh --outstanding"
echo " ./scripts/sherlock.sh --self-improve"
exit 1
fi
# --- build context lines ---
CONTEXT=""
[[ -n "$USER_EMAIL" ]] && CONTEXT="${CONTEXT}User: $USER_EMAIL\n"
[[ -n "$EXECUTION_ID" ]] && CONTEXT="${CONTEXT}Execution ID: $EXECUTION_ID\n"
[[ -n "$NOTIFY_CHANNEL" ]] && CONTEXT="${CONTEXT}Notify: $NOTIFY_CHANNEL\n"
PROMPT="$BUG_REPORT"
[[ -n "$CONTEXT" ]] && PROMPT="$PROMPT\n\n$(echo -e "$CONTEXT")"
echo ""
echo "🔍 Sherlock — investigating..."
echo ""
cd "$REPO_ROOT"
claude --print --system-prompt "$SYSTEM_PROMPT" "$PROMPT"