A minimal, local-first "read later" CLI tool for macOS and Linux. Store links locally with SQLite, no account, no sync, no background daemon. Follows Linux command conventions (ls, rm, grep) for familiarity.
- Local-first: All data stored in a single SQLite file
- Fast: Minimal dependencies, quick startup
- Portable: Easy export/import via JSON
- Search: Full-text search across URLs, titles, notes, and tags
- Interactive TUI: Beautiful terminal interface with multi-select support
- Simple: Clean CLI interface with standard library only
go install github.com/bunchhieng/rl@latestAdd to PATH:
# zsh (macOS)
GOPATH=$(go env GOPATH)
echo "export PATH=\"$GOPATH/bin:\$PATH\"" >> ~/.zshrc && source ~/.zshrc
# bash (Linux)
GOPATH=$(go env GOPATH)
echo "export PATH=\"$GOPATH/bin:\$PATH\"" >> ~/.bashrc && source ~/.bashrcVerify: rl version
git clone https://github.com/bunchhieng/rl.git && cd rl
make build # Build binary
make install # Install to $GOPATH/bin
# Or manually: go build -o bin/rl .- macOS:
~/Library/Application Support/rl/links.db - Linux:
~/.config/rl/links.db - Windows:
%AppData%/rl/links.db
Override with --db-path flag.
Commands follow Linux conventions for familiarity. Use rl --help or rl <command> for details.
Launch the interactive terminal interface:
rl # Launch TUI (default when no command provided)
rl tui # Or explicitly launch TUIKeyboard shortcuts:
j/↓- Move downk/↑- Move upg- Go to topG- Go to bottomSpace- Toggle selection (multi-select)Ctrl+A- Select all visible linksCtrl+D- Deselect all/- Search modeTab- Cycle filter (Unread/Read/All)o/Enter- Open link in browserd- Mark as read (works on selected items)u- Mark as unread (works on selected items)r- Delete link(s) (with confirmation, works on selected items)q- Quit
rl add <url> [--title "..."] [--note "..."] [--tags "..."]
rl add https://example.com --title "Example" --tags "web,example"rl ls # Unread links (default)
rl ls --read # Read links only
rl ls --all # All links
rl ls --tag <tag> # Filter by tag
rl ls --limit <n> # Limit number of results
# 'list' also works as aliasrl open <id> # Open link in browser (doesn't mark as read)
rl done <id> # Mark link as read
rl undo <id> # Mark link as unread
rl rm <id> [id...] # Delete one or more links (Linux standard)rl grep <query> # Full-text search across URL, title, note, tags
# 'search' also works as aliasrl export > links.json # Export all links to JSON
rl import <file> # Import links from JSON (merges duplicates)# Interactive mode
rl # Launch TUI for interactive browsing
# Add links
rl add https://golang.org --title "Go" --tags "programming,go"
rl add https://rust-lang.org --tags "programming,rust"
# List and filter
rl ls # List unread
rl ls --tag programming # Filter by tag
rl ls --all --limit 10 # All links, limited
# Work with links
rl open <id> # Open in browser
rl done <id> # Mark as read
rl rm <id> <id> # Delete multiple links
# Search and backup
rl grep "programming" # Search links
rl export > backup.json # Backup all linksmake build # Build binary
make test # Run tests
make install # Install locally[
{
"id": "9m1w2z3x",
"url": "https://example.com",
"title": "Example Site",
"note": "Optional note",
"tags": "tag1,tag2",
"created_at": "2024-01-01T12:00:00Z",
"read_at": "2024-01-02T10:30:00Z"
}
]- main.go: Main entry point
- internal/app: Application initialization
- internal/storage: SQLite implementation
- internal/model: Data models and validation
- internal/cli: Command handlers
- internal/tui: Interactive terminal UI (Bubble Tea)
modernc.org/sqlite: Pure Go SQLite driver (no CGO)github.com/jmoiron/sqlx: Lightweight SQL extensionsgithub.com/charmbracelet/bubbletea: Terminal UI framework
MIT