Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ Then, install and activate the environment with:
uv sync
```

1. Install prek to run linters/formatters at commit time:
4. Install prek to run linters/formatters at commit time:

```bash
uv run prek install
Expand Down Expand Up @@ -96,7 +96,7 @@ Now, validate that all unit tests are passing:
just test
```

9. Before raising a pull request you should also run tox.
8. Before raising a pull request you should also run tox.
This will run the tests across different versions of Python:

```bash
Expand Down
162 changes: 85 additions & 77 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,127 +1,135 @@
# Bub

[Bub](https://github.com/bubbuild/bub) is a common shape for agents.
**A common shape for agents that live alongside people.**

It starts from a simple question: if there are many agents in the world, what kind of agent is a Bub?
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.

A Bub is an agent that can live inside shared operator environments with explicit boundaries, visible execution evidence, and safe handoff.
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.

The point is not only to complete tasks, but to remain understandable, reviewable, and continuable when more humans and agents join the work.
[Website](https://bub.build) · [GitHub](https://github.com/bubbuild/bub)

## Current Implementation

This repository is the current Python implementation of Bub.
It is hook-first, built on `pluggy`, and keeps the core small while builtins and plugins provide behavior.
In this implementation, Bub uses [Republic](https://github.com/bubbuild/republic) as its context runtime and [constructs context from tape](https://tape.systems).
## Quick Start

- CLI bootstrap: `src/bub/__main__.py` (Typer app)
- Turn orchestrator: `src/bub/framework.py`
- Hook contract: `src/bub/hookspecs.py`
- Builtin hooks/runtime: `src/bub/builtin/hook_impl.py` + `src/bub/builtin/engine.py`
- Skill discovery and validation: `src/bub/skills.py`
```bash
pip install bub
```

## Quick Start
Or from source:

```bash
git clone https://github.com/bubbuild/bub.git
cd bub
uv sync
uv run bub --help
```

```bash
# Runtime off: falls back to model_output=prompt
BUB_RUNTIME_ENABLED=0 uv run bub run "hello"
uv run bub chat # interactive session
uv run bub run "summarize this repo" # one-shot task
uv run bub gateway # channel listener mode
```

```bash
# Internal command mode (line starts with ',')
BUB_RUNTIME_ENABLED=0 uv run bub run ",help"
```
## How It Works

```bash
# Model runtime (hosted providers usually require a key)
BUB_API_KEY=your_key uv run bub run "Summarize this repository"
```
Every inbound message goes through one turn pipeline. Each stage is a hook.

```bash
# OpenAI Codex OAuth (no provider API key required)
uv run bub login openai
BUB_MODEL=openai:gpt-5-codex uv run bub chat
```
resolve_session → load_state → build_prompt → run_model
dispatch_outbound ← render_outbound ← save_state
```

Builtins are plugins registered first. Later plugins override earlier ones. No special cases.

## CLI Commands
If `AGENTS.md` exists in the workspace, it is appended to the system prompt automatically.

- `bub run MESSAGE`: execute one inbound turn and print outbound messages
- `bub login openai`: persist OpenAI Codex OAuth credentials for later runs
- `bub hooks`: print hook-to-plugin bindings
- `bub install PLUGIN_SPEC`: install plugin from PyPI or `owner/repo` (GitHub shorthand)
Key source files:

## Runtime Behavior
- Turn orchestrator: [`src/bub/framework.py`](src/bub/framework.py)
- Hook contract: [`src/bub/hookspecs.py`](src/bub/hookspecs.py)
- Builtin hooks: [`src/bub/builtin/hook_impl.py`](src/bub/builtin/hook_impl.py)
- Skill discovery: [`src/bub/skills.py`](src/bub/skills.py)

- Regular text input: uses `run_model`; if runtime is unavailable, output falls back to the prompt text
- Comma commands: `,help`, `,tools`, `,fs.read ...`, etc.
- Unknown comma commands: executed as `bash -lc` in workspace
- Session event log: `.bub/runtime/<session-hash>.jsonl`
- `AGENTS.md`: if present in workspace, appended to runtime system prompt
## What Sets It Apart

## Skills
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:

- Discovery roots with deterministic override:
1. `<workspace>/.agent/skills`
2. `~/.agent/skills`
3. `src/skills`
- Each skill directory must include `SKILL.md`
- Supported frontmatter fields:
- required: `name`, `description`
- optional: `license`, `compatibility`, `metadata`, `allowed-tools`
- **Context from tape.** History is append-only facts. Anchors mark phase transitions. Context is assembled on demand — not accumulated, not compressed into lossy summaries.
- **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.
- **One pipeline across channels.** CLI and Telegram share the same `process_inbound()` path. Hooks don't know which channel they're in.
- **Skills as documents.** Skills are `SKILL.md` files with validated frontmatter, not code modules with magic registration.

## Plugin Development
## Extend It

Plugins are loaded from Python entry points in `group="bub"`:
```python
from bub import hookimpl

class EchoPlugin:
@hookimpl
def build_prompt(self, message, session_id, state):
return f"[echo] {message['content']}"

@hookimpl
async def run_model(self, prompt, session_id, state):
return prompt
```

```toml
[project.entry-points."bub"]
my_plugin = "my_package.my_plugin"
echo = "my_package.plugin:EchoPlugin"
```

Implement hooks with `@hookimpl` following `BubHookSpecs`.
See the [Extension Guide](https://bub.build/extension-guide/) for hook semantics and plugin packaging.

## Runtime Environment Variables
## CLI

- `BUB_RUNTIME_ENABLED`: `auto` (default), `1`, `0`
- `BUB_MODEL`: default `openrouter:qwen/qwen3-coder-next`
- `BUB_API_KEY`: runtime provider key; optional when using `openai:*` models with `bub login openai`
- `BUB_API_BASE`: optional provider base URL
- `BUB_API_FORMAT`: upstream API shape; default `completion`
Use `responses` for OpenAI Responses-compatible providers and `messages` for chat-completions-style providers.
- `BUB_RUNTIME_MAX_STEPS`: default `8`
- `BUB_RUNTIME_MAX_TOKENS`: default `1024`
- `BUB_RUNTIME_MODEL_TIMEOUT_SECONDS`: default `90`
| Command | Description |
|---------|-------------|
| `bub chat` | Interactive REPL |
| `bub run MESSAGE` | One-shot turn |
| `bub gateway` | Channel listener (Telegram, etc.) |
| `bub login openai` | OpenAI Codex OAuth |
| `bub hooks` | Print hook-to-plugin bindings |

```bash
# Use a Responses-compatible upstream API.
BUB_MODEL=openai:gpt-5-codex \
BUB_API_FORMAT=responses \
uv run bub chat
```
Lines starting with `,` enter internal command mode (`,help`, `,tools`, `,fs.read path=README.md`).

## Configuration

## Documentation
| Variable | Default | Description |
|----------|---------|-------------|
| `BUB_MODEL` | `openrouter:qwen/qwen3-coder-next` | Model identifier |
| `BUB_API_KEY` | — | Provider key (optional with `bub login openai`) |
| `BUB_API_BASE` | — | Custom provider endpoint |
| `BUB_API_FORMAT` | `completion` | `completion`, `responses`, or `messages` |
| `BUB_RUNTIME_MAX_STEPS` | `50` | Max tool-use loop iterations |
| `BUB_RUNTIME_MAX_TOKENS` | `1024` | Max tokens per model call |
| `BUB_RUNTIME_MODEL_TIMEOUT_SECONDS` | — | Model call timeout (seconds) |

- `docs/index.md`: overview
- `docs/architecture.md`: lifecycle, precedence, and failure isolation
- `docs/skills.md`: skill discovery and frontmatter constraints
- `docs/cli.md`: CLI usage and comma command mode
- `docs/features.md`: implemented capabilities and limits
## Background

## Development Checks
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.

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/)

## Docs

- [Architecture](https://bub.build/architecture/) — lifecycle, hook precedence, error handling
- [Features](https://bub.build/features/) — what ships today and current boundaries
- [CLI](https://bub.build/cli/) — commands and comma mode
- [Skills](https://bub.build/skills/) — discovery and authoring
- [Extension Guide](https://bub.build/extension-guide/) — hooks, tools, plugin packaging
- [Channels](https://bub.build/channels/) — adapters and sessions
- [Deployment](https://bub.build/deployment/) — Docker, Telegram, operations

## Development

```bash
uv run ruff check .
uv run mypy src
uv run pytest -q
```

See [CONTRIBUTING.md](./CONTRIBUTING.md).

## License

[Apache-2.0](./LICENSE)
2 changes: 1 addition & 1 deletion docs/cli.md → docs/channels/cli.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# CLI

`bub` currently exposes five builtin commands: `run`, `gateway`, `chat`, `login`, and the hidden compatibility command `message`.
`bub` exposes four main commands (`run`, `gateway`, `chat`, `login`) plus two hidden ones (`hooks` for diagnostics, `message` as a compatibility alias for `gateway`).

## `bub run`

Expand Down
8 changes: 3 additions & 5 deletions docs/channels/index.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
# Channels

Bub uses channel adapters to run the same agent pipeline across different I/O endpoints.
Bub uses channel adapters to run the same pipeline across different I/O endpoints. Hooks don't know which channel they're in.

## Builtin Channels

- `cli`: local interactive terminal channel (`uv run bub chat`)
- `telegram`: Telegram bot channel (`uv run bub gateway`)

See [Telegram](telegram.md) for channel-specific configuration and runtime behavior.
- `cli`: local interactive terminal — see [CLI](cli.md)
- `telegram`: Telegram bot — see [Telegram](telegram.md)

## Run Modes

Expand Down
13 changes: 0 additions & 13 deletions docs/core/index.md

This file was deleted.

52 changes: 31 additions & 21 deletions docs/features.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,45 @@
# Key Features

## Framework Core
## Hook-First Runtime

- Hook-first architecture powered by `pluggy`.
- Deterministic turn pipeline in `BubFramework.process_inbound()`.
- Safe fallback to prompt text when `run_model` returns no value (with `on_error` notification).
- Automatic fallback outbound when `render_outbound` produces nothing.
Every turn stage is a [pluggy](https://pluggy.readthedocs.io/) hook.
Builtins are ordinary plugins — override any stage by registering your own.
Both first-result hooks (override) and broadcast hooks (observer) are supported.
Safe fallback to prompt text when `run_model` returns no value (with `on_error` notification).
Automatic fallback outbound when `render_outbound` produces nothing.

## Runtime And Commands
## Tape-Based Context

- Builtin CLI commands: `run`, `hooks`, `message`, `chat`.
- Builtin `RuntimeEngine`:
- normal input goes through model + tool loop (Republic)
- comma-prefixed input enters internal command mode (`,help`, `,tools`, `,fs.read`, etc.)
- unknown internal commands fall back to shell execution via the `bash` tool
- Runtime events are persisted to tapes (default under `~/.bub/tapes`).
Runtime events are recorded to tapes (default under `~/.bub/tapes`).
Context is reconstructed from tape records, not accumulated in session state.

## Channel Capability
## Builtin Batteries

- Builtin channels: `cli` and `telegram`.
- `message` mode runs the same framework pipeline for channel-driven traffic.
- Outbound delivery is routed by `ChannelManager`, keeping business hooks channel-agnostic.
- **CLI**: `run`, `chat`, `gateway`, `login`, `hooks` via Typer.
- **Model runtime**: agent loop with tool use, backed by [Republic](https://github.com/bubbuild/republic).
- **Comma commands**: `,help`, `,tools`, `,fs.read`, etc. Unknown commands fall back to shell.
- **Channels**: `cli` and `telegram` ship as defaults.

All of these are hook implementations. Replace what you need.

## Channel-Agnostic Pipeline

CLI and Telegram use the same `process_inbound()` path.
Hooks don't know which channel they're in.
Outbound routing is handled by `ChannelManager`.

## Skills

Skills are `SKILL.md` files with validated frontmatter.
Plugins can ship their own by including a `skills/` directory.

## Plugin Extensibility

- External plugins are loaded via Python entry points (`group="bub"`).
- Later-registered plugins run first and can override builtin behavior.
- Supports both first-result hooks (override style) and broadcast hooks (observer style).
External plugins are loaded via Python entry points (`group="bub"`).
Later-registered plugins run first and can override builtin behavior.

## Current Boundaries

- No strict envelope schema: `Envelope` is intentionally flexible.
- `Envelope` is intentionally weakly typed (`Any` + accessor helpers).
- No centralized key contract for shared plugin `state`.
- Core repository does not currently ship a builtin Discord channel adapter.
- No builtin Discord adapter — implement one via `provide_channels`.
Loading
Loading