Personal knowledge base CLI - aggregate content from multiple sources
Project description
lestash
Core CLI and plugin system for Le Stash - a personal knowledge base that aggregates content from multiple sources into a unified, searchable database.
Note: For project overview, features, and quick start guide, see the GitHub repository.
Installation
uv add lestash
Or install the full workspace from the repository root:
uv sync --all-packages
CLI Commands
Items
# List all items (with date/time and resolved author names)
lestash items list
# Filter by source
lestash items list --source linkedin
# Search items
lestash items search "query"
# Show item details (includes reaction/comment target URLs)
lestash items show <id>
# Export items to JSON
lestash items export --output backup.json
# Create a Micro.blog draft from an item
lestash items draft <id> --output ~/blog/content/drafts/
Profiles
Map person URNs (e.g., LinkedIn) to human-readable names and profile URLs:
# Add a profile mapping
lestash profiles add "urn:li:person:abc123" --name "John Doe" --url "https://linkedin.com/in/johndoe"
# List all profiles
lestash profiles list
# Show a specific profile
lestash profiles show "urn:li:person:abc123"
# Remove a profile
lestash profiles remove "urn:li:person:abc123"
When profiles are configured, items list and items search display names instead of URNs, and items show includes the profile URL.
Sources
# List configured sources
lestash sources list
# Sync all sources
lestash sources sync
# View sync history
lestash sources history
Configuration
# Show current config
lestash config show
# Initialize config file
lestash config init
# Set a config value
lestash config set logging.level DEBUG
Plugin Architecture
Le Stash uses entry points for plugin discovery. Plugins implement the SourcePlugin base class:
from lestash.plugins.base import SourcePlugin
from lestash.models.item import ItemCreate
class MySource(SourcePlugin):
name = "my-source"
description = "My custom data source"
def get_commands(self) -> typer.Typer:
"""Return Typer app with source-specific commands."""
app = typer.Typer()
# Add commands...
return app
def sync(self, config: dict) -> Iterator[ItemCreate]:
"""Fetch items from the source."""
yield ItemCreate(
source_type="my-source",
source_id="unique-id",
content="Item content",
)
Register the plugin in pyproject.toml:
[project.entry-points."lestash.sources"]
my-source = "my_package:MySource"
Data Model
Item
The core unit of content:
| Field | Type | Description |
|---|---|---|
id |
int | Auto-generated primary key |
source_type |
str | Plugin identifier (e.g., "arxiv", "linkedin") |
source_id |
str | Unique ID within the source |
url |
str | Optional URL to original content |
title |
str | Optional title |
content |
str | Main text content |
author |
str | Optional author |
created_at |
datetime | When the content was created |
is_own_content |
bool | Whether user authored this |
metadata |
dict | Source-specific data (JSON) |
Database
SQLite database with:
- items - Main content table with unique constraint on (source_type, source_id)
- items_fts - Full-text search virtual table (FTS5)
- item_history - Audit trail of content changes
- person_profiles - URN to name/URL mapping for display
- tags / item_tags - Tagging system
- sources - Plugin configuration storage
- sync_log - Sync operation history
Configuration
Default location: ~/.config/lestash/config.toml
[general]
database_path = "~/.config/lestash/lestash.db"
[logging]
level = "INFO"
file_path = "~/.config/lestash/logs/lestash.log"
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file lestash-1.12.0-py3-none-any.whl.
File metadata
- Download URL: lestash-1.12.0-py3-none-any.whl
- Upload date:
- Size: 25.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
40e9d1dbd57e3013c1b75effe646dae9d27473b3e91532097f9bb3eaefcea900
|
|
| MD5 |
8c6d1cd30b72ec50f2f4cfe2b65699f6
|
|
| BLAKE2b-256 |
b8e515e04a716cbad745dded648d1af3ba94c5731bcf4eea881508640069eaef
|
Provenance
The following attestation bundles were made for lestash-1.12.0-py3-none-any.whl:
Publisher:
release.yml on thompsonson/lestash
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lestash-1.12.0-py3-none-any.whl -
Subject digest:
40e9d1dbd57e3013c1b75effe646dae9d27473b3e91532097f9bb3eaefcea900 - Sigstore transparency entry: 1166194492
- Sigstore integration time:
-
Permalink:
thompsonson/lestash@7a9926d2b61981cc7c9bebac81aef025cb0962db -
Branch / Tag:
refs/heads/main - Owner: https://github.com/thompsonson
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@7a9926d2b61981cc7c9bebac81aef025cb0962db -
Trigger Event:
push
-
Statement type: