“拆” (chāi) — to dismantle, break down, and digest complex knowledge into your own understanding.
Chai is a lightweight Emacs reading workflow. It does not move text into a separate note-taking system; instead, you read directly in ordinary Org files and leave lightweight marks where they belong. Chai then gives those marks color, mouse actions, annotation overlays, context navigation, and structured export.
Early versions of Chai included a heavier Refinery workflow: content was forked into a separate workbench, rewritten there, and then saved as notes. The current design is much lighter:
- Source files stay plain
.orgfiles. - Highlights are standard Org links:
[[chai:TYPE][TEXT]]. - Comments are standard Org special blocks:
#+BEGIN_CHAI_COMMENT ... #+END_CHAI_COMMENT. - Export results are ordinary Org headlines with property drawers.
- Save, copy, and edit all work through native Org/Emacs mechanisms.
Without Chai, the files remain readable and editable as normal Org documents. With Chai enabled, the same syntax gains semantic faces, mouse commands, note overlays, a context panel, and one-key export.
The workflow has three parts:
- Library — Manage reading materials as Org files
- Highlights & Comments — Mark important fragments while reading
- Export & Preview — Copy or preview an Org export of your marks
📖 Read in Library → 🔖 Highlight / Comment → ✍️ Export / Preview into your notes
- Emacs 29.1+
- Pandoc (file conversion, used by import)
- Python 3.x + PyMuPDF (PDF processing, used by import)
- transient (Library quick-command menu only)
pip install pyobjc-framework-Vision Pillow;; Add to load-path
(add-to-list 'load-path "~/path/to/chai/")
;; Load core modules
(require 'chai) ;; Highlights, comments, and export
(require 'chai-library) ;; Library management
(require 'chai-library-table) ;; Library table interface
;; Optional: Global keybindings
(global-set-key (kbd "C-c l") #'chai-library-open)
(global-set-key (kbd "C-c b") #'chai-library-open-book)
(global-set-key (kbd "C-c i") #'chai-library-import)Chai uses the following default directory structure (under ~/.emacs.d/chai/):
~/.emacs.d/chai/ ├── library/ ;; Library files (managed .org files) ├── inbox/ ;; Import inbox ├── archive/ ;; Archived source files after import └── exports/ ;; Editable export preview files
Customize via these variables:
| Variable | Description | Default |
|---|---|---|
chai-library-directory | Library directory | ~/.emacs.d/chai/library/ |
chai-library-import-inbox | Import inbox | ~/.emacs.d/chai/inbox/ |
chai-library-import-archive | Archive directory | ~/.emacs.d/chai/archive/ |
chai-export-preview-directory | Export preview directory | ~/.emacs.d/chai/exports/ |
Chai’s Library is a directory of Org files. Once an .org file is placed in
chai-library-directory, it is automatically adopted when the library is opened
or refreshed. You do not have to run an import command first.
If you start with PDF/Markdown/EPUB/HTML, use one of the import paths to convert them into Org and move them into the library:
M-x chai-library-import— Batch import all files from the inboxC-u M-x chai-library-import— Import a single specified fileM-x chai-library-auto-rename-all— Rename/adopt all unmanaged.orgfiles already in the library directory
For web articles, use the Copy as Org Mode browser extension. It supports
defuddle, so copied pages include author, title, and other metadata already
formatted as Org. Paste the result directly into chai-library-directory; Chai
will adopt it with the metadata intact, no manual filename editing required.
From the terminal:
# Batch import
python convert-to-org.py \
--temp ~/.emacs.d/chai/inbox/ \
--reference ~/.emacs.d/chai/library/ \
--archive ~/.emacs.d/chai/archive/
# Single file import
python convert-to-org.py \
--file ~/Downloads/paper.pdf \
--reference ~/.emacs.d/chai/library/- PDF (supports scanned PDF OCR, macOS only)
- Markdown
- EPUB
- HTML
Run M-x chai-library-open-book to show the Library’s filenames directly in
the minibuffer. Type to filter, press RET, and Chai opens the selected Org
file without opening the Library table first. The command only lists .org
filenames; it does not parse book contents or metadata before selection.
Imported files use structured naming:
ID__Author__Title==keyword1_keyword2--status-rating.org
Delimiter meanings:
__— Metadata separator (ID, author, title)- ==== — Keyword separator
--— Status and rating
You can also run the batch rename script from the terminal:
emacs --batch -L . -l chai-library.el -l chai-library-batch-rename.el \
--eval '(chai-library-batch-rename)'Run M-x chai-library-open to open the library interface (full-frame):
| Key | Function |
|---|---|
? | Open the transient quick-command menu |
RET | Open selected book/document |
s | Set reading status (unread/reading/done/archived) |
r / 0-5 | Set rating (0-5 stars) |
k | Set keywords (comma-separated, stored in filename) |
a | Manually rename/adopt selected file |
d | Delete file (requires confirmation) |
/ | Filter by title/author/keywords |
c | Clear filter |
S | Toggle sort order |
g | Refresh list |
The ? key opens a transient quick-command menu — it is a shortcut palette, not a
persistent operating panel. Use it to run a single command and return to the table.
Refresh (g) preserves the current book/selection position when possible.
Evil is automatically disabled in chai-library-mode so that the plain keymap above
is not shadowed by Evil bindings.
Customize Library keys with chai-library-keybindings. If you change it after
loading Chai, run M-x chai-library-apply-keybindings.
(setq chai-library-keybindings
'(("RET" . chai-library-open-book-at-point)
("R" . chai-library-refresh)
("K" . chai-library-set-keywords)))
(chai-library-apply-keybindings)While reading an Org file, mark fragments with Chai links and free-standing comment blocks:
- Highlighted text:
[[chai:TYPE][TEXT]] - Highlighted text with annotation:
[[chai:TYPE:NOTE][TEXT]] - Free-standing comment:
#+BEGIN_CHAI_COMMENT…#+END_CHAI_COMMENT
| Command | Function |
|---|---|
M-x chai-highlight-region | Highlight selected region |
M-x chai-highlight-annotate | Highlight selected region with note |
M-x chai-remove-highlight | Remove highlight at point |
M-x chai-add-comment | Prompt for a free-standing comment |
M-x chai-insert-comment | Insert a #+BEGIN_CHAI_COMMENT block |
M-x chai-export-highlights-copy | Copy highlights and comments as plain text |
M-x chai-export-highlights-copy-org | Copy highlights and comments as Org markup |
M-x chai-export-preview | Open editable Org preview buffer |
M-x chai-export-preview-save | Save Org export directly to the preview file |
M-x chai-context-panel-toggle | Toggle highlight overview panel |
M-x chai-refresh-annotations | Refresh annotation overlays |
Chai provides 12 semantic highlight types. Each type is rendered with a face, so highlights are visible directly in the buffer. Faces work in both light and dark themes, and you can customize them or add your own types.
Right-click anywhere in a Chai-enabled Org buffer to add a free-standing
comment. Right-click a chai link to change type, edit the note, remove the
highlight, or copy the highlighted text. With an active region, right-click to
highlight it with any type from chai-highlight-types.
The context menu also shows region commands. Use them with an active region:
- Chai: highlight region… — choose any highlight type for the region
- Chai: highlight TYPE — quick entries generated from
chai-highlight-types - Highlight with note… — highlight the region and attach a note (annotation)
- Chai: add comment — wrap the region in a
#+BEGIN_CHAI_COMMENTblock
If no region is active, Chai: add comment inserts an empty comment block at point.
- 🔴 important — Important viewpoint
- 🟢 idea — Inspiration/thought
- 🟠 question — Question
- 🟡 critical — Critical content
- 💛 key — Central idea/main point (yellow)
- 🔴 core — Definition/core concept (red/orange)
- 🟢 detail — Data/key details (green, underline)
- 🔵 example — Cases/supporting evidence (blue, underline)
- 🟣 hard — Difficulty/logical turn (purple, wavy)
- ⬜ block — Complete viewpoint paragraph (grey, border)
- 🟪 view — Author’s opinion/personal insight (purple)
- ⚫ outdated — Excluded/outdated info (strikethrough)
Customize highlight types:
(setq chai-highlight-types
'(("important" . chai-highlight-important)
("idea" . chai-highlight-idea)
("key" . chai-highlight-key)
;; ... add custom types
("todo" . hl-line)))Press C-c p (when bound) to toggle a side window showing all highlights
grouped by type. The current highlight’s group is highlighted for easy
navigation.
Use #+BEGIN_CHAI_COMMENT blocks for notes that are not attached to a specific
highlighted fragment:
This is my own thought about the section above.
M-x chai-add-commentprompts for comment text and inserts a complete block.M-x chai-insert-commentinserts an empty block, or wraps the active region.- Comments are collected and exported together with highlights in source order.
Chai distinguishes between storage syntax (what you type while reading) and export syntax (what is copied to the kill ring or shown in the preview buffer).
M-x chai-export-highlights-copy-org copies highlights and comments as
source-ordered Org headlines. Each highlight type becomes a TODO keyword, and
source metadata lives in a :PROPERTIES: drawer. The #+SEQ_TODO: line is
generated dynamically from your chai-highlight-types, with COMMENT appended
for free-standing comments.
The file header prefers the source Org buffer’s #+TITLE, falls back to the
source file’s base name, and finally to “Chai Export” when no source is known.
M-x chai-export-preview opens the same export in an editable *Chai Export
Preview* buffer. The buffer is associated with
~/.emacs.d/chai/exports/<source-base>_chai.org (customize via
chai-export-preview-directory) so you can edit it and press C-x C-s to save
normally. No file is written until you save.
M-x chai-export-preview-save writes the same export directly to that file.
#+TITLE: Source Title #+SOURCE: /path/to/source.org #+EXPORTED_AT: 2026-06-21 12:30 #+SEQ_TODO: IMPORTANT IDEA QUESTION KEY COMMENT * IMPORTANT highlighted text :PROPERTIES: :SOURCE: [[file:/path/to/source.org::25][L25]] :END:
Annotated highlights keep the note in a #+BEGIN_CHAI_ANNOTATION block under
the headline:
* IDEA highlighted text :PROPERTIES: :SOURCE: [[file:/path/to/source.org::25][L25]] :END: annotation text
Free-standing comments export as COMMENT headlines:
* COMMENT free-standing comment text :PROPERTIES: :SOURCE: [[file:/path/to/source.org::120][L120]] :END:
The L25 link jumps to the source line in the original file.
| Command | Function |
|---|---|
M-x chai-library-open | Open the Library table |
M-x chai-library-open-book | Select a book in the minibuffer and open it |
M-x chai-library-import | Import files from inbox (or a single file with prefix) |
M-x chai-library-auto-rename-all | Rename/adopt all unmanaged .org files in the library directory |
M-x chai-library-refresh | Refresh the Library table |
M-x chai-library-set-status | Set reading status for book at point |
M-x chai-library-set-rating / 0-5 | Set rating for book at point |
M-x chai-library-set-keywords | Set keywords for book at point |
M-x chai-library-delete | Delete book at point |
M-x chai-library-apply-keybindings | Re-apply custom chai-library-keybindings |
| Command | Function |
|---|---|
M-x chai-highlight-region | Highlight selected region |
M-x chai-highlight-annotate | Highlight selected region with note |
M-x chai-remove-highlight | Remove highlight at point |
M-x chai-add-comment | Prompt for and insert a free-standing comment |
M-x chai-insert-comment | Insert a #+BEGIN_CHAI_COMMENT block |
M-x chai-export-highlights-copy | Copy marks as plain text |
M-x chai-export-highlights-copy-org | Copy marks as Org markup |
M-x chai-export-preview | Open editable Org preview buffer |
M-x chai-export-preview-save | Save Org export directly to preview file |
M-x chai-context-panel-toggle | Toggle highlight overview panel |
M-x chai-refresh-annotations | Refresh annotation overlays |
- Put materials in the library — Drop
.orgfiles intochai-library-directory, or import PDF/Markdown/EPUB/HTML withM-x chai-library-import. - Open a book — run
M-x chai-library-open-bookto select one in the minibuffer, or runM-x chai-library-openand pressRETon the current entry. - Highlight — Select text and
M-x chai-highlight-regionorM-x chai-highlight-annotate. - Export —
M-x chai-export-highlights-copy-organd paste into your notes, orM-x chai-export-previewto edit and save the export directly.
Chai is designed to work alongside existing note-taking systems:
- Org-roam — Paste exported highlights into Org-roam notes
- Denote — Chai uses Denote-compatible timestamp IDs
- Citar/Org-cite — Add
#+BIBLIOGRAPHYreferences in book files
Issues and PRs welcome!
- Code style: Follow standard Emacs Lisp conventions
- Tests: Add tests in
test/directory for new features - Documentation: Update this README to reflect changes
GPL-3.0-or-later
Yibie <yibie@outlook.com>
- Design philosophy inspired by Zettelkasten and Progressive Summarization
- Workflow redesign: Chai no longer forks content into a separate workbench.
You now read directly in ordinary Org files, mark text with standard Org links
(
[[chai:TYPE][TEXT]]), add notes with standard Org blocks (#+BEGIN_CHAI_COMMENT), and export collected marks only when needed. - Refinery removed: The intermediate Refinery workbench and note-saving flow have been removed. Chai now focuses on Library management and highlight export.
- Headline export: Org export now uses source-ordered headlines with dynamic
#+SEQ_TODOkeywords, source metadata in:PROPERTIES:drawers, and#+BEGIN_CHAI_ANNOTATIONblocks for notes. The oldCHAI_QUOTE/CHAI_COMMENTspecial blocks are gone. - Export preview: New
M-x chai-export-previewopens an editable preview buffer, andM-x chai-export-preview-savewrites directly to the preview file. - Export headers: Exported file titles now prefer the source
#+TITLEand fall back to the source file name. - Library transient menu:
?opens a quick transient command menu in the Library table. - tp.el removed: Library table no longer depends on tp.el; status/rating changes refresh the standard tabulated-list display.
- Batch rename retained: Duplicate auto-rename logic merged into a single core function used by both interactive import and the batch script.
- README rewrite: README.org and README_cn.org rewritten around the current Library + Highlight/Comment + Export Preview workflow.
- Browser extension: README now recommends Copy as Org Mode for importing web pages with metadata.
- Library: Add
kkeybinding to set keywords for a book; keywords are encoded in the filename (===kw1_kw2= section) and searchable via =/ - Library: Fix keywords column not refreshing after changes
- Library: Open in full-frame window (
delete-other-windows) - Annotations: Automatically render note overlays in any Org buffer
containing chai links, without requiring
chai-modeto be active
- Initial release
- Library knowledge base management
- Highlighting and linking system
- Context Panel for structured annotation review
- macOS OCR support