A TUI for categorizing and reading items saved in a Keep.md account.
Sift uses the Keep.md REST API directly at runtime.
Install the latest macOS release with:
curl -fsSL https://raw.githubusercontent.com/mattorb/sift/main/install.sh | sh- That Installs
siftto~/.local/binby default
Alternative install from source: cargo install --git https://github.com/mattorb/sift --locked
Sift needs a Keep.md API key to work. The easiest setup path is:
sift loginThat writes ~/.config/sift/config.json with file permissions restricted to
the current user on Unix platforms. If ~/.config/keep/config.json already
contains an API key, sift login offers to copy it into the Sift config.
At runtime, Sift checks these API key sources in order:
KEEP_API_KEYenvironment variableKEEP_API_TOKENenvironment variable~/.config/sift/config.json(looks forapiKey)~/.config/keep/config.json(looks forapiKey)
KEEP_API_BASE_URL overrides the API base URL. sift login --base-url <url>
stores a Sift-specific base URL when the environment variable is not set.
siftPress ? for help in the TUI.
Sift can run against the local fixture server without a Keep.md account:
python3 scripts/demo_keep_api.pyIn another terminal:
cargo build
KEEP_API_BASE_URL=http://127.0.0.1:8765 ./target/debug/sift --demo--demo uses the local fixture API and a dummy token instead of reading account
credentials. It expects the fixture server to already be running. The default
demo URL is http://127.0.0.1:8765; set KEEP_API_BASE_URL to point at a
different local fixture or integration-test server.
Useful demo paths to exercise are queue navigation, detail loading, search, bucket assignment, notes, archive, and process actions.
| Key | Action |
|---|---|
? |
Toggle help |
Tab / Shift+Tab |
Move between queues |
j / k or arrows |
Move selection |
a then r/t/q/s/m |
Assign read/try/quote/share/bookmark bucket by default |
e |
Archive the selected item |
U |
Remove the active bucket from the selected item |
n |
Edit note |
o |
Open original URL in a browser |
Q |
Quit |
Sift reads items from your Keep.md account and writes changes when you categorize or manage an item:
- Assigning a bucket replaces Sift-managed
bucket/*tags with the selected bucket tag and marks unprocessed items processed. - Marking processed updates the item's processed state.
- Archiving marks the item processed if needed and sets its archive state.
- Removing a bucket updates tags while preserving non-Sift tags.
- Editing notes writes note text back to Keep.md.
- Undo restores tags, processed state, archive state, and note text for the last write action when possible.
By default there are read, quote, share, try, and bookmark categories. They are intended to be mutually exclusive.
Sift loads optional bucket definitions from ~/.config/sift/buckets.toml.
When the file is absent, the built-in workflow is unchanged. Start from
buckets.toml.template to customize the full default
set.
[[bucket]]
id = "read"
label = "To Read"
key = "r"
[[bucket]]
id = "quote"
label = "Quote"
key = "q"
requires_note = trueBucket IDs are written as bucket/<id> tags and legacy bucket-<id> tags are
recognized on read. Bucket keys must be unique single characters and cannot use
existing Sift command keys, digits, or whitespace. Processed items with
unrecognized bucket/* tags appear in the conditional misc queue.
I have been through my fair share of read-later tooling (Instapaper, Pocket, Matter). I like the direction Keep.md is going: exposing a full API and providing a CLI to better plug into AI tooling, integrations, and data portability. It also provides default scraping and HTML-to-Markdown parsing.
MIT - see LICENSE.
