Skip to content

Packaging and distribution

When you build custom tools, channel plugins, or workflow-specific skills on top of Bub, or even want to ship a branded CLI of your own, you can package them as standard Python distributions (wheels) and publish them to PyPI or a private index for your team and users to install.

In Bub, packaging and distribution usually falls into one of three shapes:

Shape Deliverable When to use it
Capability extension Plugin entry point + skill namespace Contribute custom tools, long-running services, or specialized skills to the existing Bub ecosystem
Dedicated business CLI Your own command script (for example my-bub) Wrap Bub as an agent for one business scenario, pinning the workspace or baking in default settings
All-in-one suite Own commands + plugins + skills Deliver a complete vertical-domain agent that works as soon as users install it

A distribution can provide its own command name and call Bub’s CLI entry point internally. This lets you give the agent its own brand or fix its default behavior:

# src/my_bub/cli.py
from pathlib import Path
import os
from bub.__main__ import main as bub_main


def main() -> None:
    # Optional: pin a default workspace. Bub's workspace defaults to the current
    # directory and has no BUB_* environment variable, so change directory before
    # calling bub_main(); a user-supplied --workspace still overrides it.
    if workspace := os.getenv("MY_BUB_WORKSPACE"):
        os.chdir(Path(workspace).expanduser())

    # Call Bub's CLI dispatcher; chat, run, gateway, and the other subcommands work unchanged
    bub_main()

Register the command in pyproject.toml with [project.scripts]:

[project.scripts]
my-bub = "my_bub.cli:main"

After installation, users can run my-bub chat, my-bub gateway, or my-bub run directly. Bub’s Typer CLI mounts every native subcommand, and standard arguments such as --workspace keep working.

A single wheel can provide plugin entry points, a standard skill namespace package, and custom CLI commands together:

  • Directorymy-bub/
    • pyproject.toml
    • Directorysrc/
      • Directorymy_bub/
        • __init__.py
        • cli.py # Your CLI entry point
        • plugin.py # Plugin and hook implementations
        • tools.py # Custom tools
      • Directoryskills/ # Skill namespace package (never add __init__.py)
        • Directoryrepo-reviewer/
          • SKILL.md
          • Directoryreferences/
            • guidelines.md

Set up the entry points and Hatch build includes in pyproject.toml:

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "my-bub"
version = "0.1.0"
description = "My Custom Bub Agent Distribution"
requires-python = ">=3.12"
dependencies = [
    "bub[app]>=0.6.0",         # Required for the CLI, plugin loading, and the skill runtime
]

[project.scripts]
my-bub = "my_bub.cli:main"

[project.entry-points."bub"]
my_plugin = "my_bub.plugin:plugin"

[tool.hatch.build.targets.wheel]
packages = ["src/my_bub", "src/skills"]
  1. Dependencies: Always declare bub[app]. Since 0.6.0 the core bub package holds only the lightweight kernel; the CLI, plugin loading, and the skill runtime all come from the app extra, following the package restructuring described in the 0.6 migration notes. Declare third-party libraries your plugins depend on (such as httpx or pydantic) in the distribution’s dependencies as well.
  2. Entry point format: The entry point group must be "bub". See the plugin registration rules for the exact syntax.
  3. Packaging scope: Explicitly include "src/skills" in packages under [tool.hatch.build.targets.wheel] so skill assets ship in the wheel and install into site-packages/skills/.

uv builds a standard wheel and source distribution quickly:

uv build

The artifacts land in dist/ (for example my_bub-0.1.0-py3-none-any.whl). Publish them to PyPI, or distribute them inside your organization through a private index.

For downstream users:

  • Install as a global CLI: uv tool install my-bub.
  • Install as a managed plugin: to install the package into the separate project or container environment that Bub manages, use bub install.

Before publishing publicly or releasing to production, always verify the package in a fresh virtual environment.

  1. Create an isolated environment and install the wheel:

    uv venv .test-env && source .test-env/bin/activate
    uv pip install dist/*.whl

    Always install from the built wheel rather than running from the development source directory.

  2. Verify plugin and hook loading:

    my-bub hooks

    Check that the output lists your plugin identifier, confirming the entry point loaded with no deprecation warnings or import errors.

  3. Verify skill discovery:

    my-bub run ",skill"

    Confirm that the distributed skill (such as repo-reviewer) appears in the discovered list, then run my-bub run ",skill name=repo-reviewer" to check that variable interpolation and body expansion work.

  4. Verify your command and the interaction path:

    my-bub run "Test model and custom tool calls"
    my-bub chat

    Confirm model interaction, custom tool execution, internal command dispatch, and session history persistence.

  5. Verify the gateway and host integration (if applicable): If the distribution provides channel extensions or is embedded in a host system, follow Deploy and Reuse the Bub app to wire it into the host service, and verify concurrency, stream closure, and shutdown cleanup.