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@hml

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.0.tar.gz (56.9 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.0-py3-none-any.whl (23.5 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: hook_my_lichess-0.1.0.tar.gz
  • Upload date:
  • Size: 56.9 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.0.tar.gz
Algorithm Hash digest
SHA256 5740cf748c34324e19396af0c33ee21bb62b06321dfcf4853dd84d3f1de630e7
MD5 eb7ba5c0e0da3fb1306a5b5a3f206d76
BLAKE2b-256 f710090f1f31a1a89ca13959eec7d9916cc9915ecb167f0163446e6045c9e4d6

See more details on using hashes here.

Provenance

The following attestation bundles were made for hook_my_lichess-0.1.0.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.0-py3-none-any.whl.

File metadata

  • Download URL: hook_my_lichess-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 23.5 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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8efee4beb4108caabfc148dfdf0a71290f8745a0e565bde2761c91510913ac60
MD5 624e5e3ffff17b15c8677f06d861af84
BLAKE2b-256 7474a4db990ca6ca8b9766a52735561f3cfcab71257ff92acc10ede65f5dba20

See more details on using hashes here.

Provenance

The following attestation bundles were made for hook_my_lichess-0.1.0-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