"""05 VERSIONED CRITERION. Your judgment, written down once as a prompt, with a version number and a content-hash cache. Bump PROMPT_VERSION and the whole cache invalidates itself; edit an item and only ITS verdict recomputes. This is how our production inbox classifier works (pattern mined from Ray's life repo: comms/classify.py, 106 logged runs). ES: Tu criterio, versionado y cacheado. Es un prompt cuyo trabajo es juzgar otro contenido. Run: python 05_criterion.py (first run: calls the model) python 05_criterion.py (second run: all cache hits, zero calls) Needs: Claude Code installed (the `claude` CLI on your PATH). No API keys. """ import hashlib, json, os, pathlib, shutil, subprocess, sys MODEL = os.environ.get("METAPROMPT_MODEL", "haiku") CACHE = pathlib.Path(__file__).with_name(".criterion_cache.json") PROMPT_VERSION = 1 # <- bump this and every cached verdict below recomputes. That IS the feature. CRITERION = ( "Classify the message into exactly one bucket:\n" "REPLY - a real person is waiting on a decision or answer from me\n" "WAIT - the ball is in someone else's court, just track it\n" "IGNORE - broadcast, promo, or chatter with no action\n" "Reply with ONLY the bucket word." ) INBOX = [ "Hey! Are we still on for the demo tomorrow at 2? Need to book the room.", "Newsletter: 10 AI tools you missed this week!!!", "Sent the contract to legal, will ping you when they respond.", "Can you approve my expense report before Friday?", "FYI the office wifi will be down Saturday 6-8am.", ] def llm(prompt: str) -> str: exe = shutil.which("claude") if not exe: sys.exit("claude CLI not found. Install Claude Code first: https://claude.com/claude-code") r = subprocess.run([exe, "-p", prompt, "--model", MODEL], capture_output=True, text=True, encoding="utf-8") return (r.stdout or "").strip() def main(): cache = json.loads(CACHE.read_text()) if CACHE.exists() else {} hits = calls = 0 for msg in INBOX: # Cache key = content hash + prompt version. Either changes -> recompute. key = hashlib.sha256(f"v{PROMPT_VERSION}:{msg}".encode()).hexdigest()[:16] if key in cache: verdict, src = cache[key], "cache" hits += 1 else: verdict = llm(f"{CRITERION}\n\nMESSAGE: {msg}").split()[0].upper() cache[key] = verdict src, calls = "model", calls + 1 print(f" [{verdict:<6}] ({src:<5}) {msg[:60]}") CACHE.write_text(json.dumps(cache, indent=1)) print(f"\n{calls} model calls · {hits} cache hits · criterion v{PROMPT_VERSION}") print("Run me again: all hits. Bump PROMPT_VERSION: all recompute. / Sube la version: todo se recalcula.") if __name__ == "__main__": main()