Skip to content

CLI

The bub command is provided by the application layer and requires the app optional dependency (install). This page lists only built-in commands; plugins can add commands through register_cli_commands, so consult bub --help and the plugin documentation for the full set.

bub [OPTIONS] COMMAND [ARGS]...
Option Type Default Description
--workspace, -w path current working directory Sets BubFramework.workspace
--version, -V flag — Show the installed Bub version and exit
--help flag — Show help

--workspace affects tools’ working directory, skill discovery, and relative-path resolution. It does not change BUB_HOME or the location of the configuration file.

Running bub without a command runs BubFramework.default_command with its defaults. The builtin plugin sets it to chat, so bub and bub -w PATH start the chat REPL. A plugin can choose another command by setting default_command in its register_cli_commands hook; the builtin only fills it when no plugin has.

Before loading the CLI, the command checks for the app optional dependency. If it is missing, the process prints the missing package and the install command, then exits without reaching the Typer help page.

Runs a complete Turn for one message: resolves the session, builds the prompt, calls the model and tools, saves state, and generates a reply, then prints TurnResult.outbounds to stdout. It does not start a channel manager.

bub run [OPTIONS] MESSAGE
Parameter Type Default Description
MESSAGE text required Message body; executes a command when it starts with the command prefix
--channel text cli Inbound channel name
--chat-id text local Inbound chat ID
--sender-id text human Written to context.sender_id
--session-id text <channel>:<chat-id> Explicitly overrides the session ID

Output format:

[channel:chat_id]
<content>

Examples:

Terminal window
bub run "Summarize this repository."
bub run --channel web --chat-id demo "Continue the previous topic."
bub run --session-id shared:demo ",tape.info"

Because it does not start a ChannelManager:

  • It does not start channels or background services such as mcp.lifecycle and acp-server.
  • It does not automatically send model replies to a chat platform.
  • The resource scopes for provide_tape_store, provide_lifespan, and provide_steering_inbox still run.
  • The model stage uses the non-streaming HookRuntime.run_model.

When the model returns no text, run prints the inbound content or prompt text as a fallback and logs a run_model stage error; the process itself usually still exits with code 0. To make scripted decisions based on failure, inspect stderr and the actual output rather than relying on the exit code alone.

Starts an interactive REPL. It always enables the cli channel and attaches enabled Lifecycle channels.

bub chat [OPTIONS] [INITIAL_PROMPT]
Parameter Type Default Description
INITIAL_PROMPT text — Submitted immediately after the REPL starts
--chat-id text local CLI chat ID
--session-id text cli_session Session ID

chat forces streaming output and ignores BUB_STREAM_OUTPUT. The attached Lifecycle lets MCP tools and ACP background services work during the chat.

Without a cli channel, the command prints an error and exits with code 1. This happens when a plugin replaces or removes the CLI channel.

Terminal window
bub chat
bub chat "What changed in this repository?"
bub chat --session-id shared:demo

Inside the REPL, comma-prefixed commands are controlled by BUB_COMMAND_PREFIX, which defaults to ,. Type ,help to see the current commands.

Starts the channel manager and keeps enabled channels running.

bub gateway [OPTIONS]
Option Type Default Description
--enable-channel text, repeatable empty; reads BUB_ENABLED_CHANNELS Include or exclude channels
--install flag off Install and start a background service for the current user
--uninstall flag off Stop and uninstall the background service

--install and --uninstall are mutually exclusive; passing both exits with an argument error.

BUB_ENABLED_CHANNELS is comma-separated; --enable-channel may be repeated, and command-line values take precedence.

enabled_channels Result
all Every enabled channel that is not an Interface, minus !name exclusions
Explicit ordinary channels The listed channels that are enabled and not excluded
Explicit ordinary channels + Lifecycle Select the ordinary channels first, then attach every enabled Lifecycle
Only Lifecycle Start only those Lifecycle channels
Only !name No inclusions, so startup fails
  • Interface is a user-facing surface that must be selected explicitly, such as cli.
  • Lifecycle is a background service, such as mcp.lifecycle or agent-plugins.mcp.
  • When ordinary channels are selected explicitly, Lifecycle channels are attached automatically by default; use !name to exclude one.
  • If no channel can be enabled, it prints No channels are enabled... and exits with code 1.
Terminal window
bub gateway
bub gateway --enable-channel telegram
bub gateway --enable-channel telegram --enable-channel discord
bub gateway --enable-channel telegram --enable-channel '!mcp.lifecycle'

Quote exclusions so the shell does not treat ! as history expansion.

Platform Installation method Location or behavior
Linux systemd user unit ${XDG_CONFIG_HOME:-~/.config}/systemd/user/bub-gateway.service
Windows Scheduled task Task named Bub Gateway, started when the current user logs in
macOS --install unsupported Deploy with launchd, tmux, or a container

The Linux unit uses Restart=on-failure, RestartSec=5s, and WantedBy=default.target. Installation runs daemon-reload, enable, and restart.

  • The service captures the current Python interpreter, workspace, and explicit --enable-channel arguments.
  • After changing the virtual environment, moving the workspace, or changing channel arguments, run bub gateway --install again.
  • To keep it running after logout on Linux, run loginctl enable-linger "$USER".
  • Reinstalling replaces the existing unit or task and restarts it.
  • --uninstall counts as successful even when the service does not exist.

macOS has no built-in service installation path; Deployment describes a container approach.

Interactively generates configuration: it collects model and plugin options and writes them to BubFramework.config_file, which defaults to ~/.bub/config.yml. It does not start channels.

bub onboard [OPTIONS] [PLUGIN_NAME]
Parameter Type Default Description
PLUGIN_NAME text none Run only that plugin’s onboard_config

Without a plugin name, it runs the built-in model configuration first, then the configuration of every other registered plugin. With a plugin name, it runs only the selected implementation and skips the gateway service installation prompt.

Exit code Meaning
0 Saved, or the user declined gateway installation
1 Configuration validation, write, plugin resolution, or gateway installation failed

Common write behavior:

Choice or action Result
OpenAI-compatible service or local endpoint Writes openai:<model>, api_base, and sets client_args.api_format: chat
Official OpenAI API selected but the address is not the official one Resets the address to https://api.openai.com/v1
Base URL left blank Keeps the provider’s default address and does not write an explicit empty value
Base URL entered explicitly Written even when it equals the default
API key left blank Keeps the key for the current address, or continues using an environment variable
Base URL changed Clears any key entered earlier
Codex selected Skips model discovery and asks for a model ID manually

The connection check calls only the model list endpoint, not a generation request, with a 10-second timeout. It does not verify that the model supports tool calls.

An onboard_config implementation receives the current configuration plus modifications from earlier hooks and returns a dictionary that is merged back; returning a non-dictionary raises TypeError. After all implementations finish, the result passes through configure.validate before being written to disk.

Installs plugins into the uv project managed by Bub; with no arguments, it syncs that project. It does not start channels.

bub install [OPTIONS] [SPECS]...
Parameter Type Default Description
SPECS positional empty Packages or Git sources to install
--project path $BUB_HOME/bub-project or ~/.bub/bub-project Plugin project directory; also available as BUB_PROJECT

Package spec resolution:

Form Resolves to
package PyPI package name
package@ref The packages/package subdirectory of bub-contrib, pinned to ref
owner/repo https://github.com/owner/repo.git
https://github.com/owner/repo.git@ref A prefixed Git URL that preserves the ref
git@... or https://... Prefixed with git+

To pin any GitHub repository, use the full URL:

Terminal window
bub install https://github.com/owner/repo.git@v1.2.0

Do not write owner/repo@v1.2.0: the current parser accepts only the owner/repo shorthand without a ref. Bub’s own repository name is also not the same as its package name; when installing a plugin, use the spec given in the plugin’s README.

Examples:

Terminal window
bub install bub-mcp@main
bub install bub-discord
bub install https://github.com/owner/repo.git@v1.2.0
bub install

The first invocation creates bub-project:

uv init --bare --name bub-project --app
uv add --active --no-sync --extra app <source of the current Bub installation>

The current Bub source may be an editable path, a local path, a VCS URL, or a PyPI name; source installs and PyPI installs therefore produce different project declarations.

Subsequent uv calls:

Command uv invocation
bub install (no specs) uv sync --active --inexact
bub install <specs> uv add --active <requirements>
bub uninstall <packages> uv remove --active <packages>
bub update uv sync --active --upgrade --inexact
bub update <packages> uv sync --active --inexact --upgrade-package ...

Prerequisites:

  • uv is on PATH, in the current Python scripts directory, or in ~/.local/bin;
  • Bub is running inside a virtual environment (sys.prefix != sys.base_prefix);
  • An explicitly passed --project directory must exist.

If these are not met, the command exits with code 1. When uv fails, its exit code is returned.

Uninstalls one or more plugins from the managed project. It does not start channels. Names must match the project declarations.

bub uninstall [OPTIONS] PACKAGES...
Terminal window
bub uninstall bub-discord

It modifies only bub-project, not the system Python or other packages in the environment where Bub itself runs. install, uninstall, and update all accept --project, and BUB_PROJECT can specify the same directory.

Upgrades plugins in the managed project; without package names it upgrades every dependency, and with names it upgrades only those packages. It does not start channels.

bub update [OPTIONS] [PACKAGES]...
Terminal window
bub update
bub update bub-mcp

Upgrading does not automatically migrate plugin configuration or Tape data. After upgrading across versions, restart bub chat or bub gateway and check whether bub hooks still reports entry-point loading failures.

Configures ChatGPT plan credentials through the Codex CLI. It does not start channels.

bub login codex [OPTIONS]
Option Type Default Description
--executable text codex Codex CLI executable
--device-auth flag off Use the device authorization flow
--codex-home path $CODEX_HOME or ~/.codex Credential directory

On success it prints:

login: ok
account_id: <id>
Use BUB_MODEL=codex:<model> for ChatGPT plan access.

Matching configuration:

Terminal window
export BUB_MODEL=codex:<model>

Do not set BUB_API_KEY at the same time. On failure it prints login: failed: ... and exits with code 1. Credentials are usually written to $CODEX_HOME/auth.json or ~/.codex/auth.json.

Prints each discovered plugin with the package and version that provide it.

bub plugins [OPTIONS] [NAMES]...
Option Type Default Description
NAMES text all plugins Plugin names registered in the bub entry-point group
--version-only flag off Print only each plugin’s version, one per line

Output is one line per plugin: name distribution version. The builtin hooks are listed as builtin, provided by bub. Plugins that failed to load or initialize are listed with (failed: <error>). An unknown name exits with code 1. With --version-only, each line holds only the version (- when the plugin has no package metadata), for example bub plugins my-plugin --version-only.

Prints the hook implementation map. This is a hidden command that does not appear in bub --help and does not start channels.

bub hooks

Each line has this format:

<hook>: <implementation>, <implementation>

Implementations are printed in pluggy registration order, with hook names sorted alphabetically. When there are no implementations it prints (no hook implementations).

This order is not execution order. Bub reverses pluggy’s internal list and then applies tryfirst / trylast; see Priority and dispatch for diagnosing the actual order.

Scenario Exit code
Command succeeds 0
Typer argument error 2
app optional dependency missing 1; the process exits before Typer
No channels can be enabled, plugin failure, configuration failure 1
uv failure in bub install / uninstall / update uv’s exit code

Model errors in bub run may only be logged and return fallback text, so do not rely on the exit code alone to determine whether the model call succeeded.