SkillAgentSearch skills...

Shelfctl

PDF/EPUB library CLI/TUI backed by GitHub Release assets (Git LFS alternative). On-demand per-file downloads, metadata catalog, migrate/split bloated repos.

Install / Use

/learn @blackwell-systems/Shelfctl

README

shelfctl

Blackwell Systems™ CI Go Report Card License: MIT Buy Me A Coffee

<p align="center"> <img src="assets/shelby-padded.png" alt="Shelby the Shelf - shelfctl mascot holding a magnifying glass"> </p> <p align="center"> <em>Meet Shelby, your friendly library assistant.</em> </p> <p align="center"> <img src="assets/shelf.png" alt="shelfctl architecture" width="800"> </p> <p align="center"><strong>Organize the PDFs and books you already have scattered across GitHub.</strong></p> <p align="center"> <img src="assets/tui_demo.gif" alt="shelfctl TUI demo" width="800"> </p>

If you use GitHub, you've probably hit this: one monolithic "books" repo with hundreds of PDFs, or files scattered across random repos and gists. Eventually you hit GitHub's 100MB limit, or you bolt on Git LFS and discover it's expensive and annoying for a personal library.

Once PDFs land in git history, every clone stays heavy forever. Even after you delete the files, git history never forgets.

shelfctl solves this by storing files as GitHub Release assets (not git commits) and keeping only metadata in a simple catalog.yml. That means you can split a bloated repo into topic-based shelves, migrate books out of existing repos, and search + download on demand (without moving your library to a new service).

[!WARNING] Deleting a PDF from a git repo doesn't remove it from git history. Clones still carry the weight. shelfctl avoids this entirely by storing documents as Release assets (only metadata is versioned).

Your GitHub account already gives you reliable distribution and storage primitives. shelfctl turns them into a library:

  • Release assets for the PDFs/EPUBs
  • catalog.yml for searchable metadata
  • one repo per shelf (shelf-programming, shelf-history, …)
  • Migration tools to split bloated repos and reorganize existing collections

[!TIP] Already have PDFs committed in git? shelfctl can scan and migrate them into shelves without manual re-uploads:

shelfctl migrate scan --source you/old-books-repo > queue.txt

Three ways to browse your library:

  • Interactive TUI - visual browser with keyboard navigation and search
  • Static HTML index - web-based viewer with tag filters and search (works offline)
  • Scriptable CLI - pipe, filter, automate, and integrate with shell workflows

Your library stays portable, backed by normal git repos. Free by default (only pay if you choose Git LFS or exceed GitHub plan limits).


30-Second Quickstart

# 1. Set up authentication (create token at github.com/settings/tokens)
export GITHUB_TOKEN=ghp_your_token_here

# 2. Create your first shelf
shelfctl init --repo shelf-books --name books --create-repo --owner YOUR_USERNAME

# 3. Add a book
shelfctl shelve ~/Downloads/book.pdf --shelf books

# 4. Browse your library
shelfctl browse

That's it! Your book is now stored as a GitHub Release asset with searchable metadata.


Why not commit PDFs?

The tradeoff:

| Approach | Git History | Clone Weight | Per-File Download | Cost | |----------|-------------|--------------|-------------------|------| | Git commit | Bloats forever | Heavy (even after deleting files) | Possible, but awkward | Free | | Git LFS | Clean | Still heavier than needed | Possible, but awkward | Paid storage/bandwidth | | Release asset | Clean | Light | Yes (native) | Free* |

*Free by default. You only pay if you choose LFS or exceed GitHub plan limits.

Why Release assets:

  • Git history stays clean (only metadata is versioned)
  • Documents live outside version control entirely
  • Download individual files on-demand from GitHub's CDN

On-demand downloads (no cloning)

Fetch a single book without cloning a repo or pulling a whole archive. shelfctl open <book-id> downloads only that file from GitHub's CDN and opens it. Your library can be huge, but you only download what you actually read.

Annotations and highlights sync

When you annotate or highlight PDFs in your reader, those changes are saved to your local cache. Use shelfctl sync to upload your annotated version back to GitHub (replaces the original, no versioning). From the TUI, press s to sync selected books. Your annotations stay with the book and sync across machines.


<p align="center"> <img src="assets/shelf3.png" alt="shelfctl features" width="800"> </p>

Features

Release assets backend (no git history bloat)

Files are stored as GitHub Release assets, not git commits. Your repository stays lightweight and git history never bloats.

On-demand open (per-file download)

Download and open a single book without cloning the entire repository. Your library can be huge, but you only fetch what you need.

Migration tools: scan → split → migrate

Built-in tools to scan existing repos, reorganize into topic-based shelves, and migrate files automatically. No manual re-uploads required.

Static HTML index

Generate a web-based library viewer with cover thumbnails, tag filters, and live search. Works offline in any browser without running shelfctl.

TUI + CLI

shelfctl (no arguments) launches an interactive visual hub. shelfctl --help lists all CLI commands. Every command supports --json output and --no-interactive for scripting and automation — the two modes share the same feature set.

Reusable TUI components

shelfctl uses five production-ready Bubble Tea components that have been extracted to standalone packages: Base Picker (eliminates picker boilerplate), Multi-Select (checkbox wrapper for any list), Miller Columns (hierarchical navigation layout), Carousel (peeking card layout), and Command Palette (fuzzy-search action overlay). Available as separate modules: bubbletea-picker, bubbletea-multiselect, bubbletea-millercolumns, bubbletea-carousel, bubbletea-commandpalette. See docs/development/components.md for details.


How it works

  • One repo per topic shelf Create shelf repos like shelf-programming, shelf-history, etc.

  • Books live in Releases, not git history PDFs/EPUBs are uploaded as GitHub Release assets (not committed to the repo).

  • catalog.yml is the source of truth Each shelf repo contains a catalog.yml that stores searchable metadata and maps book IDs to release assets. Only metadata is versioned; the actual documents live outside git history.

  • On-demand, per-book downloads shelfctl open <book-id> downloads only that one file from GitHub's CDN and opens it.

  • Full lifecycle management shelfctl supports the workflow end-to-end: add, get, open, migrate, split, and more.


Core Concepts

Architecture: Shelf → Repo → Release → catalog.yml + Assets

  • Shelf: A GitHub repository (e.g. shelf-programming)
  • Release: A storage container tag (default: "library", NOT a version release)
  • Assets: Your PDF/EPUB files attached to the release
  • catalog.yml: Searchable metadata file (tracked in Git) mapping book IDs to assets

Your books live as GitHub Release assets (outside Git history). Only metadata is versioned. This keeps repos lightweight and enables per-file on-demand downloads.


Prerequisites

  • GitHub account with a personal access token
  • Go 1.21+ (only if using go install or building from source)
<p align="center"> <img src="assets/shelby5.png" alt="Shelby sitting at a computer installing shelfctl" width="600"> </p>

Install

Homebrew (macOS/Linux):

brew install blackwell-systems/tap/shelfctl

Download pre-built binary:

Download the appropriate binary for your platform from the releases page, extract the archive, and run:

tar -xzf shelfctl_*_Darwin_arm64.tar.gz  # or your platform
./shelfctl

Optionally move to your PATH: mv shelfctl /usr/local/bin/

Using Go:

go install github.com/blackwell-systems/shelfctl/cmd/shelfctl@latest

This downloads the module at the latest version, builds shelfctl, and places it in $(go env GOPATH)/bin (or $GOBIN if set).

Build from source:

git clone https://github.com/blackwell-systems/shelfctl
cd shelfctl
make build

Authentication

shelfctl authenticates using a GitHub personal access token (PAT). Set GITHUB_TOKEN in your environment.

Classic PAT scopes:

  • repo - for private shelves
  • public_repo - for public-only shelves

Fine-grained PAT permissions: Grant BOTH permissions on the shelf repos you manage:

  • Contents (Read/Write) — for catalog.yml and README.md
  • Releases (Read/Write) — for uploading/downloading book files

Note: GitHub CLI (gh) is not required - shelfctl uses the GitHub REST API directly.

Setup Options

Option A: Using gh CLI (optional convenience)

If you already have GitHub CLI

Related Skills

View on GitHub
GitHub Stars11
CategoryContent
Updated15d ago
Forks0

Languages

Go

Security Score

80/100

Audited on Mar 23, 2026

No findings