|
1 | 1 | # Bub |
2 | 2 |
|
3 | | -[Bub](https://github.com/bubbuild/bub) is a common shape for agents. |
| 3 | +**A common shape for agents that live alongside people.** |
4 | 4 |
|
5 | | -It starts from a simple question: if there are many agents in the world, what kind of agent is a Bub? |
| 5 | +Bub started in group chats. Not as a demo or a personal assistant, but as a teammate that had to coexist with real humans and other agents in the same messy conversations — concurrent tasks, incomplete context, and nobody waiting. |
6 | 6 |
|
7 | | -A Bub is an agent that can live inside shared operator environments with explicit boundaries, visible execution evidence, and safe handoff. |
| 7 | +It is hook-first, built on [pluggy](https://pluggy.readthedocs.io/), with a small core (~200 lines) and builtins that are just default plugins you can replace. Context comes from [tape](https://tape.systems), not session accumulation. The same pipeline runs across CLI, Telegram, and any channel you add. |
8 | 8 |
|
9 | | -The point is not only to complete tasks, but to remain understandable, reviewable, and continuable when more humans and agents join the work. |
| 9 | +[Website](https://bub.build) · [GitHub](https://github.com/bubbuild/bub) |
10 | 10 |
|
11 | | -## Current Implementation |
12 | | - |
13 | | -This repository is the current Python implementation of Bub. |
14 | | -It is hook-first, built on `pluggy`, and keeps the core small while builtins and plugins provide behavior. |
15 | | -In this implementation, Bub uses [Republic](https://github.com/bubbuild/republic) as its context runtime and [constructs context from tape](https://tape.systems). |
| 11 | +## Quick Start |
16 | 12 |
|
17 | | -- CLI bootstrap: `src/bub/__main__.py` (Typer app) |
18 | | -- Turn orchestrator: `src/bub/framework.py` |
19 | | -- Hook contract: `src/bub/hookspecs.py` |
20 | | -- Builtin hooks/runtime: `src/bub/builtin/hook_impl.py` + `src/bub/builtin/engine.py` |
21 | | -- Skill discovery and validation: `src/bub/skills.py` |
| 13 | +```bash |
| 14 | +pip install bub |
| 15 | +``` |
22 | 16 |
|
23 | | -## Quick Start |
| 17 | +Or from source: |
24 | 18 |
|
25 | 19 | ```bash |
26 | 20 | git clone https://github.com/bubbuild/bub.git |
27 | 21 | cd bub |
28 | 22 | uv sync |
29 | | -uv run bub --help |
30 | 23 | ``` |
31 | 24 |
|
32 | 25 | ```bash |
33 | | -# Runtime off: falls back to model_output=prompt |
34 | | -BUB_RUNTIME_ENABLED=0 uv run bub run "hello" |
| 26 | +uv run bub chat # interactive session |
| 27 | +uv run bub run "summarize this repo" # one-shot task |
| 28 | +uv run bub gateway # channel listener mode |
35 | 29 | ``` |
36 | 30 |
|
37 | | -```bash |
38 | | -# Internal command mode (line starts with ',') |
39 | | -BUB_RUNTIME_ENABLED=0 uv run bub run ",help" |
40 | | -``` |
| 31 | +## How It Works |
41 | 32 |
|
42 | | -```bash |
43 | | -# Model runtime (hosted providers usually require a key) |
44 | | -BUB_API_KEY=your_key uv run bub run "Summarize this repository" |
45 | | -``` |
| 33 | +Every inbound message goes through one turn pipeline. Each stage is a hook. |
46 | 34 |
|
47 | | -```bash |
48 | | -# OpenAI Codex OAuth (no provider API key required) |
49 | | -uv run bub login openai |
50 | | -BUB_MODEL=openai:gpt-5-codex uv run bub chat |
51 | 35 | ``` |
| 36 | +resolve_session → load_state → build_prompt → run_model |
| 37 | + ↓ |
| 38 | + dispatch_outbound ← render_outbound ← save_state |
| 39 | +``` |
| 40 | + |
| 41 | +Builtins are plugins registered first. Later plugins override earlier ones. No special cases. |
52 | 42 |
|
53 | | -## CLI Commands |
| 43 | +If `AGENTS.md` exists in the workspace, it is appended to the system prompt automatically. |
54 | 44 |
|
55 | | -- `bub run MESSAGE`: execute one inbound turn and print outbound messages |
56 | | -- `bub login openai`: persist OpenAI Codex OAuth credentials for later runs |
57 | | -- `bub hooks`: print hook-to-plugin bindings |
58 | | -- `bub install PLUGIN_SPEC`: install plugin from PyPI or `owner/repo` (GitHub shorthand) |
| 45 | +Key source files: |
59 | 46 |
|
60 | | -## Runtime Behavior |
| 47 | +- Turn orchestrator: [`src/bub/framework.py`](src/bub/framework.py) |
| 48 | +- Hook contract: [`src/bub/hookspecs.py`](src/bub/hookspecs.py) |
| 49 | +- Builtin hooks: [`src/bub/builtin/hook_impl.py`](src/bub/builtin/hook_impl.py) |
| 50 | +- Skill discovery: [`src/bub/skills.py`](src/bub/skills.py) |
61 | 51 |
|
62 | | -- Regular text input: uses `run_model`; if runtime is unavailable, output falls back to the prompt text |
63 | | -- Comma commands: `,help`, `,tools`, `,fs.read ...`, etc. |
64 | | -- Unknown comma commands: executed as `bash -lc` in workspace |
65 | | -- Session event log: `.bub/runtime/<session-hash>.jsonl` |
66 | | -- `AGENTS.md`: if present in workspace, appended to runtime system prompt |
| 52 | +## What Sets It Apart |
67 | 53 |
|
68 | | -## Skills |
| 54 | +Bub grew up in multi-person chats with multiple agents running at the same time. Single-user flows hide structural problems; shared environments expose them fast. That shaped a few things: |
69 | 55 |
|
70 | | -- Discovery roots with deterministic override: |
71 | | - 1. `<workspace>/.agent/skills` |
72 | | - 2. `~/.agent/skills` |
73 | | - 3. `src/skills` |
74 | | -- Each skill directory must include `SKILL.md` |
75 | | -- Supported frontmatter fields: |
76 | | - - required: `name`, `description` |
77 | | - - optional: `license`, `compatibility`, `metadata`, `allowed-tools` |
| 56 | +- **Context from tape.** History is append-only facts. Anchors mark phase transitions. Context is assembled on demand — not accumulated, not compressed into lossy summaries. |
| 57 | +- **Hooks all the way down.** The turn pipeline *is* hooks. Override `build_prompt`, `run_model`, or `render_outbound` to change behavior. The core does not privilege its own builtins. |
| 58 | +- **One pipeline across channels.** CLI and Telegram share the same `process_inbound()` path. Hooks don't know which channel they're in. |
| 59 | +- **Skills as documents.** Skills are `SKILL.md` files with validated frontmatter, not code modules with magic registration. |
78 | 60 |
|
79 | | -## Plugin Development |
| 61 | +## Extend It |
80 | 62 |
|
81 | | -Plugins are loaded from Python entry points in `group="bub"`: |
| 63 | +```python |
| 64 | +from bub import hookimpl |
| 65 | + |
| 66 | +class EchoPlugin: |
| 67 | + @hookimpl |
| 68 | + def build_prompt(self, message, session_id, state): |
| 69 | + return f"[echo] {message['content']}" |
| 70 | + |
| 71 | + @hookimpl |
| 72 | + async def run_model(self, prompt, session_id, state): |
| 73 | + return prompt |
| 74 | +``` |
82 | 75 |
|
83 | 76 | ```toml |
84 | 77 | [project.entry-points."bub"] |
85 | | -my_plugin = "my_package.my_plugin" |
| 78 | +echo = "my_package.plugin:EchoPlugin" |
86 | 79 | ``` |
87 | 80 |
|
88 | | -Implement hooks with `@hookimpl` following `BubHookSpecs`. |
| 81 | +See the [Extension Guide](https://bub.build/extension-guide/) for hook semantics and plugin packaging. |
89 | 82 |
|
90 | | -## Runtime Environment Variables |
| 83 | +## CLI |
91 | 84 |
|
92 | | -- `BUB_RUNTIME_ENABLED`: `auto` (default), `1`, `0` |
93 | | -- `BUB_MODEL`: default `openrouter:qwen/qwen3-coder-next` |
94 | | -- `BUB_API_KEY`: runtime provider key; optional when using `openai:*` models with `bub login openai` |
95 | | -- `BUB_API_BASE`: optional provider base URL |
96 | | -- `BUB_API_FORMAT`: upstream API shape; default `completion` |
97 | | - Use `responses` for OpenAI Responses-compatible providers and `messages` for chat-completions-style providers. |
98 | | -- `BUB_RUNTIME_MAX_STEPS`: default `8` |
99 | | -- `BUB_RUNTIME_MAX_TOKENS`: default `1024` |
100 | | -- `BUB_RUNTIME_MODEL_TIMEOUT_SECONDS`: default `90` |
| 85 | +| Command | Description | |
| 86 | +|---------|-------------| |
| 87 | +| `bub chat` | Interactive REPL | |
| 88 | +| `bub run MESSAGE` | One-shot turn | |
| 89 | +| `bub gateway` | Channel listener (Telegram, etc.) | |
| 90 | +| `bub login openai` | OpenAI Codex OAuth | |
| 91 | +| `bub hooks` | Print hook-to-plugin bindings | |
101 | 92 |
|
102 | | -```bash |
103 | | -# Use a Responses-compatible upstream API. |
104 | | -BUB_MODEL=openai:gpt-5-codex \ |
105 | | -BUB_API_FORMAT=responses \ |
106 | | -uv run bub chat |
107 | | -``` |
| 93 | +Lines starting with `,` enter internal command mode (`,help`, `,tools`, `,fs.read path=README.md`). |
| 94 | + |
| 95 | +## Configuration |
108 | 96 |
|
109 | | -## Documentation |
| 97 | +| Variable | Default | Description | |
| 98 | +|----------|---------|-------------| |
| 99 | +| `BUB_MODEL` | `openrouter:qwen/qwen3-coder-next` | Model identifier | |
| 100 | +| `BUB_API_KEY` | — | Provider key (optional with `bub login openai`) | |
| 101 | +| `BUB_API_BASE` | — | Custom provider endpoint | |
| 102 | +| `BUB_API_FORMAT` | `completion` | `completion`, `responses`, or `messages` | |
| 103 | +| `BUB_RUNTIME_MAX_STEPS` | `50` | Max tool-use loop iterations | |
| 104 | +| `BUB_RUNTIME_MAX_TOKENS` | `1024` | Max tokens per model call | |
| 105 | +| `BUB_RUNTIME_MODEL_TIMEOUT_SECONDS` | — | Model call timeout (seconds) | |
110 | 106 |
|
111 | | -- `docs/index.md`: overview |
112 | | -- `docs/architecture.md`: lifecycle, precedence, and failure isolation |
113 | | -- `docs/skills.md`: skill discovery and frontmatter constraints |
114 | | -- `docs/cli.md`: CLI usage and comma command mode |
115 | | -- `docs/features.md`: implemented capabilities and limits |
| 107 | +## Background |
116 | 108 |
|
117 | | -## Development Checks |
| 109 | +We care less about whether an agent can finish a demo task, and more about whether it can coexist with real people under real conditions. Context is not baggage to carry forever — it is a working set, constructed when needed and let go when done. |
| 110 | + |
| 111 | +Read more: [Context from Tape](https://tape.systems) · [Socialized Evaluation and Agent Partnership](https://bub.build/posts/2026-03-01-bub-socialized-evaluation-and-agent-partnership/) |
| 112 | + |
| 113 | +## Docs |
| 114 | + |
| 115 | +- [Architecture](https://bub.build/architecture/) — lifecycle, hook precedence, error handling |
| 116 | +- [Features](https://bub.build/features/) — what ships today and current boundaries |
| 117 | +- [CLI](https://bub.build/cli/) — commands and comma mode |
| 118 | +- [Skills](https://bub.build/skills/) — discovery and authoring |
| 119 | +- [Extension Guide](https://bub.build/extension-guide/) — hooks, tools, plugin packaging |
| 120 | +- [Channels](https://bub.build/channels/) — adapters and sessions |
| 121 | +- [Deployment](https://bub.build/deployment/) — Docker, Telegram, operations |
| 122 | + |
| 123 | +## Development |
118 | 124 |
|
119 | 125 | ```bash |
120 | 126 | uv run ruff check . |
121 | 127 | uv run mypy src |
122 | 128 | uv run pytest -q |
123 | 129 | ``` |
124 | 130 |
|
| 131 | +See [CONTRIBUTING.md](./CONTRIBUTING.md). |
| 132 | + |
125 | 133 | ## License |
126 | 134 |
|
127 | 135 | [Apache-2.0](./LICENSE) |
0 commit comments