lst is a personal lists and notes management application with a focus on plain-text storage, offline-first functionality, and multi-device synchronization.
For a step-by-step guide see docs/INSTALL.md.
The lst-cli supports optional features to reduce compilation time and dependencies:
gui(default): Enables desktop app integration and live updateslists(default): Core list functionalitynotes: Note management features
# Full installation (default - includes GUI integration)
cargo install --path crates/lst-cli
# Minimal installation (no GUI dependencies, ~3x faster compilation)
cargo install --path crates/lst-cli --no-default-features --features lists
# Custom feature selection
cargo install --path crates/lst-cli --no-default-features --features "lists,notes"Compilation Time Comparison:
- With GUI features: ~19 seconds
- Without GUI features: ~6 seconds (3x faster)
git clone https://github.com/yourusername/lst.git
cd lst
# Install the CLI tool (with GUI integration)
cargo install --path crates/lst-cli
# Install the CLI tool WITHOUT GUI dependencies (faster compilation)
cargo install --path crates/lst-cli --no-default-features --features lists
# Install the MCP server (optional, lightweight)
cargo install --path crates/lst-mcp
# Install the sync daemon (optional)
cargo install --path crates/lst-syncd
# Install the server (optional)
cargo install --path crates/lst-serverThe lst-mcp provides a Model Context Protocol server that allows AI assistants (like opencode) to manage your lists and notes.
# Install the MCP server (lightweight, no Tauri dependencies)
cargo install --path crates/lst-mcp
# Run the MCP server
lst-mcpThe MCP server provides tools for:
- Listing all available lists
- Adding items to lists
- Marking items as done/undone
- Managing list content through AI assistants
The lst-server provides a centralized HTTP API for content synchronization and multi-device access.
# Build the server binary
cargo build --release --bin lst-server
# Or install it system-wide
cargo install --path crates/lst-server-
Create a configuration file at
~/.config/lst/config.toml(see examples/config.toml for reference):Pro tip: LST automatically includes schema references in generated config files for LSP validation. See CONFIG_SCHEMA.md for editor setup instructions.
Generate the schema yourself:
lst schema > lst-config-schema.json
[server]
host = "127.0.0.1" # or "0.0.0.0" for all interfaces
port = 5673
[database]
# Directory for server databases (tokens.db, content.db, sync.db)
data_dir = "~/.config/lst/lst_server_data"The server always prints authentication tokens, deep links, and QR codes to stdout so you can deliver them to users through any secure channel you prefer.
# Using the installed binary
lst-server
# Or with custom config path
lst-server --config /path/to/your/config.toml
# Or directly from source
cargo run --bin lst-serverThe server will:
- Listen on the configured host:port (default:
127.0.0.1:5673) - Create SQLite databases in the configured data directory
- Provide REST API endpoints at
/api/* - Print login tokens, deep links, and QR codes to stdout for manual delivery
- Request login token:
curl -X POST -H "Content-Type: application/json" \
-d '{"email": "[email protected]", "host": "your.server.com"}' \
http://localhost:5673/api/auth/request- Verify token and get JWT:
curl -X POST -H "Content-Type: application/json" \
-d '{"email": "[email protected]", "token": "RECEIVED-TOKEN"}' \
http://localhost:5673/api/auth/verify- Use JWT for authenticated requests:
JWT_TOKEN="your-jwt-token"
curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer $JWT_TOKEN" \
-d '{"kind": "notes", "path": "example.md", "content": "Hello from API!"}' \
http://localhost:5673/api/contentFor complete API documentation, see SPEC.md.
The CLI provides a streamlined authentication flow that works with the server's log-based token system:
- Configure server URL (if not done already):
lst sync setup --server http://localhost:5673/api- Request authentication:
lst auth request [email protected]Watch the server logs or terminal output to copy the generated token (or scan the QR code).
- Verify and store JWT:
lst auth verify [email protected] YOUR-TOKEN-HEREThis exchanges the token for a JWT that's stored locally for future requests.
- Use authenticated commands:
lst server create notes "test.md" "Hello from authenticated CLI!"The CLI includes these authentication commands:
# Request authentication token
lst auth request [email protected]
# Verify token and store JWT
lst auth verify [email protected] RECEIVED-TOKEN
# Check authentication status
lst auth status
# Logout (remove stored JWT)
lst auth logoutOnce authenticated, you can interact with server content directly:
# Create content on the server
lst server create notes "example.md" "Hello from CLI!"
# Get content from the server
lst server get notes "example.md"
# Update content on the server
lst server update notes "example.md" "Updated content"
# Delete content from the server
lst server delete notes "example.md"-
Manage to-do lists from the command line
-
Stores data locally as plain Markdown files (CLI);
lst-serveruses SQLite databases for centralized data management via its API. -
Work offline, sync when connected
-
Fuzzy matching for item targeting
-
Supports multiple document types: lists and notes
-
Directory structure support: Organize files in nested directories while maintaining fuzzy search by filename
-
Daily workflows: Automatic organization of daily lists and notes in dedicated subdirectories
-
Edit & reorder: Change item text or move items within a list
-
Share documents: Grant read or write access to specific devices
-
Sync daemon control:
lst synccommands to configure and monitor background sync -
Tauri apps: Optional desktop and mobile front‑ends built with Tauri
-
MCP Integration: Model Context Protocol server for AI assistant integration
-
Live Updates: Real-time GUI updates when using CLI commands
-
Theming System: Comprehensive theme support with base16/base24 color schemes across all applications
# List all lists
lst ls
# View a specific list
lst ls <list_name>
# Open a list in your editor
lst open <list_name>
# Add an item to a list (creates the list if it doesn't exist)
lst add <list_name> "<item_text>"
# Mark an item as done (by text, fuzzy matching, or index)
lst done <list_name> "<item_text>" # Text match
lst done <list_name> "<partial_text>" # Fuzzy match
lst done <list_name> "#2" # By index (the second item)
# Remove an item from a list
lst rm <list_name> "<item_text>"
# Read items from stdin
cat items.txt | lst pipe <list_name>
# Directory structure support
lst add groceries/pharmacy "Vitamins" # Creates groceries/pharmacy.md automatically
lst add pharmacy "Bandages" # Fuzzy matches to groceries/pharmacy.md
# Share a document with specific devices
lst share <path> --writers <ids> --readers <ids>
# Remove sharing information
lst unshare <path># Create a new note
lst note new "<title>"
# Append text to a note (creates note if missing)
lst note add "<title>" "<text>"
# Open a note in your editor
lst note open "<title>"
# Remove a note
lst note rm "<title>"
# List all notes
lst note ls
# Directory structure support for notes
lst note new "projects/rust/lst" # Creates projects/rust/lst.md automatically
lst note open "lst" # Fuzzy matches to projects/rust/lst.mdlst provides special commands for daily workflows that automatically organize files by date:
# Daily Lists (stored in daily_lists/ subdirectory)
lst dl # Show today's daily list
lst dl add "<task>" # Add task to today's daily list
lst dl done "<task>" # Mark task as done
lst dl undone "<task>" # Mark task as undone
lst dl rm "<task>" # Remove task from today's daily list
lst dl ls # List all daily lists with dates
# Daily Notes (stored in daily_notes/ subdirectory)
lst dn # Open today's daily note in editorDaily files are automatically named with the current date (e.g., daily_lists/20250524_daily_list.md, daily_notes/20250524_daily_note.md) and organized in their respective subdirectories.
# Configure sync settings
lst sync setup --server https://lists.example.com --token <auth>
# Start the background daemon
lst sync start
# Check daemon status
lst sync status
# Stop the daemon
lst sync stop
# View logs
lst sync logs --followlst includes a comprehensive theming system that supports base16 and base24 color schemes across all applications (CLI, desktop, and mobile).
# List available themes
lst theme list
# Apply a theme
lst theme apply <theme_name>
# Show current theme information
lst theme current
# Get detailed theme information
lst theme info <theme_name>
# Validate a theme file
lst theme validate <theme_file>The system includes several built-in themes:
- catppuccin-mocha: Dark theme with warm, muted colors
- catppuccin-latte: Light theme with soft, pastel colors
- gruvbox-dark: Popular dark theme with earthy tones
- gruvbox-light: Light variant of the gruvbox theme
- nord: Cool, arctic-inspired color palette
- solarized-dark: Classic dark theme with balanced contrast
- solarized-light: Light variant of the solarized theme
Themes can be configured in your config.toml file:
[theme]
# Set the active theme
name = "catppuccin-mocha"
# Override specific colors
[theme.vars]
primary = "#a6e3a1"
background = "#1e1e2e"Both desktop and mobile applications support real-time theme switching:
- Desktop: Theme selector in the sidebar
- Mobile: Theme selector in the Settings panel
- Live Updates: Theme changes apply immediately without restart
- Consistent Experience: Same themes work across all platforms
lst uses a unified TOML configuration file located at ~/.config/lst/config.toml that is shared across all components (CLI, server, sync daemon). You can override the config file location by setting the LST_CONFIG environment variable.
Configuration changes take effect the next time you run a command. If you change the content_dir option, existing data will remain in the old location, and you'll need to move it manually to the new location.
[server]
# URL of the sync server API (CLI) / Server host & port (server only)
url = "https://lists.example.com/api"
auth_token = "your-auth-token"
host = "127.0.0.1" # server only
port = 3000 # server only[syncd]
# Server URL for remote sync (if None, runs in local-only mode)
url = "https://lists.example.com/api"
auth_token = "your-auth-token"
# device_id is auto-generated on first startup[ui]
# Order in which to try different methods when resolving item targets
# Valid values: "anchor", "exact", "fuzzy", "index", "interactive"
resolution_order = ["anchor", "exact", "fuzzy", "index", "interactive"]
# Enable Vim-like keybindings in the frontend applications
vim_mode = false
# Leader key used for command sequences (defaults to space)
leader_key = " "[theme]
# Active theme name (use 'lst theme list' to see available themes)
name = "catppuccin-mocha"
# Override specific theme colors
[theme.vars]
primary = "#a6e3a1"
background = "#1e1e2e"
foreground = "#cdd6f4"[fuzzy]
# Similarity threshold for fuzzy matching (0.0 to 1.0)
# Higher values require closer matches
threshold = 0.75
# Maximum number of suggestions to show in interactive mode
max_suggestions = 7[paths]
# Base directory for all content (lists, notes) when used by the CLI directly.
# For `lst-server`, this directory (or the directory containing config.toml if content_dir is not set,
# which then determines the location of a 'lst_server_data' subdirectory)
# is where SQLite database files (e.g., tokens.db, content.db) are stored.
content_dir = "~/Documents/lst"
The lst-server uses specific sections from config.toml:
# Settings for lst-server under its [server] block (host, port)
# are already shown in "CLI & Server Configuration".
# The [paths] block (see above) is crucial for lst-server:
# `content_dir` (or the directory of config.toml if content_dir is not set)
# determines where the 'lst_server_data' subdirectory is created,
# which in turn stores its SQLite database files (e.g., tokens.db, content.db).
# Login tokens are always printed to stdout along with QR codes, so no additional
# server-only configuration is required for authentication delivery.
# The [content] block (with 'root', 'kinds') previously used for
# file system layout is no longer directly applicable to how lst-server serves
# content via its API, as content is now stored in an SQLite database.
# 'Kind' is now a dynamic part of the data schema within the database.[sync]
# Sync behavior settings
interval_seconds = 30
max_file_size = 10485760 # 10MB
exclude_patterns = [".*", "*.tmp", "*.swp"]
[storage]
# CRDT storage settings
crdt_dir = "~/.config/lst/crdt"
max_snapshots = 100lst-syncd keeps a persistent WebSocket connection to the server and reacts to filesystem
events immediately; the interval_seconds value now acts only as a safety fallback when
the daemon cannot maintain a push channel (for example, when the server is offline).
An example unified configuration file is provided in the examples/config.toml file in the repository. You can copy this file to ~/.config/lst/config.toml and customize it to your needs. Each component reads only the sections it needs from the same file.
CLI and Local Usage:
When using the lst CLI directly for local operations, data is stored as Markdown files in the content directory (which can be configured in config.toml using paths.content_dir):
content/
├─ lists/ # per-line anchors, supports nested directories
│ ├─ groceries.md
│ ├─ groceries/
│ │ └─ pharmacy.md
│ └─ daily_lists/ # automatically organized daily lists
│ └─ 20250524_daily_list.md
├─ notes/ # whole-file merge, supports nested directories
│ ├─ bicycle-ideas.md
│ ├─ projects/
│ │ └─ rust/
│ │ └─ lst.md
│ └─ daily_notes/ # automatically organized daily notes
│ └─ 20250524_daily_note.md
---
id: 4a2e00bf-5842-4bff-8487-b9672413f0b6
title: groceries
sharing: []
updated: 2025-04-21T07:35:51.705060Z
---
- [ ] Milk ^XMuD1
- [x] Bread ^lkJzl
- [ ] Eggs ^w5CdqThis project is licensed under the MIT License - see the LICENSE file for details.
Contributions are welcome! Please feel free to submit a Pull Request.
The lst project follows a modular architecture with clear separation of concerns across multiple crates:
-
lst-core- Core functionality- Contains shared data structures (
List,ListItem, etc.) - Storage layer for markdown files and notes
- Configuration management
- Core command implementations
- Theme system with base16/base24 support
- No UI dependencies - lightweight and reusable
- Contains shared data structures (
-
lst-cli- Command-line interface- Depends on
lst-corewith optional Tauri integration - Command-line parsing and user interaction
- Optional desktop app communication (live updates) via
guifeature - Can be installed without GUI dependencies for faster compilation
- Depends on
-
lst-mcp- MCP (Model Context Protocol) server- Depends on
lst-core(lightweight, no Tauri dependencies) - Provides MCP tools for AI assistants (Claude, etc.)
- Enables AI agents to manage lists and notes
- Fast compilation without UI dependencies
- Depends on
-
lst-server- HTTP API server- REST API for multi-device synchronization
- SQLite databases for authentication and content
- Email-based authentication flow
- Separate from CLI for deployment flexibility
-
lst-syncd- Background sync daemon- CRDT-based conflict-free synchronization
- File watching and automatic sync
- Encrypted client-server communication
- Multi-device support
-
lst-desktop- Tauri desktop application- Cross-platform GUI built with React + TypeScript
- Real-time updates from CLI changes
- Rich text editing with CodeMirror
- Integrated theme system with live switching
-
lst-mobile- Tauri mobile application- Mobile-optimized interface
- SQLite storage for offline capability
- Touch-friendly UI components
- Mobile-friendly theme selector in Settings
- Modular Design: Each crate has a specific purpose and minimal dependencies
- Lightweight Core:
lst-corecan be used without UI dependencies - Fast MCP Server: No Tauri compilation when installing MCP server
- Reusable Components: Core functionality shared across all interfaces
- Flexible Deployment: Install only the components you need
The lst-server provides an HTTP API for managing authentication and content.
- Token Request:
POST /api/auth/request- Client sends:
{ "email": "[email protected]", "host": "client.host.name" } - Server prints a one-time token (plus deep link and QR code) to stdout and stores the hashed token in
tokens.db.
- Client sends:
- Token Verification & JWT:
POST /api/auth/verify- Client sends:
{ "email": "[email protected]", "token": "RECEIVED_TOKEN" } - Server verifies the token against
tokens.db. If valid, it's consumed, and a JWT is issued.
- Client sends:
- Authenticated Requests:
- The received JWT is used in the
Authorization: Bearer <JWT>header for all subsequent protected API calls.
- The received JWT is used in the
Content (like notes or lists) is stored in the server's content.db SQLite database. Items are identified by a kind (e.g., "notes", "lists") and a path (e.g., "personal/todos.md"). These are logical identifiers within the database.
- Create:
POST /api/content- Payload:
{ "kind": "notes", "path": "travel/packing_list.md", "content": "- Passport\n- Tickets" } - Response:
201 Createdor409 Conflictifkind/pathalready exists.
- Payload:
- Read:
GET /api/content/{kind}/{path}- Example:
GET /api/content/notes/travel/packing_list.md - Response:
200 OKwith content or404 Not Found.
- Example:
- Update:
PUT /api/content/{kind}/{path}- Payload:
{ "content": "- Passport (checked!)" } - Response:
200 OKor404 Not Found.
- Payload:
- Delete:
DELETE /api/content/{kind}/{path}- Response:
200 OKor404 Not Found.
- Response:
Example curl Usage:
-
Request login token:
curl -X POST -H "Content-Type: application/json" \ -d '{ "email": "[email protected]", "host": "your.server.com" }' \ http://your.server.com:3000/api/auth/request
(Copy the token from the server logs; assume token is
ABCD-1234) -
Verify token and get JWT:
curl -X POST -H "Content-Type: application/json" \ -d '{ "email": "[email protected]", "token": "ABCD-1234" }' \ http://your.server.com:3000/api/auth/verify
(Returns JSON with
jwtfield, e.g.,{"jwt":"eyJ...", "user":"[email protected]"}) -
Create a note using JWT:
JWT_TOKEN="eyJ..." # Replace with actual JWT curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer $JWT_TOKEN" \ -d '{ "kind": "notes", "path": "example.md", "content": "Hello from API!" }' \ http://your.server.com:3000/api/content
-
Read the note:
curl -X GET -H "Authorization: Bearer $JWT_TOKEN" \ http://your.server.com:3000/api/content/notes/example.md
For complete API details, please refer to SPEC.md.
A typical command flow:
- User enters a command like
lst done my-list item1 lst-cliparses this usingclapand dispatches tocli::commands::mark_donecli::commands::mark_donecallslst_core::commands::mark_donelst_core::commands::mark_doneuseslst_core::storage::markdown::mark_doneto modify the filelst-clisends a notification to the desktop app (if running) for live updates
This architecture provides:
- Separation of Concerns: Each crate has a distinct responsibility
- Testability: Core logic can be tested without I/O dependencies
- Flexibility: Multiple interfaces (CLI, MCP, server, GUI) can use the same core logic
- Performance: MCP server compiles quickly without UI dependencies
- Live Updates: GUI automatically refreshes when CLI makes changes
The lst tools are implemented in Rust, and debug builds can exhibit noticeable startup latency.
For the fastest experience, use optimized release builds:
# Install CLI with GUI integration (default)
cargo install --path crates/lst-cli
# Install CLI without GUI dependencies (faster compilation)
cargo install --path crates/lst-cli --no-default-features --features lists
# Install MCP server (compiles quickly - no Tauri dependencies)
cargo install --path crates/lst-mcp
# Install other components as needed
cargo install --path crates/lst-server
cargo install --path crates/lst-syncdRelease builds start up in just a few milliseconds. The MCP server is particularly fast to compile since it doesn't include any UI dependencies.
If you prefer to build locally without installing:
# Build and run specific components
cargo build --release -p lst-cli
./target/release/lst ls <list_name>
# Build CLI without GUI dependencies (faster)
cargo build --release -p lst-cli --no-default-features --features lists
./target/release/lst ls <list_name>
# Build MCP server (always lightweight)
cargo build --release -p lst-mcp
./target/release/lst-mcp