A GitHub-backed Markdown bookmark manager for the command line.
Project description
Teeny Weeny — Bookmark Manager
A GitHub-backed Markdown bookmark manager for the command line.
Bookmarks are stored as structured JSON and rendered to human-readable Markdown. The repository can be kept in sync with GitHub so your bookmarks are always backed up, versioned, and accessible anywhere.
Core principle: JSON is the source of truth. Markdown is generated output.
What it does
- Save bookmarks from the command line with
bookmark add - Organize bookmarks into categories → spaces → collections
- Fetch page title, description, and favicon automatically
- Detect and reject duplicate URLs after normalization
- Optionally commit and push after every
bookmark add - Validate repository health with
bookmark validate - Run
bookmark --install-completion zshfor tab completion
Installation
Install with pipx (recommended)
pipx install teeny-weeny
Verify:
bookmark --version
bookmark --help
Development install
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
Verify:
bookmark --help
Quick start
# 1. Create a bookmark repository
bookmark init --repo ~/Documents/bookmarks --yes
# 2. Organize with categories, spaces, and collections
bookmark category add -c Engineering
bookmark space add -c Engineering -p Cloud
bookmark collection add -c Engineering -p Cloud -l Kubernetes
# 3. Add a bookmark
bookmark add -l kubernetes -t aws,eks -n "Official docs" https://kubernetes.io
# 4. Validate
bookmark validate
Daily usage
bookmark add -l kubernetes https://example.com # add with metadata fetch
bookmark add -l kubernetes --no-metadata https://example.com # skip metadata
bookmark add -l kubernetes -t aws,eks -n "Note" https://example.com
bookmark category show # view hierarchy
bookmark validate # health check
bookmark config show # current config
Repository structure
After bm init, your repository looks like this:
bookmarks/
├── .bookmark.toml ← project config
├── data/
│ ├── bookmarks.json ← source of truth (all bookmarks)
│ ├── categories.json ← category / space / collection hierarchy
│ └── tags.json ← tag index
├── bookmarks/
│ └── engineering/
│ └── cloud/
│ └── kubernetes.md ← generated Markdown
└── assets/
└── favicons/ ← downloaded favicons
Configuration
User config lives at ~/.config/bookmark/config.toml.
Show resolved config:
bookmark config show
Set a value:
bookmark config set repo.path ~/Documents/bookmarks
bookmark config set git.mode commit
bookmark config set git.commit_message_template "Add bookmark: {title}"
Example config file:
[repo]
path = "/Users/example/Documents/bookmarks"
[git]
mode = "manual"
commit_message_template = "Add bookmark: {title}"
[metadata]
timeout_seconds = 10
download_favicons = true
Categories, spaces, and collections
Bookmarks are organized in a three-level hierarchy:
category → space → collection
Example:
bookmark category add -c Engineering
bookmark space add -c Engineering -p Cloud
bookmark collection add -c Engineering -p Cloud -l Kubernetes
bookmark collection add -c Engineering -p Cloud -l Terraform
bookmark category show
Output:
Engineering
└── Cloud
├── Kubernetes
└── Terraform
Add bookmarks
bookmark add -l <collection> [OPTIONS] <url>
Options:
| Flag | Purpose |
|---|---|
-l, --collection |
Target collection (slug or name) — required |
-c, --category |
Disambiguate if collection name is not unique |
-p, --space |
Disambiguate if collection name is not unique |
-t, --tags |
Comma-separated tags, e.g. aws,eks |
-n, --note |
Personal note |
--status |
unread (default), read, archived |
--title |
Override fetched title |
--description |
Override fetched description |
--no-metadata |
Skip page fetch |
--no-favicon |
Skip favicon download |
Examples:
bookmark add -l kubernetes https://example.com
bookmark add -l kubernetes -t aws,eks -n "Good reference" https://example.com
bookmark add -c engineering -p cloud -l kubernetes https://example.com
bookmark add -l kubernetes --no-metadata https://example.com
Git behavior
Configure Git mode:
bookmark config set git.mode manual # update files only (default)
bookmark config set git.mode commit # update files + local commit
bookmark config set git.mode commit_and_push # update files + commit + push
| Mode | Behavior |
|---|---|
manual |
Files updated, no Git commit |
commit |
Files updated + local commit |
commit_and_push |
Files updated + commit + push |
Configure the commit message template:
bookmark config set git.commit_message_template "Add bookmark: {title}"
Available placeholders: {id}, {title}, {url}, {normalized_url},
{collection}, {collection_slug}, {category_slug}, {space_slug},
{status}, {added_at}.
Safety rule: Git runs after both
bookmarks.jsonand the collection Markdown file are written. A Git failure never rolls back file changes — the bookmark is always added even if Git fails.
Validate repository
bookmark validate
Validate a specific repository:
bookmark validate --repo ~/Documents/bookmarks
Output as JSON (for scripts):
bookmark validate --json
Fail on warnings too (used in CI):
bookmark validate --strict
Validation checks:
- Required repository files and directories
data/bookmarks.jsonschema and integritydata/categories.jsonschema and integritydata/tags.jsonschema- Duplicate normalized URLs
- Collection Markdown files exist on disk
- Bookmark-to-collection references are consistent
- Favicon paths exist if stored
- Generated Markdown bookmark blocks match JSON records
GitHub Actions
The repository ships with .github/workflows/validate.yml.
The workflow runs on every push and pull request:
- Installs the package
- Runs
pytest - Runs
ruff check . - Runs
bookmark validate --strict
Shell completion
Bookmark Manager uses Typer's built-in completion system.
zsh
bookmark --install-completion zsh
exec zsh # reload shell
bookmark <TAB> # try completion
bash
bookmark --install-completion bash
exec bash
bookmark <TAB>
Show completion script without installing
bookmark --show-completion zsh
bookmark --show-completion bash
Both
bookmarkandbookmarksupport completion.
Common aliases
Add to your ~/.zshrc or ~/.bashrc:
alias bma='bookmark add'
alias bmv='bookmark validate'
alias bmc='bookmark category show'
alias bmg='bookmark config show'
Usage:
bma -l kubernetes https://example.com
bmv
bmc
Command reference
| Command | Purpose |
|---|---|
bookmark init |
Bootstrap a bookmark repository |
bookmark config show |
Show resolved configuration |
bookmark config set KEY VALUE |
Set a user config value |
bookmark category add -c CATEGORY |
Add a category |
bookmark space add -c CATEGORY -p SPACE |
Add a space |
bookmark collection add -c CATEGORY -p SPACE -l COLLECTION |
Add a collection |
bookmark category show |
Show the category / space / collection hierarchy |
bookmark add -l COLLECTION URL |
Add a bookmark |
bookmark validate |
Validate the repository |
bookmark doctor |
Check that the CLI is installed correctly |
Troubleshooting
bookmark command not found
Make sure the package is installed:
pipx install teeny-weeny
which bookmark
bookmark --help
For development:
pip install -e ".[dev]"
which bookmark
Repository path is not configured
bookmark config set repo.path ~/Documents/bookmarks
bookmark config show
Repository is not initialized
bookmark init --repo ~/Documents/bookmarks
Collection not found
bookmark category show # list all collections
bookmark add -l kubernetes https://example.com
If the collection name is ambiguous across categories or spaces, include
--category and --space:
bookmark add -c engineering -p cloud -l kubernetes https://example.com
Duplicate bookmark detected
The URL already exists in bookmarks.json after normalization.
The CLI shows the existing title, collection location, and date added.
Metadata fetch failed
The bookmark is still added. The CLI uses the URL hostname as a fallback title and shows a warning. You can supply a title manually:
bm add -l kubernetes --title "My Title" https://example.com
Git commit failed
The bookmark files were updated successfully. Commit manually:
cd ~/Documents/bookmarks
git status
git add data/bookmarks.json bookmarks/ assets/favicons/
git commit -m "Add bookmark"
git push
Validation failed
bookmark validate # see all issues with paths
bookmark validate --json # machine-readable output
Fix the reported files and run bookmark validate again.
Development
pip install -e ".[dev]"
pytest # run tests
ruff check . # lint
ruff format . # format
bookmark validate --strict # validate the bookmark repository itself
Roadmap
Future phases (not yet implemented):
bm search— full-text search across bookmarksbm edit— edit bookmark fieldsbm delete— remove a bookmarkbm import— import from browser bookmarks or Markdownbm export— export to browser-importable format- Sync / conflict resolution
- Browser extension
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 Distribution
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 teeny_weeny-0.1.1.tar.gz.
File metadata
- Download URL: teeny_weeny-0.1.1.tar.gz
- Upload date:
- Size: 47.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.17
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2b1d651272d8bc3ddca2809abb0629e36bc3cf0712c141574e290f174601f858
|
|
| MD5 |
d9f72d4dfc2b711225a9d0af3602b94e
|
|
| BLAKE2b-256 |
86358a89351179ede1eec9e8f34ece8c19d947e59a0def11b68c0ddae684c335
|
File details
Details for the file teeny_weeny-0.1.1-py3-none-any.whl.
File metadata
- Download URL: teeny_weeny-0.1.1-py3-none-any.whl
- Upload date:
- Size: 60.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.17
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7cb4bed3ace583594513b3ef7aa69dbf0407e99352a1bec4d0cd725ab9ddf5bb
|
|
| MD5 |
8df3fdce5fa75f41d51f782afae35a20
|
|
| BLAKE2b-256 |
a93eef10aa6f5ad0e7df2d3a18f7ee6f3abb2f43f90a31d1e9b4204d65157411
|