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.
Global options
Section titled “Global options”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.
bub run
Section titled “bub run”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_storeis 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.
bub chat
Section titled “bub chat”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
ChannelManagerwithenabled_channels=["cli"]andstream_output=True, then callsmanager.listen_and_run(). - Exits with code
1if no plugin provides a channel namedcli. - The CLI channel uses
prompt_toolkitandrichto render streamed events.
bub gateway
Section titled “bub gateway”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-channelis omitted the manager readsChannelSettings.enabled_channels(BUB_ENABLED_CHANNELS, defaultall). allstarts every enabled non-Interfacechannel. When you list at least one non-Lifecyclechannel explicitly, enabledLifecycleruntimes are attached automatically. Use!nameto exclude one.framework.running()is held open until the manager loop exits;provide_tape_storecleanup runs on shutdown.- On Linux,
--installwritesbub-gateway.serviceunder${XDG_CONFIG_HOME:-~/.config}/systemd/user/, enables it for the user’s default target, and starts or restarts it. Useloginctl enable-lingerseparately if it must remain active after logout. - On Windows,
--installregisters and starts a current-userBub GatewayTask 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-channelvalues. Re-running the command replaces and restarts the existing service; do so after moving or replacing the Python environment. --uninstallstops 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.--installand--uninstallare mutually exclusive.
See Operate › Channels for per-channel deployment notes.
bub onboard
Section titled “bub onboard”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] [PLUGIN_NAME]
Pass a registered plugin name to configure only that plugin, for example bub onboard builtin.
Other configuration is preserved, and targeted onboarding skips the gateway installation prompt.
An unknown plugin or one without an onboard_config hook exits with code 1 without saving.
Omit the name to run all onboarding hooks.
| 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, andBUB_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_confighook receives a copy of the loaded configuration plus updates from earlier hooks. Existing fields are preserved unless a hook overrides them; non-dict returns abort withTypeError. - The merged dict is validated through
configure.validatebefore being written. onboardis 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 launchonboardonly 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. |
bub install
Section titled “bub install”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
uvonPATHand that Bub itself runs inside a virtualenv (sys.prefix != sys.base_prefix); otherwise exits with1. - Initializes the project on first use via
uv init --bare --name bub-project --appand adds Bub to it as a dependency (matching the local install: editable, file://, VCS, or PyPI). - The default project directory is created automatically. When
--projectis 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
Section titled “bub uninstall”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
Section titled “bub update”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.
bub login
Section titled “bub login”Top-level group for authentication subcommands.
bub login [OPTIONS] COMMAND [ARGS]...
| Option | Type | Default | Description |
|---|---|---|---|
--help |
flag | — | Show help and exit. |
bub login openai
Section titled “bub login openai”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 setBUB_MODEL=openai:<codex-model>and omitBUB_API_KEY. - On
CodexOAuthLoginErrorexits with code1.
bub hooks
Section titled “bub hooks”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.