Files
atm-curs-dl/.claude/hooks/context_guard.py
Claude Agent fa4c8baa70 CLAUDE.md: sesiunea principala e doar orchestrator, plus hook de context la 250k
Cerut explicit de user: contextul principal e resursa rara, deci munca de
volum (citit transcrieri, scris sumarizari, convertit diagrame, cautari
largi) se da la agenti, iar sesiunea principala imparte munca, citeste
rapoartele, verifica prin sondaj si comite.

Adaugat:
- CLAUDE.md cu tabelul "ce faci tu vs. ce dai la agenti", regulile care se
  pun in promptul fiecarui agent (acelasi prag de context, raport scurt,
  fara commit, fara sub-agenti, domeniu clar, verificare in sarcina lui),
  si capcanele de orchestrare pe care le-am patit azi.
- .claude/hooks/context_guard.py: citeste usage din transcriere si anunta
  cand contextul trece de 250k, o singura data per prag. Testat pe payload
  sintetic (sub prag, peste prag, repetare, fara transcript) si live.
- .claude/settings.json: hook PostToolUse care il ruleaza.
- PROGRESS.md: pointer catre regulile astea.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MtSTyTmt6AbCL9j5ajEDm1
2026-09-13 08:52:09 +00:00

102 lines
3.4 KiB
Python
Executable File

#!/usr/bin/env python3
"""Anunță când contextul sesiunii depășește un prag, ca să se predea sesiunea.
Userul a cerut asta pe 13.09.2026: la ~250k tokeni, sesiunea salvează
PROGRESS.md și se oprește, iar munca o continuă o sesiune nouă. Fără un
semnal automat, pragul se ratează — contextul crește în tăcere.
Rulează ca hook PostToolUse. Primește pe stdin JSON-ul hook-ului, citește
`usage` din ultimul mesaj al transcrierii și, dacă totalul depășește pragul,
injectează un mesaj în context. Anunță o singură dată per prag, ca să nu
umple contextul chiar el.
"""
import json
import os
import sys
THRESHOLD = int(os.environ.get("CTX_GUARD_THRESHOLD", "250000"))
STEP = 50_000 # re-anunță din 50k în 50k peste prag
STATE_DIR = os.path.expanduser("~/.claude/ctx_guard")
MSG = """[context guard] Contextul sesiunii a ajuns la ~{tokens:,} de tokeni (prag: {threshold:,}).
Conform instrucțiunilor userului, acum:
1. Salvează starea în PROGRESS.md — ce s-a făcut, ce a rămas, ce rulează.
2. Comite și fă push.
3. Oprește agenții care au terminat (SendMessage cu shutdown_request).
4. Spune userului că sesiunea e gata de predat și oprește-te.
Nu începe o sarcină nouă mare. Dacă un agent încă lucrează, cere-i raportul
parțial și notează în PROGRESS.md ce rămâne de reluat."""
def total_tokens(transcript_path: str) -> int:
"""Suma din ultimul `usage` găsit în transcriere — aproximarea contextului."""
try:
with open(transcript_path, "r", encoding="utf-8") as fh:
lines = fh.readlines()
except OSError:
return 0
for line in reversed(lines):
try:
usage = json.loads(line).get("message", {}).get("usage")
except (json.JSONDecodeError, AttributeError):
continue
if not usage:
continue
return (usage.get("input_tokens", 0)
+ usage.get("cache_read_input_tokens", 0)
+ usage.get("cache_creation_input_tokens", 0)
+ usage.get("output_tokens", 0))
return 0
def already_warned(session_id: str, bucket: int) -> bool:
"""Marcăm pragul atins, ca să nu repetăm anunțul la fiecare tool call."""
os.makedirs(STATE_DIR, exist_ok=True)
path = os.path.join(STATE_DIR, f"{session_id}.txt")
try:
with open(path) as fh:
if int(fh.read().strip() or 0) >= bucket:
return True
except (OSError, ValueError):
pass
with open(path, "w") as fh:
fh.write(str(bucket))
return False
def main() -> None:
try:
payload = json.load(sys.stdin)
except (json.JSONDecodeError, ValueError):
return
transcript = payload.get("transcript_path")
session_id = payload.get("session_id", "unknown")
if not transcript:
return
tokens = total_tokens(transcript)
if tokens < THRESHOLD:
return
bucket = THRESHOLD + ((tokens - THRESHOLD) // STEP) * STEP
if already_warned(session_id, bucket):
return
text = MSG.format(tokens=tokens, threshold=THRESHOLD)
print(json.dumps({
"systemMessage": f"Context la ~{tokens:,} tokeni — salvează PROGRESS.md și predă sesiunea.",
"hookSpecificOutput": {
"hookEventName": payload.get("hook_event_name", "PostToolUse"),
"additionalContext": text,
},
}))
if __name__ == "__main__":
main()