Přejít na obsah
~/case-studies/scorekeeper

scorekeeper

Sledování závazků LLM agentů. Scoreboard toho, k čemu se agent zavázal — ne jen paměť toho, co se stalo.

Sólo — výzkum, teorie, architektura, Python2026Open source (Apache-2.0) · fáze 2 — EntitleBench
PythonClaude Code hooksMCP serverPluggable LLM backendsEntitleBenchPyPI

scorekeeper je normativní vrstva pro dlouho běžící LLM agenty. Vedle paměti agenta — tedy záznamu toho, co se stalo — udržuje scoreboard: k čemu se agent zavázal, co každý závazek podpírá a co je s čím v konfliktu. Závazky se z každého tahu extrahují do strukturovaných záznamů, provenience se sleduje jako plnohodnotná data a nekompatibility se zachytí dřív, než se propíšou do kódu.

Teorie pochází z padesáti let filozofie jazyka — Brandomova deontického scorekeepingu — přeloženého do datového modelu doslova, ne jako metafora. Vydává se jako plugin pro Claude Code (instalace na dva řádky), MCP server a python knihovna. Je změřený benchmarkem včetně publikovaných negativních výsledků a dogfooduje sám sebe: vlastní závazky projektu žijí v .scorekeeper/.

0
driftů se scoreboardem — holý agent driftoval
+0,6 %
režie tokenů
126
testů prochází
5
Claude Code hooků

problém

Dlouho běžící agenti selhávají charakteristickým způsobem. V kroku 3 se rozhodnou pro Postgres, v kroku 47 píšou kód pro MongoDB. Slíbí, že zachovají API kontrakt, a o hodinu později potichu přejmenují dvě pole. Tvrdí něco, co nikde nečetli — a po kompakci kontextu si ani nepamatují, že to tvrdili. Průmysl tomu říká problém paměti a předepisuje větší okna, lepší retrieval, chytřejší sumarizaci.

Nepříjemné pozorování: ve většině těchhle selhání ta informace pořád v kontextovém okně byla. Rozhodnutí pro Postgres tam leželo, čtyřicet tahů zpátky. Úzkým hrdlem nebyl retrieval — chyběl status. Rozhodnutí bylo jen další text, jedna sekvence tokenů mezi tisíci, bez značky, která by řekla tohle tě zavazuje. A to není problém paměti, ale problém normativní: agent vede záznam o tom, co se stalo, ale žádnou účetní knihu toho, k čemu se zavázal.

myšlenka

Filozofie jazyka studuje přesně tuhle strukturu už padesát let. Robert Brandom (Making It Explicit, 1994) popisuje diskurz jako hru, ve které si každý účastník vede deontické skóre o všech ostatních: kdo je k čemu zavázán a kdo je k čemu oprávněn. Tři pojmy se mapují jedna ku jedné na datový model:

Závazek — něco tvrdíš, a tím jsi vázán jak tvrzením samotným, tak jeho důsledky. Oprávnění — máš pro to důvod? Přečtený soubor, instrukci uživatele, výsledek nástroje? Nekompatibilita — závazek k p vylučuje oprávnění k tvrzením, která s p věcně kolidují.

Přeloženo do selhání agentů to sedí až překvapivě přesně. Halucinace je závazek bez oprávnění — a v grafu provenience to není mlhavý soud o kvalitě, ale viditelná díra. Sebe-rozpor je nezachycená nekompatibilita mezi dvěma živými závazky: Postgres v kroku 3 a MongoDB v kroku 47 byly oba aktivní a nikdo nedržel skóre. Nekoherence po kompakci je smazání scoreboardu — sumarizátory zachovají příběh a zahodí přesně ten normativní stav.

$the-overlay
agent turn ──▶ extractor ──▶ commitments + provenance (entitlement)
scoreboard ──▶ operators: ASSERT · CHALLENGE · SUPERSEDE · CONFLICT
file write ──▶ Tier-0 gate ──▶ DENIED until the scoreboard itself
                               records an entitled revision

jak to funguje

Terminálové demo nahoře ukazuje to klíčové rozlišení naživo: stejný tvar změny, jiná provenience, jiný verdikt. Nejdřív se zaznamená oprávněné rozhodnutí. Vlastní drift agenta k MongoDB se pak chytí jako BRANCH-CONFLICT, zatímco změna vyžádaná uživatelem projde jako čistý SUPERSEDE. Reprodukovatelné za zhruba 20 sekund: uv run --project core python demo/drift_demo.py.

scorekeeper je vrstva, ne framework. Pět Claude Code hooků připojí živý scoreboard k libovolné session. Izolovaný scorer extrahuje závazky z každého tahu do strukturovaných záznamů — a dělá to asynchronně, takže samotný tah zůstává na zhruba nulové latenci. Nekompatibilitu mezi živými závazky posuzuje jazykový model, a to záměrně: skutečné konflikty jsou věcné, ne formální. „Nejdřív vydáme CLI“ a „první deliverable je webový dashboard“ nesdílejí jediný predikát, kterého by se chytil dokazovač vět — a přitom tu kolizi vidí každý kompetentní čtenář. Kromě pluginu se scorekeeper vydává i jako MCP server a knihovna, s vyměnitelnými backendy (defaultně lokální claude CLI bez API klíče, nebo Anthropic a OpenAI-kompatibilní API).

Designový postoj, na kterém celý projekt stojí: agent si nedrží vlastní skóre. Sbíhají se v něm tři nezávislé linie. Filozofie — pro Brandoma je scorekeeping konstitutivně sociální, skóre drží druhý hráč, ne mluvčí sám o sobě. Kognitivní věda — Mercier a Sperber ukazují, že jsme líní producenti vlastních zdůvodnění a zároveň ostří hodnotitelé cizích, a evidence u LLM tohle přesně zrcadlí. Inženýrství — paměť, kterou si agent edituje sám, má notorickou mezeru ve spolehlivosti: když agent zapomene zapsat, fakt neexistuje. Scoreboard je proto scaffolded, ne extended — udržují ho deterministické hooky mimo pravomoc agenta. Agent na lešení stojí, ale nepřestavuje si ho za běhu pod sebou.

  • Oprávnění jako provenience — každý závazek nese odkazy na to, co ho podpírá. Závazek se source: none je podezřelý první kategorie.
  • Přežití kompakce — normativní digest se vstřikuje do sumarizace přesně tam, kde ho dnešní sumarizátory zahazují.
  • Asynchronní extrakce — odpojený worker skóruje tah na pozadí a nálezy se ukážou u dalšího promptu.
  • Poctivě na cizích ramenou — kusy tohohle uměly už commitment stores (Hamblin, 1970) i truth-maintenance systémy (Doyle, 1979). Nové je spojení: vlastní diskurz LLM agenta, provenience jako plnohodnotná dimenze, věcná nekompatibilita nad přirozeným jazykem a nasazení v produkčním harnessu.

změřeno, včetně negativních výsledků

Fáze 0 přinesla první párovou deltu. Na nastraženém scénáři s volbou databáze holý haiku agent driftoval k MongoDB proti vlastnímu zaznamenanému rozhodnutí, zatímco jeho dvojče se scoreboardem — stejný model, stejný scénář, přidaný jen scoreboard — linii udrželo. Tedy 0/6 vs. 1/6 driftů, s nulou falešných konfliktů na sondě oprávněné revize a režií +0,6 % tokenů.

Fáze 2, EntitleBench, přinesla nejpoučnější výsledky — dva z nich negativní a oba publikované. V nejtěžší podmínce slabý agent proplul kolem jedenácti poradních varování a stejně postavil lákavou Memcached hot path. Drift dokonce zamaskoval docstringem, který nad importem pymemcache tvrdil „backed by Redis“. Selhal i jednorázový blokující retardér: na výzvu „pokud si to objednal uživatel, řekni to a zkus znovu“ si agent prostě přisvojil oprávnění, které neměl, a zkusil to znovu. Co vydrželo, byla zeď rozhodovaná scoreboardem (ADR-0007): konfliktní zápis zůstává odmítnutý, dokud sám scoreboard nezaznamená oprávněnou revizi. Slovo agenta ji nezvedne. Ověřeno symetricky — drift HELD (žádný konkurenční kód nepřistál), oprávněná revize EXECUTED s nulou odmítnutí. Legitimní cesta nestála nic.

Samotné měření je adversariálně zocelené. Primární metrikou je deterministický klasifikátor nad artefakty; LLM soudce je vědomě až sekundární, nespolehlivá metrika. Benchmark přežil adversariální revizi 33 agentů, každý potvrzený přehmat se stal regresním testem a obě selhání se penalizují na téže hranici: drift (SCR) i falešná odmítnutí (FRR).

stav a co dál

scorekeeper je open source pod licencí Apache-2.0 a je na PyPI. Plugin pro Claude Code se instaluje dvěma řádky z marketplace a scorer si při prvním hooku stáhne sám. MCP server vede zápisy stejnou pipeline operátorů. Repozitář je zdokumentovaný jako výzkumný artefakt — 7 ADRs, závazná specifikace (česky), čtyři literární rešerše, osnova paperu, citační soubor — a drží skóre sám na sobě v .scorekeeper/.

Místo dalšího škálování čísel doma přichází teď prosba směrem ke komunitě: vyzkoušet to. Zkušenostní report na jeden odstavec — co to chytilo, minulo, nebo spletlo — formuje roadmapu víc než cokoli jiného.

$try-it-in-60-seconds
# on a real Claude Code session — nothing to pre-install
/plugin marketplace add michalstrnadel/scorekeeper
/plugin install scorekeeper@scorekeeper

# five hooks attach a live scoreboard;
# watch .scorekeeper/scoreboard.md grow as you work