Skip to content

CLI

This page lists every command exposed by the bub CLI entry point. Commands are registered through the builtin register_cli_commands hook (src/bub/builtin/hook_impl.py); plugins may add more.

bub [OPTIONS] COMMAND [ARGS]...
Option Type Default Description
--workspace, -w TEXT current working directory Path to the workspace; sets BubFramework.workspace.
--help flag — Show help and exit.

The framework is created in bub/__main__.py, which calls BubFramework().load_hooks() and then create_cli_app(). The active framework is stored on ctx.obj.

Run one inbound ChannelMessage through BubFramework.process_inbound and print every outbound to stdout.

bub run [OPTIONS] MESSAGE
Option Type Default Description
MESSAGE (arg) TEXT required Inbound message content.
--channel TEXT cli Channel name attached to the inbound envelope.
--chat-id TEXT local Chat id attached to the inbound envelope.
--sender-id TEXT human Sender id; stored under context.sender_id.
--session-id TEXT {channel}:{chat_id} Override the session id.

Behavior notes:

  • Opens framework.running() for the duration of one turn — provide_tape_store is entered and exited around the call.
  • Outbounds are formatted as [channel:chat_id]\n<content>.
  • Streaming output is not enabled; the model hook is invoked through HookRuntime.run_model.

Start an interactive REPL backed by the cli channel.

bub chat [OPTIONS] [INITIAL_PROMPT]

Pass an optional initial message to submit it automatically, then continue chatting in the same session. Quote prompts containing spaces, for example bub chat "Explain this project".

Option Type Default Description
--chat-id TEXT local Chat id reported by the CLI channel.
--session-id TEXT none Optional explicit session id.

Behavior notes:

  • Constructs a ChannelManager with enabled_channels=["cli"] and stream_output=True, then calls manager.listen_and_run().
  • Exits with code 1 if no plugin provides a channel named cli.
  • The CLI channel uses prompt_toolkit and rich to render streamed events.

Start every enabled channel listener (Telegram, custom plugin channels, …).

bub gateway [OPTIONS]
Option Type Default Description
--enable-channel TEXT (repeatable) empty list (use BUB_ENABLED_CHANNELS) Restrict gateway to the listed channel names. Pass multiple times.
--install flag disabled Install and start the gateway as a per-user background service.
--uninstall flag disabled Stop and uninstall the per-user gateway service.

Behavior notes:

  • When --enable-channel is omitted the manager reads ChannelSettings.enabled_channels (BUB_ENABLED_CHANNELS, default all).
  • all starts every enabled non-Interface channel. When you list at least one non-Lifecycle channel explicitly, enabled Lifecycle runtimes are attached automatically. Use !name to exclude one.
  • framework.running() is held open until the manager loop exits; provide_tape_store cleanup runs on shutdown.
  • On Linux, --install writes bub-gateway.service under ${XDG_CONFIG_HOME:-~/.config}/systemd/user/, enables it for the user’s default target, and starts or restarts it. Use loginctl enable-linger separately if it must remain active after logout.
  • On Windows, --install registers and starts a current-user Bub Gateway Task Scheduler task. It runs at that user’s logon with limited privileges and restarts after failures.
  • Installation captures the current Python executable, workspace, and explicit --enable-channel values. Re-running the command replaces and restarts the existing service; do so after moving or replacing the Python environment.
  • --uninstall stops and removes the corresponding systemd user unit or Windows scheduled task. It succeeds when the service is already absent and does not require an enabled channel.
  • --install and --uninstall are mutually exclusive.

See Operate › Channels for per-channel deployment notes.

Interactively collect plugin configuration via onboard_config hooks and write the result to ~/.bub/config.yml (or whatever framework.config_file resolves to).

bub onboard [OPTIONS]
Option Type Default Description
--help flag — Show help and exit.

Behavior notes:

  • All providers follow the same flow: select a provider, enter connection details, check the connection, choose a model, then configure channels and streaming.
  • Provider labels distinguish OpenAI (official API) from OpenAI-compatible (custom URL / local server). Compatible services are saved as openai:<model> with your API base URL.
  • Hosted providers use their default endpoint and normally ask only for an API key. Compatible services, Azure, Ollama, other providers, and custom endpoints supplied by preceding hooks also prompt for a URL. Blank API keys retain a key supplied in this run for the same endpoint or use environment credentials, including OPENAI_API_KEY, BUB_API_KEY, and BUB_OPENAI_API_KEY. Environment keys are not copied into the saved configuration. A compatible server gets the SDK’s placeholder key only when no key is supplied or available from the environment.
  • Bub fetches the provider’s model list with a 10-second asynchronous timeout, then offers searchable model selection and manual entry. Blocking SDK calls may take longer. This checks access to the models endpoint; it does not test a model completion. If discovery fails, edit the URL/key, retry, or enter a model ID manually. Providers that do not support model discovery, including Azure in the current SDK, explain the limitation and proceed directly to manual entry without offering retries.
  • When the effective connection uses OpenAI OAuth, model discovery is skipped and you enter a model ID manually. Displayed default URLs are not written to the configuration. Leave the URL blank to preserve the default and OAuth routing; entering a URL explicitly saves it, even if it matches the displayed default.
  • Each plugin’s onboard_config hook receives only the configuration accumulated during this run, starting from an empty dict. Existing file contents are not merged; non-dict returns abort with TypeError.
  • The merged dict is validated through configure.validate before being written.
  • onboard is interactive. The provider labels and prompt order have changed, and connection results determine subsequent prompts. Scripts that supply a fixed sequence of answers must be updated; for unattended setup, write the configuration file directly. The bundled installers launch onboard only in interactive mode.
  • After saving a configuration with at least one channel on Linux or Windows, onboarding asks whether to install the gateway as a per-user background service. The default is no. Installation failure leaves the saved configuration intact and exits with code 1.

Exit codes:

Code Meaning
0 Config saved.
1 Validation, write, or requested gateway installation error; message printed to stderr.

Install a plugin into Bub’s managed uv project (BUB_HOME/bub-project, or ~/.bub/bub-project when BUB_HOME is unset), or sync the project when no specs are passed.

bub install [OPTIONS] [SPECS]...
Option Type Default Description
SPECS (args) one or more strings empty list Package specs: PyPI name, owner/repo[@ref], git+..., or a bub-contrib package as name@ref resolved against https://github.com/bubbuild/bub-contrib.git.
--project PATH BUB_HOME/bub-project, or ~/.bub/bub-project when BUB_HOME is unset (env: BUB_PROJECT) Path to the Bub plugin project directory.

Behavior notes:

  • Requires uv on PATH and that Bub itself runs inside a virtualenv (sys.prefix != sys.base_prefix); otherwise exits with 1.
  • Initializes the project on first use via uv init --bare --name bub-project --app and adds Bub to it as a dependency (matching the local install: editable, file://, VCS, or PyPI).
  • The default project directory is created automatically. When --project is provided explicitly, the directory must already exist.
  • With no specs, runs uv sync --active --inexact.
  • With specs, runs uv add --active <requirements>.

Exit codes mirror uv — non-zero from the underlying subprocess.run is propagated.

bub uninstall [OPTIONS] PACKAGES...
Option Type Default Description
PACKAGES (args) one or more strings required Package names as recorded in the project’s pyproject.toml.
--project PATH BUB_HOME/bub-project, or ~/.bub/bub-project when BUB_HOME is unset (env: BUB_PROJECT) Plugin project directory.

Calls uv remove --active <packages> inside --project.

bub update [OPTIONS] [PACKAGES]...
Option Type Default Description
PACKAGES (args) zero or more strings empty list Package names to upgrade; empty means all.
--project PATH BUB_HOME/bub-project, or ~/.bub/bub-project when BUB_HOME is unset (env: BUB_PROJECT) Plugin project directory.

Behavior notes:

  • No packages → uv sync --active --upgrade --inexact.
  • With packages → uv sync --active --inexact --upgrade-package <name> for each.

Top-level group for authentication subcommands.

bub login [OPTIONS] COMMAND [ARGS]...
Option Type Default Description
--help flag — Show help and exit.

Run the Codex OAuth flow to obtain OpenAI credentials, then save them under the resolved Codex home.

bub login openai [OPTIONS]
Option Type Default Description
--codex-home PATH $CODEX_HOME or ~/.codex Directory to store the resulting auth.json.
--browser / --no-browser flag --browser Open the OAuth authorize URL in the default browser.
--manual flag off Skip the local callback server and prompt for the callback URL or code.
--timeout FLOAT 300.0 OAuth wait timeout in seconds.

Behavior notes:

  • On success prints login: ok, the account id, the auth file path, and a usage hint to set BUB_MODEL=openai:<codex-model> and omit BUB_API_KEY.
  • On CodexOAuthLoginError exits with code 1.

Hidden diagnostic command that prints the hook → adapters map.

bub hooks

The command is registered with hidden=True, so it does not appear in the top-level --help listing. Output is one line per hook: hook_name: adapter1, adapter2, …. Use it to verify discovery; see Hooks › How hooks are invoked before inferring firstresult precedence from the printed order.