Skip to content

Instantly share code, notes, and snippets.

@vrde
Created March 27, 2026 07:10
Show Gist options
  • Select an option

  • Save vrde/dab8f9fc2b52df6d3a225e04b8f31f99 to your computer and use it in GitHub Desktop.

Select an option

Save vrde/dab8f9fc2b52df6d3a225e04b8f31f99 to your computer and use it in GitHub Desktop.
Claude Code Sycophancy Meter
#!/usr/bin/env python3
"""sycophancy-meter: how often does Claude say "you're right"?
Run from a machine with Claude Code conversation transcripts.
Outputs a histogram by day + day-of-week analysis, normalized by message count.
Usage: python3 sycophancy-meter.py [--exclude-today]
"""
import os
import re
import sys
from datetime import datetime, date
from pathlib import Path
from collections import defaultdict
PROJECTS_DIR = Path(os.environ.get("CLAUDE_PROJECTS_DIR", Path.home() / ".claude" / "projects"))
EXCLUDE_TODAY = "--exclude-today" in sys.argv
print(f"Scanning transcripts in {PROJECTS_DIR} ...")
right = defaultdict(int)
absolutely = defaultdict(int)
msgs = defaultdict(int)
today_str = date.today().isoformat()
for jsonl in PROJECTS_DIR.rglob("*.jsonl"):
for line in open(jsonl, errors="ignore"):
if '"role":"assistant"' not in line and '"role": "assistant"' not in line:
continue
m = re.search(r'"timestamp":\s*"(\d{4}-\d{2}-\d{2})', line)
if not m:
continue
d = m.group(1)
if EXCLUDE_TODAY and d == today_str:
continue
msgs[d] += 1
if re.search(r"you're right", line, re.IGNORECASE):
right[d] += 1
if re.search(r"you're absolutely right", line, re.IGNORECASE):
absolutely[d] += 1
dates = sorted(right.keys())
days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
if not dates:
print("No \"you're right\" found. Your AI is refreshingly honest.")
sys.exit(0)
max_rate = max(right[d] / msgs[d] * 1000 for d in dates)
scale = 40 / max_rate
print(f"\n{'Date':<12} {'Day':<4} {'#':>3} {'msgs':>5} {'rate':>6} per 1000 msgs")
print(f"{'':_<12} {'':_<4} {'':_>3} {'':_>5} {'':_>6} {'':_<40}")
for d in dates:
total = right[d]
ab = absolutely[d]
dt = datetime.strptime(d, "%Y-%m-%d")
day = days[dt.weekday()]
m = msgs[d]
rate = total / m * 1000
bar_len = round(rate * scale)
ab_len = round(ab / m * 1000 * scale)
n_len = max(bar_len - ab_len, 0)
print(f"{d:<12} {day:<4} {total:>3} {m:>5} {rate:>5.1f}‰ {'░' * n_len}{'█' * ab_len}")
# Day of week analysis
dow_right = defaultdict(int)
dow_msgs = defaultdict(int)
dow_abs = defaultdict(int)
for d in dates:
w = datetime.strptime(d, "%Y-%m-%d").weekday()
dow_right[w] += right[d]
dow_msgs[w] += msgs[d]
dow_abs[w] += absolutely[d]
active_days = sorted(dow_right.keys())
max_dow = max(dow_right[w] / dow_msgs[w] * 1000 for w in active_days)
ds = 30 / max_dow
print(f"\n{'Day':<4} {'right':>6} {'msgs':>6} {'rate':>6} per 1000 msgs")
print(f"{'':_<4} {'':_>6} {'':_>6} {'':_>6} {'':_<30}")
for w in range(7):
if w not in dow_right:
continue
r = dow_right[w]; m = dow_msgs[w]; a = dow_abs[w]
rate = r / m * 1000
bl = round(rate * ds); al = round(a / m * 1000 * ds)
print(f"{days[w]:<4} {r:>6} {m:>6} {rate:>5.1f}‰ {'░' * max(bl - al, 0)}{'█' * al}")
tr = sum(right.values()); ta = sum(absolutely.values())
tm = sum(msgs[d] for d in dates)
print(f"\n░░ you're right: {tr - ta}")
print(f"██ you're ABSOLUTELY right: {ta}")
print(f" total: {tr} across {tm} messages ({tr / tm * 1000:.1f}‰)")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment