Skip to main content

A Claude Code hook that opens a Lichess puzzle in your terminal while Claude is working.

Project description

hook-my-lichess

A Lichess puzzle that floats over the same terminal Claude Code is running in. While Claude is working, the puzzle hovers in the top-right corner. You play moves by typing p:<move> as a prompt — including while Claude is mid-response — and the board updates live, no PTY proxy, no wrapper binary in the launch path.

How it works (v6, sidecar architecture)

Claude Code owns its terminal end-to-end. There is no wrapper. The overlay lives in a sibling process:

  • Hook-launched daemon. A UserPromptSubmit hook calls hml-overlay start, which double-forks a Python daemon that opens /dev/tty for writes and emits Kitty graphics escapes. Claude is never resized, never has its I/O intercepted.
  • Independent 16 ms redraw clock. The daemon re-emits kitty_place(image_id, p=1) on its own timer, decoupled from Claude's stdout — so the image snaps back above scrolls without waiting for Claude to emit a byte.
  • Two input surfaces. A turn-boundary path via the UserPromptSubmit hook (p:<move> is intercepted with decision: "block" so the prompt never reaches Claude). And a mid-turn path via the daemon tailing Claude Code's session JSONL transcript at ~/.claude/projects/<project>/<session>.jsonl for queue-operation enqueue and attachment.queued_command records — Claude Code logs queued user input the moment you type it, so the daemon dispatches mid-turn moves with no documented hook involvement at all. An 8-second dedup window swallows the duplicate when UserPromptSubmit later replays the same prompt.

See docs/v5-wrapper-vs-v6-sidecar.md for the full architecture comparison and the bugs that drove the rewrite.

Install

hook-my-lichess is distributed as a Claude Code plugin. Two slash commands and you're done.

Prereqs (one-time):

# uv runs the Python daemon on demand and caches it
curl -LsSf https://astral.sh/uv/install.sh | sh

# Lichess personal token, see https://lichess.org/account/oauth/token
export LICHESS_TOKEN=lip_xxxxxxxxxxxxxxxx   # add to your shell rc

Install in Claude Code:

/plugin marketplace add 0JCRG0/hook-my-lichess
/plugin install hook-my-lichess@jcrg-tooling

That's it. The next prompt you submit will fire the hooks; uvx fetches hook-my-lichess from PyPI on first run (~2 s) and caches it. Subsequent invocations are instant.

The daemon auto-detects whether the terminal supports Kitty graphics (Ghostty / Kitty / WezTerm); on terminals that don't (iTerm2, Terminal.app, tmux), it exits silently — Claude works as normal.

Playing the puzzle

Submit any prompt to Claude. The board appears in the top-right within ~1 s.

Type a puzzle command as your prompt:

  • p:e2e4 — submit a UCI move
  • p:Nf3 — submit a SAN move (piece letters uppercase: Nf3, not nf3)
  • p:hint — hint (which square the piece moves from)
  • p:solve — give up and reveal the move
  • p:quit — close the puzzle

The hook intercepts these (decision: "block") so Claude never sees them. You can also type them while Claude is mid-response — they'll queue, the daemon's transcript tailer will pick them up within ~100 ms, and the board updates without waiting for Claude's turn to finish. (Anything that doesn't start with p: passes through to Claude untouched.)

When Claude finishes its turn, the banner flips to "✓ Claude is done" and you can keep solving at your own pace.

Customizing the board (size & position)

Generate a default settings file:

uvx --from hook-my-lichess hml-overlay init-config
# wrote default settings to ~/.config/hml/settings.json

Edit ~/.config/hml/settings.json:

{
  "size": "xxl",
  "position": "center"
}
  • size — one of "small" (0.75×), "medium" (1×, default), "large" (1.25×), "xl" (1.5×), "xxl" (2×), or any positive number for an exact scale (e.g. "size": 1.7).
  • position — one of "top-right" (default), "top-left", "bottom-right", "bottom-left", "center", or a [row, col] pair for an exact 1-indexed cell (e.g. "position": [3, 80]).

The daemon checks three locations in order: $HML_CONFIG, then <cwd>/hml.json, then ~/.config/hml/settings.json. The per-user file is the one you usually want.

Developing locally

If you want to hack on the overlay itself instead of just using it:

git clone https://github.com/0JCRG0/hook-my-lichess
cd hook-my-lichess
python3 -m venv .venv
.venv/bin/pip install -e .
cp .env.example .env   # put LICHESS_TOKEN here

The hooks in this repo's .claude/settings.json reference $CLAUDE_PROJECT_DIR/hooks/*.sh, and those scripts prefer the local .venv/bin/hml-overlay over uvx when present — so working inside this repo always uses your in-tree code, no rebuild needed.

If you also have the marketplace plugin installed, disable it for this repo (/plugin disable hook-my-lichess) so hooks don't double-fire.

Force-enable the overlay (debugging)

Set HML_FORCE_OVERLAY=1 to bypass the terminal-detection heuristic and always emit Kitty graphics escapes.

HML_DEBUG=1 writes diagnostic lines to /tmp/hml-sidecar-debug.log.

Standalone puzzle (no Claude, no overlay)

Same engine, plain stdin loop:

.venv/bin/lichess-puzzle

Useful for exercising engine.py, board.py, api.py, render.py without touching the overlay code path.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

hook_my_lichess-0.1.2.tar.gz (57.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

hook_my_lichess-0.1.2-py3-none-any.whl (24.0 kB view details)

Uploaded Python 3

File details

Details for the file hook_my_lichess-0.1.2.tar.gz.

File metadata

  • Download URL: hook_my_lichess-0.1.2.tar.gz
  • Upload date:
  • Size: 57.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for hook_my_lichess-0.1.2.tar.gz
Algorithm Hash digest
SHA256 60ec76c8d7d92f1af25e5129e114c6db625846be02b2f8125d900def49b27d58
MD5 cf78dd5b3cc4ab8f4a6b386cdd7fadf4
BLAKE2b-256 68aca23abfd1ffbbe440db28b8ea66a2562c5fd02d34fdb9a8d0933b983418ca

See more details on using hashes here.

Provenance

The following attestation bundles were made for hook_my_lichess-0.1.2.tar.gz:

Publisher: release.yml on 0JCRG0/hook-my-lichess

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file hook_my_lichess-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: hook_my_lichess-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 24.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for hook_my_lichess-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 a12bced6db63ceb5d0ae79256ef9ea532a928096d775516e204894e6b879cc4d
MD5 26e924f5adf4b257666e44c796cff0bf
BLAKE2b-256 73fc255cfc4a7330ab5fe5a61784c3fbb81f5bfc7f6195f952339d446530a820

See more details on using hashes here.

Provenance

The following attestation bundles were made for hook_my_lichess-0.1.2-py3-none-any.whl:

Publisher: release.yml on 0JCRG0/hook-my-lichess

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page