Skip to main content

A Git-backed JSON 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 zsh for 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.json and 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.json schema and integrity
  • data/categories.json schema and integrity
  • data/tags.json schema
  • 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:

  1. Installs the package
  2. Runs pytest
  3. Runs ruff check .
  4. 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 bookmark and bookmark support 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 bookmarks
  • bm edit — edit bookmark fields
  • bm delete — remove a bookmark
  • bm import — import from browser bookmarks or Markdown
  • bm export — export to browser-importable format
  • Sync / conflict resolution
  • Browser extension

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

teeny_weeny-0.2.0.tar.gz (42.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

teeny_weeny-0.2.0-py3-none-any.whl (55.0 kB view details)

Uploaded Python 3

File details

Details for the file teeny_weeny-0.2.0.tar.gz.

File metadata

  • Download URL: teeny_weeny-0.2.0.tar.gz
  • Upload date:
  • Size: 42.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for teeny_weeny-0.2.0.tar.gz
Algorithm Hash digest
SHA256 70e2d225c60537d01aac35f30197700b823fc8f3e87e7d1f1d0ed6bd71b009ef
MD5 755c74cb70230f6b748540706bf9bebb
BLAKE2b-256 4bd8bc384ae3f776321a0e097548c80133b07a19dd54201034162aa54bbc8dc7

See more details on using hashes here.

Provenance

The following attestation bundles were made for teeny_weeny-0.2.0.tar.gz:

Publisher: release.yml on Mohammadbjl/Bookmark

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file teeny_weeny-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: teeny_weeny-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 55.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for teeny_weeny-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8cb789fd03a48a94c2a471fd5a47de192faf158b6eb8733e37d6fd21acc0560b
MD5 2d226d7f7bee8854ffc6241a1cb8801f
BLAKE2b-256 f9046e31e9eb2be7e4f4764b8015ae6d59e9d66f8c97399a947d44b7b5f2a659

See more details on using hashes here.

Provenance

The following attestation bundles were made for teeny_weeny-0.2.0-py3-none-any.whl:

Publisher: release.yml on Mohammadbjl/Bookmark

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page