A hook-first runtime for agents that live alongside people.
Bub is a small Python runtime for building agents in shared environments. It started in group chats, where multiple humans and agents had to work in the same conversation without hidden state, hand-wavy memory, or framework-specific magic.
Built on [agents.md](https://agents.md/) and [Agent Skills](https://agentskills.io/) , Bub stays intentionally small. Every turn stage is a [pluggy](https://pluggy.readthedocs.io/) hook. Builtins are included but replaceable. The same runtime drives CLI, Telegram, and any channel you add.
[Website](https://bub.build) · [GitHub](https://github.com/bubbuild/bub)
## Quick Start
```bash
pip install bub
```
Or from source:
```bash
git clone https://github.com/bubbuild/bub.git
cd bub
uv sync # enough to run Bub from source
```
For local development, use `make install` instead so the website toolchain and `prek` hooks are installed too.
```bash
uv run bub chat # interactive session
uv run bub run "summarize this repo" # one-shot task
uv run bub gateway # channel listener mode
```
## Why Bub
- **Hook-first runtime.** Every turn stage is a hook. Override one stage or replace the whole flow without forking the runtime.
- **Tape context.** Context is rebuilt from append-only records, not carried around as mutable session state. Easier to inspect, replay, and hand off.
- **One runtime across surfaces.** The same inbound pipeline runs across CLI, Telegram, and custom channels. Adapters change the surface, not the runtime model.
- **Batteries included.** CLI, Telegram, tools, skills, and model execution ship with the core runtime. Use the defaults first, replace them later.
- **Operator equivalence.** Humans and agents work inside the same runtime boundaries, with the same evidence trail and handoff model. No hidden operator class.
## How It Works
Every inbound message goes through one turn pipeline. Each stage is a hook.
```
resolve_session → load_state → build_prompt → run_model
↓
dispatch_outbound ← render_outbound ← save_state
```
Builtins are registered first. External plugins load after them. At runtime, later plugins take precedence. There are no framework-only shortcuts.
Key source files:
- Turn orchestrator: [`src/bub/framework.py`](https://github.com/bubbuild/bub/blob/main/src/bub/framework.py)
- Hook contract: [`src/bub/hooks/specs.py`](https://github.com/bubbuild/bub/blob/main/src/bub/hooks/specs.py)
- Builtin hooks: [`src/bub/builtin/hook_impl.py`](https://github.com/bubbuild/bub/blob/main/src/bub/builtin/hook_impl.py)
- Skill discovery: [`src/bub/skills.py`](https://github.com/bubbuild/bub/blob/main/src/bub/skills.py)
## Extend It
```python
from bub import hookimpl
from bub.envelope import content_of
class EchoPlugin:
@hookimpl
def build_prompt(self, message, session_id, state):
return f"[echo] {content_of(message)}"
@hookimpl
async def run_model(self, prompt, session_id, state):
return prompt
echo_plugin = EchoPlugin()
```
```toml
[project.entry-points."bub"]
echo = "my_package.plugin:echo_plugin"
```
See the [Build docs](https://bub.build/docs/build/) for hook guides, packaging, and plugin structure.
## CLI
| Command | Description |
| ------------------ | --------------------------------- |
| `bub chat` | Interactive REPL |
| `bub run MESSAGE` | One-shot turn |
| `bub gateway` | Channel listener (Telegram, etc.) |
| `bub install` | Install or sync Bub plugin deps |
| `bub update` | Upgrade Bub plugin deps |
| `bub login openai` | OpenAI Codex OAuth |
Lines starting with `,` enter internal command mode (`,help`, `,skill name=my-skill`, `,fs.read path=README.md`).
`bub hooks` still exists for diagnostics, but it is hidden from top-level help. `bub install` and `bub update` manage a separate uv project for Bub plugins, defaulting to `~/.bub/bub-project` or `BUB_PROJECT`.
## Configuration
| Variable | Default | Description |
| --------------------------- | ---------------------------- | ---------------------------------------------------- |
| `BUB_MODEL` | `openrouter:openrouter/free` | Model identifier |
| `BUB_API_KEY` | — | Provider key (optional with `bub login openai`) |
| `BUB_API_BASE` | — | Custom provider endpoint |
| `BUB_CLIENT_ARGS` | — | JSON object forwarded to the underlying model client |
| `BUB_MAX_STEPS` | `50` | Max tool-use loop iterations |
| `BUB_MAX_TOKENS` | `16384` | Max tokens per model call |
| `BUB_MODEL_TIMEOUT_SECONDS` | — | Model call timeout (seconds) |
## Background
Bub is shaped by one constraint: real collaboration is messier than a solo demo. In shared environments, operators need visible boundaries, auditable history, and extension points that do not collapse into framework sprawl.
Read more:
- [Why We Rewrote Bub](https://bub.build/posts/why-rewrite-bub/)
- [Socialized Evaluation and Agent Partnership](https://bub.build/posts/socialized-evaluation/)
- [Context from Tape](https://tape.systems)
## Docs
- [Getting Started](https://bub.build/docs/getting-started/) — install Bub and run the first turn
- [Concepts](https://bub.build/docs/concepts/) — the mental model behind the runtime
- [Channels](https://bub.build/docs/operate/channels/) — run Bub in CLI, Telegram, or your own channel
- [Skills](https://bub.build/docs/build/skills/) — discover, inspect, and author Agent Skills in Bub
- [Build](https://bub.build/docs/build/) — write plugins, override hooks, ship tools and skills
- [Deployment](https://bub.build/docs/operate/deploy/) — Docker, environment, upgrades
## Development
```bash
make install
make check
make test
make docs
make docs-test
```
See [CONTRIBUTING.md](https://github.com/bubbuild/bub/blob/main/CONTRIBUTING.md).
## License
[Apache-2.0](https://github.com/bubbuild/bub/blob/main/LICENSE)