Skip to main content

Bunnify

PyPI version Python 3.14+ License: MIT CI

A Python bookmark manager and URL shortcut system: terminal CLI, web command palette, Chrome OpenSearch integration, and parameterized redirects.

Install

pipx is the recommended path for end users:

pipx install bunnify
pipx ensurepath   # adds ~/.local/bin to PATH if needed (restart the shell)
bunnify --version
bunnify onboard   # print bookmarks / setup / Chrome next steps

pipx installs bunnify and bunnify-server under ~/.local/bin by default (or $PIPX_BIN_DIR when set). Ensure that directory is on your PATH before running either command. Prefer the pipx apps over any checkout ./scripts/bunnify still on PATH.

The wheel installs bunnify (CLI), bunnify-server (Django server), and spotty-bunny (Spotlight-style search box; macOS needs extra macos, Windows needs extra windows). No repository checkout or uv is required at runtime.

Package on PyPI: pypi.org/project/bunnify.

After install or upgrade

pipx does not print package docs after install. Run:

bunnify onboard

That prints the ready-to-go checklist (bookmarks path, bunnify setup, Chrome/Edge, and upgrade). Same text:

bunnify --onboard

Summary of what it covers:

  1. Bookmarks at ~/.config/bunnify/bookmarks.json (required before the server starts) — bunnify setup can install the example shortcuts, or seed from bunnify.json.example
  2. bunnify setup — local on a laptop; remote for a home/always-on host
    LOCAL.md
  3. Chrome / Edge — match base_url from config.toml
    CHROME_SETUP.md
  4. Try it: bunnify gh or address-bar keyword (e.g. b gh)
  5. macOS Spotty Bunny (optional) — pipx install 'bunnify[macos]' then bunnify spotty-bunny install (LOCAL.md)
  6. Windows Spotty Bunny (optional) — pipx install 'bunnify[windows]' then bunnify spotty-bunny install (LOCAL.md)

Upgrade

Preferred:

bunnify upgrade

That prints the version/commit you are running from, the PyPI target, then the pipx app version/commit to after pipx upgrade. Use this instead of bare pipx upgrade bunnify so you can see when PATH is still a git checkout.

On macOS, bunnify upgrade also refreshes installed server and Spotty Bunny LaunchAgents when their plists are present (or run bunnify-server upgrade / bunnify spotty-bunny upgrade manually). On Windows, bunnify upgrade also refreshes an installed Spotty Bunny Scheduled Task the same way — there is no Windows equivalent of the server LaunchAgent yet, so only Spotty Bunny is refreshed.

pipx upgrade only updates ~/.local/bin/bunnify. If bunnify --version still shows a checkout SHA, PATH is hitting ./scripts/bunnify or a repo .venv. After pipx ensurepath, command -v bunnify should be ~/.local/bin/bunnify.

Bookmarks and ~/.config/bunnify/config.toml are user data — upgrades do not overwrite them. After a major server change, re-run bunnify setup only if docs or release notes say so. Setup will offer to stop a different local Bunnify build and start this CLI's build when the port is already in use.

Source and docs: github.com/the-hcma/bunnify.

Quick start

1. Bookmarks file

bunnify setup offers to install the example bookmarks when none exist yet. You can also create the file yourself from the documented example into XDG config:

mkdir -p ~/.config/bunnify
curl -fsSL https://raw.githubusercontent.com/the-hcma/bunnify/main/bunnify.json.example \
  -o ~/.config/bunnify/bookmarks.json
# edit ~/.config/bunnify/bookmarks.json with your shortcuts

See Configuration for overrides (BUNNIFY_BOOKMARKS, XDG_CONFIG_HOME).

2. Configure local or remote mode

bunnify setup

Laptop / daily machine: choose local (default). On macOS, setup installs the server LaunchAgent (com.thehcma.bunnify), verifies /health, records the port, and saves settings to ~/.config/bunnify/config.toml. Elsewhere it starts a managed background server the same way as before. Point Chrome or Edge at the same base_url (Chrome / Edge setup).

Home server / always-on host: choose remote on client devices and enter that host’s URL. Setup probes /health; if the host is unreachable it warns and asks before saving. Prefer a centralized remote install when several machines share one server — not as a laptop’s only dependency if you often go offline.

One-time override without saving: bunnify --base-url https://… shortcut.

Details: Local and remote setup.

3. Run shortcuts

bunnify              # interactive REPL (Tab completion, history)
bunnify gh           # open a shortcut in the browser
bunnify bun          # Bunnify source on GitHub
bunnify pr the-hcma/bunnify 272   # parameterized shortcut
bunnify --fzf        # fuzzy picker
bunnify --print-url gh

Unknown keys exit non-zero in direct mode (no search-engine fallback).

4. Shell completion (optional)

Tab completion for shortcut keys, outside the interactive REPL:

mkdir -p ~/.local/share/bash-completion/completions
bunnify --completion bash > ~/.local/share/bash-completion/completions/bunnify.bash

That's a bash-completion v2 user directory — no rc file edit, lazy-loaded on first Tab press in a new shell. zsh/fish aren't supported yet. The emitted script calls bunnify --list-keys at completion time, so Tab-completing shortcuts needs the server running.

source etc/bunnify-completion (from a source checkout) still works too.

Features

  • CLI / REPL — fuzzy Tab completion, fzf mode, Vim/Emacs edit keys
  • Spotty Bunny — configurable-chord search box (spotty-bunny; auto Control/Option by default, spotty-bunny hotkey to change; extra macos; login LaunchAgent via install / upgrade / uninstall)
  • macOS server LaunchAgent — local setup installs bunnify-server under launchd (bunnify-server install|status|upgrade|uninstall)
  • Web — /cmd/ command palette, /list/ browser, smart /search/
  • Chrome / Edge — OpenSearch at /opensearch.xml (setup guide)
  • Parameters — URLs with #{name} placeholders and optional defaults
  • Validation — JSON Schema on load; reserved keys h / help

Spotty Bunny (macOS)

Optional Spotlight-style search box. Hold the left (or right) copy of the chord's modifier key, then tap the other copy of the same modifier — for example, hold left Control and tap right Control. By default (auto) the modifier is chosen automatically from which keyboard is attached — see below to pin it or change it. Needs the macos extra (PyObjC).

Hotkey chord

Standard MacBook keyboards have only one physical Control key, so the dual-Control chord doesn't work on laptop-only setups — the default auto choice already accounts for that by using Option instead. Configure the chord in ~/.config/bunnify/config.toml (spotty_bunny_hotkey), or via:

bunnify spotty-bunny hotkey            # show the current choice
bunnify spotty-bunny hotkey auto       # Option on laptops with no external
                                        # keyboard, Control when one is attached
bunnify spotty-bunny hotkey control    # dual-Control (needs two Control keys)
bunnify spotty-bunny hotkey option     # dual-Option
bunnify spotty-bunny hotkey command    # dual-Command

Default (auto) keystrokes by keyboard:

Keyboard attached Chord used Keystroke
Built-in only (no external keyboard) Option Hold left Option, tap right Option (or the reverse)
External keyboard present (USB/Bluetooth) Control Hold left Control, tap right Control (or the reverse)

auto is re-checked on every periodic tap health check, so plugging in or unplugging an external keyboard switches the chord without restarting Spotty Bunny. Pinning a choice (control / option / command) always uses both copies of that modifier, regardless of what's attached — useful on an external keyboard that lacks a second Option or Command key, or if you just prefer one chord everywhere.

Install

pipx install 'bunnify[macos]'
pipx ensurepath
bunnify spotty-bunny install    # login LaunchAgent (TCC + KeepAlive)
bunnify spotty-bunny status

install grants Accessibility and Input Monitoring to the interpreter launchd will exec (typically the pipx venv Python), writes ~/Library/LaunchAgents/com.thehcma.bunnify.spotty-bunny.plist, and bootstraps it. Bare spotty-bunny (or bunnify spotty-bunny with no subcommand) still runs in the foreground for debugging.

Upgrade

bunnify upgrade                 # pipx package; on macOS refreshes LaunchAgents
bunnify spotty-bunny upgrade    # manual plist bounce when needed

On macOS, bunnify upgrade rewrites both LaunchAgents when installed. Use bunnify spotty-bunny upgrade only when you need to refresh Spotty without upgrading the pipx package.

Uninstall

bunnify spotty-bunny uninstall

That boots the agent out, removes the plist, and stops a leftover overlay process. Bookmarks and config.toml are unchanged. Right-click the bunny icon for Check for Updates (forces an immediate PyPI check, skipping the daily cache), Install (when the LaunchAgent is missing), Quit, Uninstall, and (when installed and either a newer PyPI release is out or this running overlay predates what's actually installed) Upgrade. An up-arrow badge on the icon and an About line mark either case — a newer PyPI release (checked at most once a day) or this process simply running stale bits after a local upgrade; both clear once Upgrade restarts the overlay.

Left-click the bunny for About: bookmarks file, GitHub repo when that file lives in a GitHub checkout, and whether the CLI is talking to a local or remote server (with its URL).

Details: Local and remote setup.

Spotty Bunny (Windows)

Optional Spotlight-style search box, same overlay behavior as macOS. Needs the windows extra (pywin32).

Hotkey chord

Only the dual-Control chord actually works on Windows today: hold left Control, tap right Control (or the reverse). auto and control both resolve to it; option and command fall back to Control with a warning logged, rather than inventing an Alt or Windows-key chord.

bunnify spotty-bunny hotkey            # show the current choice
bunnify spotty-bunny hotkey control    # dual-Control (the only chord that works)

Install

pipx install 'bunnify[windows]'
pipx ensurepath
bunnify spotty-bunny install    # Scheduled Task (LogonTrigger + RestartOnFailure)
bunnify spotty-bunny status

There is no TCC-style permission step on Windows — install registers a Scheduled Task named "Bunnify Spotty Bunny", runs it once, and waits for the overlay to come up. Bare spotty-bunny (or bunnify spotty-bunny with no subcommand) still runs in the foreground for debugging.

Upgrade

bunnify upgrade                 # pipx package; also refreshes an installed task
bunnify spotty-bunny upgrade    # re-register the task for the current binary

bunnify upgrade refreshes an already-installed Scheduled Task automatically after the pipx package upgrade (skip this with bunnify spotty-bunny upgrade if you only need to re-register the task by itself). Either way, a failed upgrade restores the previous task configuration when one existed (or removes the non-functional registration when it didn't) rather than silently leaving a broken task behind.

Uninstall

bunnify spotty-bunny uninstall

That deletes the Scheduled Task and stops a leftover overlay process. Bookmarks and config.toml are unchanged. The right-click menu (Check for Updates, Install/Uninstall/Upgrade, Quit) and left-click-for-About behavior are the same as macOS's.

WH_KEYBOARD_LL, the low-level keyboard hook Spotty Bunny uses to detect the chord, is a known heuristic trigger for antivirus software and Windows SmartScreen on unsigned pipx-installed binaries — the hook is listen-only (it always calls CallNextHookEx, so keystrokes are never intercepted or altered, only observed to detect the chord), but the first run may still show a SmartScreen prompt. Details: Local and remote setup.

Server lifecycle

Installed users manage the server with bunnify-server:

bunnify-server --help
bunnify-server install --port 8000   # macOS: server LaunchAgent only
bunnify-server status
bunnify-server upgrade               # rewrite plist for current binary
# Foreground (systemd, debugging):
bunnify-server --foreground --noninteractive --port 8000
# Background managed daemon (non-macOS or manual):
bunnify-server --port 8000 --noninteractive --pid-dir ~/.local/share/bunnify/run
bunnify-server --stop --pid-dir ~/.local/share/bunnify/run
curl --max-time 2 http://127.0.0.1:8000/health

Local setup: bunnify setup (macOS installs the server LaunchAgent; other platforms start a managed background server). Stop with:

bunnify stop    # macOS: boot out server LaunchAgent; else stop managed server

That prints the URL and runtime directory before stopping. Check the current mode, target URL, and reachability at any time:

bunnify status

Details: Local and remote setup.

Linux production: systemd user service via setup-service from repository-helpers.

macOS: prefer bunnify setup (local) or the commands above. Manual plist copy is optional — see LaunchAgent example and LOCAL.md.

Web usage

With the server running (default http://127.0.0.1:8000 after setup):

URL Purpose
/cmd/ Command palette (recommended)
/search/?q=pr+12345 Smart search
/list/ Browse all bookmarks
/<key>/ Direct redirect
/opensearch.xml Chrome search engine descriptor

Bookmarks format

{
  "gh": {
    "description": "GitHub",
    "url": "https://github.com/"
  },
  "pr": {
    "description": "Pull request",
    "url": "https://github.com/#{repo}/pull/#{pr_number}",
    "defaults": { "repo": "org/repo" }
  }
}

Required fields: description, url. Placeholders use #{parameter_name}. Reload after edits: the server watches the JSON file, or run load_bookmarks in a development checkout.

Development checkout

Contributors clone the repo and use uv — separate from the pipx path above.

git clone https://github.com/the-hcma/bunnify.git
cd bunnify
uv sync
uv run python manage.py migrate

mkdir -p ~/.config/bunnify
cp bunnify.json.example ~/.config/bunnify/bookmarks.json

./scripts/bunnify setup
./scripts/bunnify-server --console --log-level DEBUG   # optional
./test_bunnify

Full guidelines: CONTRIBUTING.md. Quality gates: ./scripts/checks.

Wrappers under ./scripts/ prefer uv run when uv is on PATH, otherwise the checkout .venv (same entry points systemd uses on service hosts).

Documentation

Doc Audience
CONFIG.md XDG paths and environment variables
LOCAL.md Local vs remote setup, ports, Spotty Bunny
SYSTEMD.md Linux user service
CHROME_SETUP.md Browser search engine
QUICK_REFERENCE.md Cheat sheet
RELEASING.md Maintainers: PyPI releases

Troubleshooting

Server won't start

bunnify-server --console --log-level DEBUG
# or in a checkout: ./scripts/bunnify-server --console

Bookmarks missing

ls -l ~/.config/bunnify/bookmarks.json
# run `bunnify setup` (offers the example), or copy bunnify.json.example

CLI can't reach server

bunnify setup
curl -sf "$(grep '^base_url' ~/.config/bunnify/config.toml | sed -E 's/^base_url = "(.*)"$/\1/')/health"

Stale managed process

bunnify-server --stop --pid-dir ~/.local/share/bunnify/run

Releasing

Maintainers: docs/RELEASING.md (Release Please + PyPI).

License

MIT © 2026 Henrique Andrade (GitHub's thehcma) — see LICENSE.

Metadata

Release files for bunnify 0.15.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for bunnify 0.15.0
File Size Uploaded
bunnify-0.15.0.tar.gz 284.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for bunnify 0.15.0
File Interpreter ABI Platform
bunnify-0.15.0-py3-none-any.whl Python 3 none any Details

Total release size: 614.8 kB

Release files / bunnify-0.15.0.tar.gz

Download URL bunnify-0.15.0.tar.gz
Size 284.8 kB
Tags Source
SHA-256 checksum
How to use checksums
81db4e649107cf3c81b4dae334204fcaedccab80fd4a1f1d8c39b7a06913a54b
BLAKE2b-256 checksum
How to use checksums
697160934f5ef3536d08bfd053bb8d5485c3fea03cbef072784be15db6cc384e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 19, 2026.

Transparency log

Release files / bunnify-0.15.0-py3-none-any.whl

Download URL bunnify-0.15.0-py3-none-any.whl
Size 330.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1be210e6e8b004b30adf1e2000489dba027ff342c6669e5eb534a45d14921e12
BLAKE2b-256 checksum
How to use checksums
ac8d39a955e8e5822b27ac3ac7aa70069131c81d55f182a0a5f37d93d6745347
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 19, 2026.

Transparency log

Release history Release notifications | RSS feed

1.1.2

2 release files

1.1.1

2 release files

1.1.0

2 release files

1.0.0

2 release files

This release

0.15.0 This release

2 release files

0.14.0

2 release files

0.13.1

2 release files

0.13.0

2 release files

0.11.3

2 release files

0.11.2

2 release files

0.11.1

2 release files

0.11.0

2 release files

0.10.0

2 release files

0.9.2

2 release files

0.9.1

2 release files

0.9.0

2 release files

0.8.3

2 release files

0.8.1

2 release files

0.8.0

2 release files

0.7.1

2 release files

0.7.0

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page