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 works, the board hovers in the top-right; you
play by typing p:<move> as a prompt — including while Claude is
mid-response. No PTY proxy, no wrapper binary.
Install
Prereqs (one-time): uv and a Lichess personal token (create one here):
curl -LsSf https://astral.sh/uv/install.sh | sh
export LICHESS_TOKEN=lip_xxxxxxxxxxxxxxxx # add to your shell rc
Then, inside Claude Code:
/plugin marketplace add 0JCRG0/hook-my-lichess
/plugin install hook-my-lichess@jcrg-tooling
Done. Your next prompt fires the hooks; uvx fetches the daemon from
PyPI on first run (~2 s) and caches it.
Playing
Submit any prompt — the board appears within ~1 s. Then type puzzle commands as prompts:
| Command | Effect |
|---|---|
p:e2e4 |
UCI move |
p:Nf3 |
SAN move (piece letters uppercase) |
p:hint |
which square the piece moves from |
p:solve |
give up, reveal the move (shown 10 s) |
p:quit |
close the puzzle |
p:size xl |
resize the overlay (live + persisted) |
p:pos center |
reposition the overlay (live + persisted) |
Anything not starting with p: goes to Claude untouched. Mid-turn
commands hit the board within ~100 ms — no waiting for Claude to
finish. When Claude's turn ends, the banner flips to "✓ Claude is
done" and you keep solving at your own pace.
Caveats
- Kitty graphics protocol required. Works in Ghostty, Kitty, and WezTerm. On anything else (iTerm2, Terminal.app, tmux, VS Code's terminal, plain SSH), the daemon exits silently and Claude works as normal — you just don't get a board.
- Mid-turn commands are visible to the model. Claude Code has no
hook for messages typed while a turn is running, so a mid-turn
p:e2e4reaches Claude's context as plain text (the board still updates — the daemon reads queued input from the session transcript). The plugin injects a standing instruction telling the model to silently ignorep:messages, which works well in practice but costs a few context tokens per prompt. Commands submitted while Claude is idle are properly blocked and never reach the model. - macOS / Linux only. The daemon writes Kitty escapes straight to the pty device; there is no Windows support.
Customizing size & position
The quick way — just type it as a prompt, live overlay updates instantly and the change persists:
p:size xl # small | medium | large | xl | xxl | any number (p:size 1.7)
p:pos center # top-right | top-left | bottom-right | bottom-left | center | row col (p:pos 3 80)
Or edit the settings file by hand:
uvx --from hook-my-lichess hml-overlay init-config
Then edit ~/.config/hml/settings.json:
{ "size": "xxl", "position": "center" }
size—"small"|"medium"(default) |"large"|"xl"|"xxl", or any positive number (e.g.1.7).position—"top-right"(default) |"top-left"|"bottom-right"|"bottom-left"|"center", or a 1-indexed[row, col]pair.
Config is read from $HML_CONFIG, then <cwd>/hml.json, then
~/.config/hml/settings.json — first hit wins.
How it works
Claude Code owns its terminal end-to-end; the overlay is a sibling
daemon, spawned by a UserPromptSubmit hook:
- The hook resolves the terminal's pty device by walking the process tree (hook processes have no controlling terminal) and the daemon writes Kitty graphics escapes straight to it, re-placing the image on a 16 ms clock so it snaps back over scrolls immediately.
- Idle
p:prompts are intercepted withdecision: "block". Mid-turnp:messages are picked up by tailing the session's JSONL transcript, with an 8-second dedup window against duplicates. - One daemon per terminal, keyed by pty name — two Claude sessions in two panes get independent boards.
Full architecture notes and the bugs that drove the sidecar rewrite:
docs/v5-wrapper-vs-v6-sidecar.md.
Developing locally
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 hook scripts prefer the sibling .venv/bin/hml-overlay over
uvx, so working inside this repo always runs your in-tree code. If
the marketplace plugin is also installed, disable it here
(/plugin disable hook-my-lichess) to avoid double-firing.
Debugging: HML_FORCE_OVERLAY=1 bypasses terminal detection;
HML_DEBUG=1 logs to /tmp/hml-sidecar-debug.log. A standalone
stdin-loop version of the puzzle (no Claude, no overlay) runs with
.venv/bin/lichess-puzzle.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file hook_my_lichess-0.1.11.tar.gz.
File metadata
- Download URL: hook_my_lichess-0.1.11.tar.gz
- Upload date:
- Size: 1.8 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
49d14dc9c6684165780210663d1ec1515a517ed9ae8411e6b6699d76dd887318
|
|
| MD5 |
6ac403bd648dc89be27065631ecb1603
|
|
| BLAKE2b-256 |
a35b2369fc400f108ebe4ae001100b0272c960fcf05d2973b561ad2ebe01ddc6
|
Provenance
The following attestation bundles were made for hook_my_lichess-0.1.11.tar.gz:
Publisher:
release.yml on 0JCRG0/hook-my-lichess
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hook_my_lichess-0.1.11.tar.gz -
Subject digest:
49d14dc9c6684165780210663d1ec1515a517ed9ae8411e6b6699d76dd887318 - Sigstore transparency entry: 2254845492
- Sigstore integration time:
-
Permalink:
0JCRG0/hook-my-lichess@0df3eaf8d0de11c18e1064c3765e221a1c3dea73 -
Branch / Tag:
refs/tags/v0.1.11 - Owner: https://github.com/0JCRG0
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@0df3eaf8d0de11c18e1064c3765e221a1c3dea73 -
Trigger Event:
push
-
Statement type:
File details
Details for the file hook_my_lichess-0.1.11-py3-none-any.whl.
File metadata
- Download URL: hook_my_lichess-0.1.11-py3-none-any.whl
- Upload date:
- Size: 26.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e697edd44567de6d4169359f2244ac1bd24aa2dd0d8198971bfbb98b2991cae8
|
|
| MD5 |
547f733388358240709c919bca9b6542
|
|
| BLAKE2b-256 |
170d2407c20247fc587e916124b80c865a19e0ef8975c0ba49af3ab88d13b086
|
Provenance
The following attestation bundles were made for hook_my_lichess-0.1.11-py3-none-any.whl:
Publisher:
release.yml on 0JCRG0/hook-my-lichess
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hook_my_lichess-0.1.11-py3-none-any.whl -
Subject digest:
e697edd44567de6d4169359f2244ac1bd24aa2dd0d8198971bfbb98b2991cae8 - Sigstore transparency entry: 2254845712
- Sigstore integration time:
-
Permalink:
0JCRG0/hook-my-lichess@0df3eaf8d0de11c18e1064c3765e221a1c3dea73 -
Branch / Tag:
refs/tags/v0.1.11 - Owner: https://github.com/0JCRG0
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@0df3eaf8d0de11c18e1064c3765e221a1c3dea73 -
Trigger Event:
push
-
Statement type: