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]...
OptionTypeDefaultDescription
--workspace, -wTEXTcurrent working directoryPath to the workspace; sets BubFramework.workspace.
--helpflag—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
OptionTypeDefaultDescription
MESSAGE (arg)TEXTrequiredInbound message content.
--channelTEXTcliChannel name attached to the inbound envelope.
--chat-idTEXTlocalChat id attached to the inbound envelope.
--sender-idTEXThumanSender id; stored under context.sender_id.
--session-idTEXT{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".

OptionTypeDefaultDescription
--chat-idTEXTlocalChat id reported by the CLI channel.
--session-idTEXTnoneOptional 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]
OptionTypeDefaultDescription
--enable-channelTEXT (repeatable)empty list (use BUB_ENABLED_CHANNELS)Restrict gateway to the listed channel names. Pass multiple times.
--installflagdisabledInstall and start the gateway as a per-user background service.
--uninstallflagdisabledStop 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]
OptionTypeDefaultDescription
--helpflag—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:

CodeMeaning
0Config saved.
1Validation, 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]...
OptionTypeDefaultDescription
SPECS (args)one or more stringsempty listPackage specs: PyPI name, owner/repo[@ref], git+..., or a bub-contrib package as name@ref resolved against https://github.com/bubbuild/bub-contrib.git.
--projectPATHBUB_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...
OptionTypeDefaultDescription
PACKAGES (args)one or more stringsrequiredPackage names as recorded in the project’s pyproject.toml.
--projectPATHBUB_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]...
OptionTypeDefaultDescription
PACKAGES (args)zero or more stringsempty listPackage names to upgrade; empty means all.
--projectPATHBUB_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]...
OptionTypeDefaultDescription
--helpflag—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]
OptionTypeDefaultDescription
--codex-homePATH$CODEX_HOME or ~/.codexDirectory to store the resulting auth.json.
--browser / --no-browserflag--browserOpen the OAuth authorize URL in the default browser.
--manualflagoffSkip the local callback server and prompt for the callback URL or code.
--timeoutFLOAT300.0OAuth 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.