rune
Status: archived. rune is feature-complete and no longer developed. It still works —
pipx install rune-cheatsheet— and its output format is frozen and spec'd (docs/text-format.md), so what it renders today it will render, byte-identically, forever. Fork freely.
One keybinding cheatsheet for your whole machine, generated from your configs.
which-key is great inside one program. rune is for the stack around it: tmux,
Neovim, your shell, your terminal, your window manager, Git aliases, and the
little binds you forget until you need them.
A hand-kept cheatsheet (a gist, a wiki page, a sticky note) drifts the moment
you change a config. rune regenerates from the configs themselves, so it's
never out of date. It also does two things a static sheet can't: doctor
finds conflicts across tools — a window-manager chord silently eating a
Neovim mapping — and the chord normalizer makes wildly different spellings
comparable (cmd-alt-ctrl-shift-h, hyper+h, ^A, <C-w> are all the same
kind of thing to rune).
rune show # interactive terminal cheatsheet
rune doctor # find duplicate and shadowed chords
rune which cmd-h # where is this bound?
rune export --html k.html # self-contained cheatsheet + keyboard page
rune build -o keys.json # JSON for another renderer, such as sigil
Install
pipx install rune-cheatsheet
From a clone:
pip install -e .
rune is pure Python 3.11+ and uses the standard library only.
Shell completions
rune completions {bash,zsh,fish} prints a completion script — subcommands,
flags, and even extract's tool names — generated from rune's own parser, so
it can't drift out of sync.
# bash — add to .bashrc
source <(rune completions bash)
# zsh — either eval it directly in .zshrc...
source <(rune completions zsh)
# ...or write it to a file on fpath (needs autoload -Uz compinit && compinit)
rune completions zsh > ~/.zfunc/_rune
# fish — add to config.fish
rune completions fish | source
Platforms
macOS and Linux are first-class — most extractors target tools native to one
or the other (AeroSpace/Hammerspoon/skhd vs. Sway/Hyprland), and each fails
soft when its tool isn't there. Run rune extractors --check to see what's
live on your machine. On Windows, build, export, and doctor work; rune show falls back to plain text instead of the curses UI.
Quick Start
rune init
rune show
rune init writes a small rune.toml. rune show reads it, extracts bindings,
and opens a terminal UI. Press k in the UI for the keyboard view.
No config yet? rune show still tries common tools so you can see whether it is
useful before wiring anything up.
What It Reads
rune can read bindings in two ways. Mix them freely.
Native Extractors
These read real bindings with no annotation:
[[extract]]
tool = "tmux"
[[extract]]
tool = "git"
[[extract]]
tool = "nvim"
path = "~/.config/nvim/lua/keymaps.lua"
Current extractors include tmux, Git aliases, zsh, bash, fish, Neovim, WezTerm, Ghostty, Kitty, Alacritty, Helix, VS Code, AeroSpace, Hammerspoon, skhd, Vim, Sway, Hyprland, readline, and Emacs.
Check what works on your machine:
rune extractors --check
Inline Annotations
Use annotations when you want the description to be yours:
# @rune section Windows
# @rune family system
# @rune row caps + h :: focus left
# @rune row caps + l :: focus right
# @rune end
cmd-alt-ctrl-shift-h = "focus left"
cmd-alt-ctrl-shift-l = "focus right"
@rune is the current marker. The old @cs marker still works.
If an extractor and an annotation produce the same section, the annotation wins. Extraction gives coverage; annotations give taste and authority.
A path containing *, ?, or [ is treated as a glob and expands to one
annotation source per match (path = "~/.config/nvim/lua/keymaps/*.lua").
Example Config
[[extract]]
tool = "tmux"
[[extract]]
tool = "git"
[[annotate]]
path = "~/.config/aerospace/aerospace.toml"
[[view]]
id = "term"
label = "Terminal"
key = "1"
columns = [["tmux-prefix"], ["git-aliases"], []]
There is a fuller example at
examples/dotfiles.rune.toml.
Output
rune showopens a terminal cheatsheet with search and a keyboard view.rune export --html keys.htmlwrites one portable HTML page.rune export --md keys.mdwrites Markdown for docs or a wiki.rune build -o keys.jsonwrites the stable JSON contract.rune listwrites a flat TSV, one row per chord: key, action, section, source.
rune list is the fzf/grep/awk surface — no nested JSON to unwrap:
rune list | fzf
Filtering (the TUI's / search and every --filter flag) is substring
or subsequence — "wndwfcs" finds "window focus" even with the spaces
dropped and half the letters skipped.
The HTML and TUI keyboard views show physical keys by modifier layer. That makes used chords and free chords visible at a glance. The layout assumes an ANSI US-QWERTY physical keyboard for now.
Conflicts
rune doctor
doctor looks for:
- duplicates: the same chord bound twice in the same context
- shadows: an outer layer catches a chord before an inner layer can see it
For example, a window-manager binding can shadow a terminal, tmux, shell, or editor binding. Modal bindings such as tmux prefix maps and Vim leader maps are handled separately so intentional layers do not look like bugs.
Sample output, from a skhd config with a repeated binding and a chord that also lives in zsh:
analyzed 4 chord(s) across 2 context(s): skhd, zsh
duplicate (one silently wins):
⚠ cmd+h bound 2× in skhd — one silently wins
skhd yabai -m window --focus west ← extractor:skhd
skhd yabai -m window --focus west ← extractor:skhd
shadow (outer layer eats the key):
⚠ ctrl+h: skhd grabs it before zsh ever sees it
skhd yabai -m window --focus west ← extractor:skhd
zsh backward delete char ← extractor:zsh
2 conflict(s).
doctor's exit code is the conflict count, so it wires straight into CI or a
pre-commit hook.
Before binding a new chord, check whether it's already taken:
rune which cmd-h
which looks up a chord across every tool rune knows about and prints every
binding it finds, using the same normalizer as doctor — so cmd-h and ⌘h
find the same match. It exits 0 if the chord is bound and 1 if it's free, so
it also works as a script check.
sigil
rune owns the data and its own renderers (TUI, HTML, Markdown); rune build
emits a stable JSON contract that other tools can consume too.
sigil is one such consumer — a native macOS
HUD that reads that JSON and renders it as an overlay. Nothing about the
contract is macOS- or sigil-specific; any renderer of the JSON works the same
way.
(rune's keyboard-cheatsheet feature started life inside sigil and was later pulled out to stand on its own.)
Status
v0.1. The JSON shape is intended to be stable. Extractors are best effort. Annotate anything you want to be exact, polished, or personal.
For internals and maintenance notes, read docs/GUIDE.md.
Authorship
This project and its docs were written with AI assistance. Care was taken to keep the code and explanations readable by both humans and AI agents: short sections, direct examples, stable names, and comments where they earn their place.
License
MIT. See LICENSE.
Metadata
Release files for rune-cheatsheet 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| rune_cheatsheet-0.2.0.tar.gz | 62.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| rune_cheatsheet-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 120.1 kB
Release files / rune_cheatsheet-0.2.0.tar.gz
| Download URL | rune_cheatsheet-0.2.0.tar.gz |
|---|---|
| Size | 62.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
97a1735e07594b1f3a7af74658ba554be92cec6fbbe44122be91b95a0f9ab590
|
|
BLAKE2b-256 checksum How to use checksums |
a0ec01e53936f699b865eb9a8ecd9eb9f4d199d521430d7cf1306b3cb55f5408
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 22, 2026.
Transparency logRelease files / rune_cheatsheet-0.2.0-py3-none-any.whl
| Download URL | rune_cheatsheet-0.2.0-py3-none-any.whl |
|---|---|
| Size | 57.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
23f223d433f43ebf72d3e3d221872fb0bca77fe06db7e5b8f72158d0c0872181
|
|
BLAKE2b-256 checksum How to use checksums |
e40f0b049145ef160caaf46bc424492ec7e96a38d3f895787f5d7be1c454b2ce
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 22, 2026.
Transparency log