Grab text from any window on a Linux desktop, write a note next to it, and keep every note in one plain Markdown file.
It was built for reading what an AI coding agent just said and answering it in writing, but it does not know or care where the text came from. A browser, a PDF, a terminal, an editor, a chat window. Anything you can select works.
Select the text, press the shortcut, type the note, press Ctrl+Enter. The
window closes and the note is on disk.
Notes are appended to ~/Annotations/annotations.md:
## 2026-08-22 12:05 · Terminal — cargo build
> warning: unused variable: `attempt`
> --> src/main.rs:96:13
→ Left over from the focus logging. xdotool windowactivate exits 0 even when it
silently fails, so the only trustworthy signal is whether getwindowfocus
actually reports our window.That is the whole storage format. There is no database and no sync. The
directory and the file are created readable by you only. Set ANNOTATIONS_DIR
to keep them somewhere else.
The second tab is every note you have taken, newest first. It is one document
rather than a table of rows, so you can drag a selection across the end of one
note and the start of the next and copy exactly that. Filter with Ctrl+F,
copy the selection with Ctrl+C, edit any note in place and press Save edits
to write the file back.
git clone https://github.com/testy-cool/desktop-annotator
cd desktop-annotator
/usr/bin/python3 annotate.pyIt has to be the system Python, because that is the interpreter with the GTK bindings installed. There is nothing to build and nothing to install.
To get the shortcut, link the launcher somewhere on your path and bind it in your desktop's keyboard settings. On Cinnamon that is Keyboard, Shortcuts, Custom Shortcuts:
ln -s "$PWD/annotate.py" ~/.local/bin/desktop-annotatorPressing the shortcut again closes an open window instead of opening a second one. If two monitors are connected the window opens on the one to the right of your mouse, so it does not cover what you are reading.
| Key | Does |
|---|---|
Ctrl+Enter |
Save the note, or save your edits in the list |
Ctrl+1 |
Add tab |
Ctrl+2 or Ctrl+L |
List tab |
Ctrl+F |
Filter the list |
Ctrl+A |
Select every note in the list |
Esc |
Close |
The arrow button in the title bar opens annotations.md in Sublime Text, if you
have the subl command.
- Linux running X11. Wayland is not supported.
- Python 3 with PyGObject, GTK 3 and WebKit2GTK 4.1.
xclipandxdotool. Alsozenity, but only for the older GTK window.
Tested on Linux Mint with Cinnamon. Other X11 desktops should work, since the only desktop specific part is the keyboard shortcut you bind yourself.
Selecting text on X11 usually publishes it to the PRIMARY selection. The tool
reads PRIMARY and the clipboard once, when you launch it. If PRIMARY is
empty, which happens with applications that do not publish it, it sends a brief
Ctrl+C and then puts your old clipboard contents back. It does not run in the
background and it does not watch your typing.
Rough on purpose. It was written in a few sittings to solve one problem, and it is small enough to read in an afternoon.
The interface is one HTML file loaded into a WebKit window, so changing how it
looks means editing desktop_annotator/ui/index.html and pressing the shortcut
again. That costs about 230ms of startup. Set DESKTOP_ANNOTATOR_UI=gtk for the
older plain GTK window, which opens in roughly half the time and has fewer
features.
rust/ is an abandoned experiment at rebuilding the same thing in Rust and
Slint. It starts slower and uses more memory than the Python version once it
parses a real annotation file, which was the end of that idea. It is kept
because the notes in rust/README.md are worth more than the code.
/usr/bin/python3 -m unittest discover -vMIT.

