Skip to main content

rune

ci

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

rune demo: show, doctor, which

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 show opens a terminal cheatsheet with search and a keyboard view.
  • rune export --html keys.html writes one portable HTML page.
  • rune export --md keys.md writes Markdown for docs or a wiki.
  • rune build -o keys.json writes the stable JSON contract.
  • rune list writes 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)

Source distribution for rune-cheatsheet 0.2.0
File Size Uploaded
rune_cheatsheet-0.2.0.tar.gz 62.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for rune-cheatsheet 0.2.0
File Interpreter ABI Platform
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 log

Release 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

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page