She could write everything the HUD shows but not read most of it back (stack,
live net, alligator state, scar/confidence entries) — so "what's my live net?"
or "what's in my confidence bank?" was a memory guess.
- session_state tool returns the same bundle the HUD renders, as a readable
summary; added to the Cash toolset.
- Cash card tells her the HUD exists, that she and it share the same data, and to
answer where-am-I questions from session_state, never memory.
- test_modes.py +1; 42 green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Brian's own rituals (mined from his logs) become first-class, live tools instead
of post-hoc recap sections:
- Scar Note — instructive mistakes with the punt/cooler/standard distinction.
- Confidence Bank — good process, banked regardless of result.
- Alligator Blood — invokable adversity state; she suggests it when he's
card-dead/short/stuck, and her coaching register shifts while it's on (live
state injected into context per-turn via chat._mode_state_note).
- Reset — tilt circuit-breaker; mental marker only, stats stay continuous.
poker_rituals table + log_ritual/list_rituals/set_alligator/alligator_active;
4 tools added to the Cash toolset and taught in the mode card; HUD gains a 🐊
banner + Confidence Bank + Scar Notes panels; recap grounded via _rituals_block.
tests/test_modes.py +5 ritual tests; 41 green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Lyra was hallucinating poker facts — phantom flushes, missed straights, wrong
equity, only correcting when spoon-fed. Board reading + equity are combinatorial
facts an LLM can't do reliably; this is exactly the "math via deterministic
tools, never the LLM" principle.
- lyra/equity.py: treys-backed analyze(hero, villain, board) -> made hands,
who's ahead, EXACT equity (enumerated), and outs (one to come). Handles 'Jx'
unknown suits (assigned rainbow to avoid phantom flushes); rejects 'x'/dupes.
- analyze_spot tool wired into chat; persona MANDATES it for any equity/board/
who's-ahead/outs question — never eyeballed.
- tests on the real JJ-vs-65 hand: flop 78.7%, turn villain straight + hero 6.8%
with outs "9s 9h 9c" (correctly excludes 9d, which makes villain a flush).
Verified live: she now calls the tool and reports exact numbers, no hallucinated
flush.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Named players in recorded hands now auto-enrich a persistent dossier, and stats
emerge once the sample is big enough — laying groundwork for A.
- poker: player_observations table (per named player per hand: vpip/pfr/saw_flop/
showed/cards/summary); record_hand auto-links named players via link_hand_players;
player_profile(name) returns dossier + reads + shown hands, with inferred
VPIP/PFR/WTSD gated behind MIN_STATS_SAMPLE (12) so thin samples don't lie;
list_players()
- player_profile tool ("what do I know about X"); thin files return a blunt
"don't generalize" directive
- persona: she MUST call player_profile before discussing an opponent and answer
only from it — fixes observed confabulation (she invented a whole read from one
hand / from memory). Verified: now reports only the real logged hand.
- tests: observation linking, profile, stat-emergence at sample threshold
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Completes the poker copilot loop: talk through a session -> structured capture
-> generated writeup in Brian's format, remembered + exportable.
- poker.generate_recap(): LLM produces Brian's .md log (Session Header, Money
Flow, Overview, Timeline, Key Hands w/ assessments, Villain Notes, Confidence
Bank, Scar Notes, Mental Game, Final Assessment) from the session's structured
data + the linked chat conversation; stored on poker_sessions.recap_md
- sessions now capture chat_session_id (via tool ctx) to pull the right convo;
list_recent_hands() for browsing
- generate_recap tool ("write up the recap")
- web: /recap/{id} (renders the md) + /recap/{id}/download (.md attachment) +
/hands browser (recent hands -> /hand/{id}); nav links added (desktop + mobile)
- tests: recap generation (stubbed), recent-hands listing
Verified live: recap for the Meadows session rendered + downloaded; all pages 200.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Brian's idea: vomit rough shorthand, Lyra rebuilds it into a structured,
replayable hand history.
- poker.parse_hand(): focused LLM pass turning shorthand into a canonical hand
JSON (positions, stacks, hero cards, chronological actions w/ board reveals,
result); store_hand_history() persists JSON + extracted flat fields;
record_hand() = parse+store; standalone hands attach to a 'Hand Reviews' session
- poker_hands gains a `structured` JSON column (ALTER-migrated for existing DBs)
- record_hand tool wired into chat: "log this hand: ..." -> reconstructed + a
/hand/{id} link
- web: GET /hand/{id} viewer + /hand/{id}/data — a felt table with seats placed
around the oval (hero at bottom), hole cards, progressive board reveal, and
prev/next/end step-through of the action with running pot
- tests: store/get roundtrip, record_hand tool (stubbed parse)
Verified live: parsed a real AKs hand (BTN, 14 actions, full board) end to end.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The real upgrade over the ChatGPT prose-recap workflow: structured data capture
via tools Lyra drives during a live session, with stats computed from real data.
- lyra/poker.py: domain pack (separate from core memory) — poker_sessions,
poker_hands, persistent poker_players (villain file) + player_reads; functions
for session lifecycle (start/buyin/end with net+hours), tolerant hand logging,
villain upsert/reads, and session/running stats ($/hr, by stake/venue/game)
- tools.py: 8 poker tools wired into the chat tool loop (start_session,
add_buyin, log_hand, add_read, end_session, session_stats, running_stats,
get_villain_file) — partial/terse input tolerated
- import/: Brian's real .md session-log format (reference for the phase-2 recap)
- tests: lifecycle/net math, partial hand logging, villain upsert, running
stats, tool dispatch
Verified live: a full talk-through session persisted as structured rows
(session +240, AKs hand, seat-5 read) — she drove the tools from natural chat.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
She can now *do* things mid-conversation, not just reply. Adds a tool-calling
loop to the chat path and her first two tools; the same mechanism will carry the
poker tools (start_session, log_result, get_stats, solver) next.
- tools.py: registry of OpenAI-style tool specs + handlers + safe dispatch;
journal_write (knowing journaling) and note (tagged notepad, e.g. poker reads)
- llm.chat_call(): OpenAI-style call that returns tool_calls (cloud/mi50);
local has no tool support and returns plain content
- chat.respond(): tool loop — offer tools, run any calls, feed results back,
repeat until a text reply (capped at MAX_TOOL_ROUNDS); persists final reply
- tests: dispatch + full chat loop (tool call -> result -> reply)
Verified live: she invoked `note`, tagged it 'poker', stored a villain read.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>