Skip to content

the-hcma/bunnify

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

163 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Bunnify 🐰

A powerful Python-based bookmark manager and URL shortcut system with advanced command palette, Chrome integration, and real-time GitHub Copilot code reviews.

Prerequisites

  • Python 3.14+
  • uv - Fast Python package manager
# Install uv
curl -LsSf https://astral.sh/uv/install.sh | sh

Features

Core Functionality

  • Smart Search: Type "pr 12345" or "g search terms" directly in your browser
  • Dynamic URL Redirects: Navigate to /<key>/ to be redirected to the bookmark's URL
  • Parameter Substitution: Supports URLs with placeholders (e.g., #{pr_number}, #{search_terms})
  • Multi-Parameter Support: Bookmarks can accept multiple parameters with optional defaults
  • JSON Schema Validation: Validates the bookmark JSON file before loading
  • Web Interface: Browse all bookmarks with search and filtering

Command Palette (/cmd/)

  • Tab Completion: Auto-complete shortcuts and commands
  • Command History: Navigate previous commands with ↑/↓ arrows
  • Filtered History: Type a prefix and use arrows to filter history
  • Reverse Search (Ctrl-R): Bash-style interactive history search
  • Special Commands: Built-in shortcuts like h (help) to list all bookmarks
  • Autocomplete Suggestions: Real-time suggestions as you type
  • Opens in New Tab: All commands open in new tabs for quick workflows

Chrome Integration

  • OpenSearch API: Add Bunnify as a search engine in Chrome
  • Address Bar Suggestions: Auto-complete suggestions in Chrome's omnibox
  • Seamless Navigation: Type shortcuts directly in the address bar

GitHub Copilot Integration

  • PR Code Reviews: Use the rpr shortcut to request Copilot reviews on PRs
  • Streaming Responses: Real-time progress updates during review generation
  • Private Reviews: Reviews displayed in-app without public PR comments

Infrastructure

  • Dual-Stack Networking: IPv4 and IPv6 support (accessible via 127.0.0.1, [::1], or localhost)
  • Comprehensive Logging: Detailed logs with PID/function/line numbers to /tmp/bunnify.log
  • File Watching: Auto-reload bookmarks when JSON file changes
  • Daemonization: Background process management with proper cleanup

Quick Start

1. Clone and Setup

# Clone the repository
git clone https://github.com/thehcma/bunnify.git
cd bunnify

# Install dependencies with uv
uv sync

# Run migrations
uv run python manage.py migrate

# Create your bookmarks file
mkdir -p ~/work/bunnify
cp bunnify.json.example ~/work/bunnify/bunnify.json
# Edit ~/work/bunnify/bunnify.json with your bookmarks

# Load bookmarks
uv run python manage.py load_bookmarks

2. Start the Server

Always use the bunnify-server script to ensure proper setup:

./bunnify-server

This will:

  • Start the server on port 8000 (dual-stack IPv4/IPv6 binding)
  • Start the bookmark file watcher for auto-reload
  • Daemonize both processes
  • Show URLs for access

Logging options:

./bunnify-server --console          # Log to console instead of file
./bunnify-server --log-level DEBUG  # Change log level
./bunnify-server --help            # Show all options

Note: The bunnify-server script uses dual-stack binding ([::]:8000), making the server accessible via IPv4, IPv6, and localhost.

3. Access Bunnify

The server is accessible at:

  • http://127.0.0.1:8000/ (IPv4)
  • http://[::1]:8000/ (IPv6)
  • http://localhost:8000/ (auto)

4. Chrome Browser Integration

Set up Bunnify as a search engine in Chrome:

  1. Visit http://127.0.0.1:8000/ (or http://[::1]:8000/ for IPv6) while the server is running
  2. Go to Chrome Settings β†’ Search engine β†’ Manage search engines
  3. Find "Bunnify" (added automatically via OpenSearch) or add manually:
    • Search engine: Bunnify
    • Shortcut: s (or any letter you prefer)
    • URL (IPv4): http://127.0.0.1:8000/search/?q=%s
    • URL (IPv6): http://[::1]:8000/search/?q=%s
    • URL (localhost): http://localhost:8000/search/?q=%s
  4. Save

Note: Choose the URL that matches how you're running the server:

  • Use IPv4 (127.0.0.1) if running with 127.0.0.1:8000
  • Use IPv6 ([::1]) if you prefer IPv6-only access
  • Use localhost if running with [::]:8000 (dual-stack) - Chrome will auto-select

Optional: Set as Default Search Engine

  • Click the three dots next to "Bunnify" and select "Make default"
  • Now you can type bookmarks directly without any prefix!

5. Persistent Bunnify Service (Linux)

Use the provided setup script instead of manual systemd steps:

./scripts/setup-service

To verify configuration and service health:

./scripts/setup-service --status

For live logs:

journalctl --user -u bunnify.service -f

Usage

Command Palette (Recommended)

Visit http://127.0.0.1:8000/cmd/ for the enhanced command palette:

Features:

  • Type to filter shortcuts with auto-complete
  • Tab to complete suggestions
  • ↑/↓ to navigate command history (with prefix filtering)
  • Ctrl-R for bash-style reverse search through history
  • Enter to execute (opens in new tab)
  • Esc to cancel

Examples:

  • Type pr then ↑ to see recent PR commands
  • Type pr and ↑ to cycle through filtered history
  • Press Ctrl-R and type 12345 to find commands with that PR number

Browser Address Bar (with Chrome Integration)

Type in Chrome's address bar:

  • s pr 12345 β†’ Opens PR #12345
  • s g python tutorial β†’ Google search for "python tutorial"
  • s vault β†’ Opens Vault
  • s h β†’ Shows all bookmarks

Direct URL Access

Simple redirects:

  • http://127.0.0.1:8000/c/ β†’ Google Calendar
  • http://127.0.0.1:8000/vault/ β†’ Vault

Parameterized redirects:

  • http://127.0.0.1:8000/pr/?pr_id=12345 β†’ PR #12345
  • http://127.0.0.1:8000/g/?search_terms=python+tutorial β†’ Google search

Special endpoints:

  • http://127.0.0.1:8000/list/ β†’ Browse all bookmarks
  • http://127.0.0.1:8000/cmd/ β†’ Command palette
  • http://127.0.0.1:8000/review-pr/?pr=12345 β†’ Request Copilot review

JSON File Format

The application expects a JSON file with the following structure:

{
    "key": {
        "description": "Description of the bookmark",
        "url": "https://example.com/path",
        "old-url": "https://old-url.com/path"  // optional
    }
}

Parameterized URLs

URLs can contain placeholders in the format #{parameter_name}:

Single Parameter:

{
    "g": {
        "description": "Google search",
        "url": "https://www.google.com/search?q=#{search_terms}"
    }
}

Usage: g python tutorial β†’ https://www.google.com/search?q=python+tutorial

Multiple Parameters with Defaults:

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

Usage:

  • pr 12345 β†’ Uses default repo β†’ https://github.com/your-org/your-repo/pull/12345
  • pr 12345 Shopify/shopify-build β†’ Overrides default β†’ https://github.com/Shopify/shopify-build/pull/12345

Parameter Order: Required parameters (no defaults) are mapped first, then optional parameters (with defaults).

Project Structure

bunnify/
β”œβ”€β”€ bookmarks/
β”‚   β”œβ”€β”€ management/
β”‚   β”‚   └── commands/
β”‚   β”‚       └── load_bookmarks.py    # Command to load JSON data
β”‚   β”œβ”€β”€ templates/
β”‚   β”‚   └── bookmarks/
β”‚   β”‚       β”œβ”€β”€ base.html            # Base template
β”‚   β”‚       β”œβ”€β”€ index.html           # Home page
β”‚   β”‚       β”œβ”€β”€ list.html            # Bookmark list
β”‚   β”‚       └── opensearch.xml       # OpenSearch descriptor
β”‚   β”œβ”€β”€ models.py                    # Bookmark model
β”‚   β”œβ”€β”€ views.py                     # View logic (includes search_redirect)
β”‚   └── urls.py                      # URL routing
β”œβ”€β”€ bunnify/
β”‚   β”œβ”€β”€ settings.py                  # Application settings
β”‚   └── urls.py                      # Main URL config
β”œβ”€β”€ .venv/                           # Virtual environment (managed by uv)
β”œβ”€β”€ manage.py                        # Management script
└── pyproject.toml                   # Project dependencies

Schema Validation

The load_bookmarks command validates the JSON file against a schema that ensures:

  • All keys match the pattern ^[a-zA-Z0-9_]+$
  • Each bookmark has required fields: description and url
  • Optional fields: old-url or oldurl
  • Reserved keywords "h" and "help" are blocked and will cause an error

API Endpoints

  • GET / - Home page with usage instructions
  • GET /search/?q=<query> - Smart search endpoint (e.g., "pr 12345")
  • GET /list/ - List all bookmarks with search
  • GET /<key>/ - Redirect to bookmark URL
    • With parameters: GET /<key>/?param1=value1&param2=value2
  • GET /opensearch.xml - OpenSearch descriptor for browser integration

Reserved Keywords

The following keywords are reserved and cannot be used as bookmark keys:

  • h - Shows all bookmarks (help shortcut)
  • help - Shows all bookmarks (help shortcut)

Development

Running Tests

The project includes comprehensive smoke tests that verify core functionality.

Run all tests:

./test_bunnify

Run specific test suite:

# Run only smoke tests
./test_bunnify bookmarks.tests.SmokeTests

# Run with verbose output
./test_bunnify -v 2

# Run a specific test
./test_bunnify bookmarks.tests.SmokeTests.test_search_with_parameter

Test coverage includes:

  • Page loading (index, list, command palette, OpenSearch XML)
  • Search redirects with/without parameters
  • Parameter substitution in URLs
  • Direct bookmark redirects
  • Help command functionality
  • API suggestions endpoint
  • Model methods and ordering
  • Error handling (404, 400)

Creating a Superuser

uv run python manage.py createsuperuser

Then access the admin interface at http://127.0.0.1:8000/admin/

Reloading Bookmarks

To reload bookmarks after updating your JSON file:

uv run python manage.py load_bookmarks

This will clear existing bookmarks and load fresh data.

Technologies Used

  • Python web stack: ASGI/WSGI app with URL routing and templates
  • jsonschema: JSON validation
  • SQLite: Database (default storage)
  • Python 3.14: Programming language with type hints
  • uv: Fast Python package manager
  • pathlib: Modern file path handling
  • OpenSearch: Browser integration protocol
  • localStorage: Client-side command history
  • Streaming responses: Real-time progress updates

Project Structure

bunnify/
β”œβ”€β”€ bookmarks/              # Core application logic
β”‚   β”œβ”€β”€ management/
β”‚   β”‚   └── commands/      # Management commands
β”‚   β”‚       β”œβ”€β”€ load_bookmarks.py    # Load bookmarks from JSON
β”‚   β”‚       └── watch_bookmarks.py   # Auto-reload on file changes
β”‚   β”œβ”€β”€ templates/         # HTML templates
β”‚   β”‚   └── bookmarks/
β”‚   β”‚       β”œβ”€β”€ cmd.html              # Command palette
β”‚   β”‚       β”œβ”€β”€ list.html             # Browse bookmarks
β”‚   β”‚       β”œβ”€β”€ opensearch.xml        # Chrome integration
β”‚   β”‚       └── copilot_review.html   # Copilot review UI
β”‚   β”œβ”€β”€ models.py          # Bookmark model
β”‚   β”œβ”€β”€ views.py           # View functions
β”‚   └── urls.py            # URL routing
β”œβ”€β”€ bunnify/               # Main configuration directory
β”‚   β”œβ”€β”€ settings.py        # Configuration with logging
β”‚   └── urls.py            # Root URL configuration
β”œβ”€β”€ scripts/               # Helper scripts
β”‚   β”œβ”€β”€ checks             # Local preflight checks (format/lint/tests)
β”‚   β”œβ”€β”€ setup-service      # Systemd user service setup/status helper
β”‚   └── dev/start-development  # Session bootstrap for worktree/dev setup
β”œβ”€β”€ manage.py              # Management script
β”œβ”€β”€ bunnify-server         # Server startup + watcher script
β”œβ”€β”€ requirements.txt       # Python dependencies
└── bunnify.json.example   # Example bookmark configuration

Contributing

Contributions are welcome! Please see CONTRIBUTING.md for guidelines.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Author

thehcma - GitHub

Acknowledgments

  • Built with modern Python features
  • Inspired by browser bookmark management needs
  • Enhanced with GitHub Copilot integration for code reviews

Tips & Tricks

  1. Quick Access: Set Bunnify as your default search engine for the fastest access
  2. Discover Bookmarks: Type h to quickly see all available shortcuts
  3. Parameterized Shortcuts: For frequently used parameterized bookmarks (like pr), you can create individual Chrome search engines for even faster access
  4. Auto-start: Run scripts/setup-service to configure Bunnify as a persistent systemd service.

Persistent Background Service

For production-like use, you should run Bunnify as a systemd user service. This ensures it starts on boot and restarts automatically if it crashes.

Automated Setup

We provide a script to automate the systemd configuration and enable lingering:

./scripts/setup-service

Verifying Configuration

You can verify that everything is correctly configured using the --status flag:

./scripts/setup-service --status

Manual Verification

You can check the service status with:

systemctl --user status bunnify.service

Lingering

To ensure the service runs even when you are not logged in, lingering must be enabled (the setup script does this for you):

loginctl enable-linger $(whoami)

Troubleshooting

Server won't start

# Make sure you're in the right directory
cd ~/work/ai/bunnify

# Use the bunnify-server script
./bunnify-server

Bookmarks not loading

# Check if the JSON file exists and is valid
cat ~/work/bunnify/bunnify.json

# Reload bookmarks
uv run python manage.py load_bookmarks

Chrome not detecting Bunnify

  1. Make sure the server is running at http://127.0.0.1:8000/
  2. Visit the homepage to trigger OpenSearch detection
  3. Manually add the search engine with URL: http://127.0.0.1:8000/search/?q=%s

About

🐰 A powerful bookmark manager with command palette, Chrome integration, inspired by Meta's bunnylol.

Resources

Contributing

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages