bub 0.5.1__tar.gz → 0.6.0a2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bub-0.6.0a2/PKG-INFO +139 -0
- bub-0.6.0a2/README.md +83 -0
- {bub-0.5.1 → bub-0.6.0a2}/pyproject.toml +18 -15
- bub-0.6.0a2/src/bub/__init__.py +62 -0
- bub-0.6.0a2/src/bub/__main__.py +101 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/_version.py +2 -2
- bub-0.6.0a2/src/bub/builtin/__init__.py +6 -0
- bub-0.6.0a2/src/bub/builtin/agent.py +265 -0
- bub-0.6.0a2/src/bub/builtin/archive.py +85 -0
- bub-0.6.0a2/src/bub/builtin/auth.py +50 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/builtin/cli.py +1 -1
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/builtin/codemode/__init__.py +186 -22
- bub-0.6.0a2/src/bub/builtin/codemode/code_runner_child.py +584 -0
- bub-0.6.0a2/src/bub/builtin/codemode/republic_bridge.py +275 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/builtin/environment.py +3 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/builtin/hook_impl.py +51 -56
- bub-0.6.0a2/src/bub/builtin/model.py +150 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/builtin/onboarding.py +58 -85
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/builtin/settings.py +62 -37
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/builtin/spill.py +2 -2
- bub-0.6.0a2/src/bub/builtin/store.py +87 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/builtin/tools.py +8 -6
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/channels/cli/__init__.py +44 -25
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/channels/cli/renderer.py +5 -14
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/channels/manager.py +1 -1
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/channels/message.py +0 -26
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/channels/telegram.py +1 -1
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/configure.py +5 -0
- bub-0.6.0a2/src/bub/core/__init__.py +74 -0
- bub-0.6.0a2/src/bub/core/agent.py +778 -0
- bub-0.6.0a2/src/bub/core/commands.py +64 -0
- bub-0.6.0a2/src/bub/core/context.py +70 -0
- bub-0.6.0a2/src/bub/core/events.py +320 -0
- bub-0.6.0a2/src/bub/core/model.py +83 -0
- bub-0.6.0a2/src/bub/core/recorder.py +92 -0
- {bub-0.5.1/src/bub → bub-0.6.0a2/src/bub/core}/store.py +1 -75
- bub-0.6.0a2/src/bub/core/system_prompt.py +91 -0
- {bub-0.5.1/src/bub → bub-0.6.0a2/src/bub/core}/tape.py +148 -169
- {bub-0.5.1/src/bub → bub-0.6.0a2/src/bub/core}/tools.py +93 -107
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/environment.py +16 -1
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/framework.py +22 -22
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/hooks/interception.py +55 -115
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/hooks/runtime.py +9 -4
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/hooks/specs.py +25 -17
- bub-0.6.0a2/src/bub/prompt.py +58 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/tracing.py +10 -7
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/turn.py +5 -2
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/utils.py +1 -1
- bub-0.6.0a2/tests/__init__.py +1 -0
- bub-0.6.0a2/tests/conftest.py +95 -0
- bub-0.6.0a2/tests/model_fakes.py +116 -0
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_agent_hooks.py +139 -90
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_builtin_agent.py +140 -229
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_builtin_cli.py +13 -28
- bub-0.6.0a2/tests/test_builtin_codex.py +234 -0
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_builtin_hook_impl.py +21 -16
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_builtin_tools.py +8 -8
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_channels.py +43 -20
- bub-0.6.0a2/tests/test_cli_main.py +72 -0
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_cli_renderer.py +3 -4
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_codemode.py +314 -31
- bub-0.6.0a2/tests/test_core_agent.py +390 -0
- bub-0.6.0a2/tests/test_core_agent_step.py +460 -0
- bub-0.6.0a2/tests/test_core_boundary.py +43 -0
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_environment.py +19 -4
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_file_tape_store_entry_ids.py +3 -3
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_fork_store_merge_back.py +2 -2
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_framework.py +23 -2
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_hook_runtime.py +25 -0
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_image_message.py +40 -66
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_install_scripts.py +1 -1
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_onboarding.py +127 -143
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_otlp.py +1 -1
- bub-0.6.0a2/tests/test_provider_messages.py +259 -0
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_sdk_isolation.py +77 -40
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_session_settings.py +4 -4
- bub-0.6.0a2/tests/test_settings.py +381 -0
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_spill.py +71 -66
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_subagent_tool.py +1 -1
- bub-0.6.0a2/tests/test_tape.py +200 -0
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_tape_search_output.py +1 -1
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_tool_loading.py +52 -73
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_tools.py +73 -77
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_tracing.py +87 -141
- bub-0.5.1/PKG-INFO +0 -221
- bub-0.5.1/README.md +0 -176
- bub-0.5.1/src/bub/__init__.py +0 -45
- bub-0.5.1/src/bub/__main__.py +0 -63
- bub-0.5.1/src/bub/builtin/__init__.py +0 -3
- bub-0.5.1/src/bub/builtin/agent.py +0 -621
- bub-0.5.1/src/bub/builtin/auth.py +0 -537
- bub-0.5.1/src/bub/builtin/codemode/code_runner_child.py +0 -176
- bub-0.5.1/src/bub/builtin/codex_provider.py +0 -521
- bub-0.5.1/src/bub/builtin/commands.py +0 -20
- bub-0.5.1/src/bub/builtin/context.py +0 -97
- bub-0.5.1/src/bub/builtin/model_runner.py +0 -629
- bub-0.5.1/src/bub/types.py +0 -16
- bub-0.5.1/tests/conftest.py +0 -39
- bub-0.5.1/tests/test_builtin_codex.py +0 -605
- bub-0.5.1/tests/test_builtin_model_runner.py +0 -405
- bub-0.5.1/tests/test_settings.py +0 -234
- bub-0.5.1/tests/test_tape.py +0 -136
- bub-0.5.1/tests/test_types.py +0 -20
- {bub-0.5.1 → bub-0.6.0a2}/.gitignore +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/LICENSE +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/builtin/codemode/code_runner.py +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/builtin/shell_manager.py +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/builtin/steering.py +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/channels/__init__.py +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/channels/admission.py +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/channels/base.py +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/channels/cli/ansi_bridge.py +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/channels/cli/terminal_output.py +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/channels/cli/writers.py +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/channels/contracts.py +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/channels/handler.py +0 -0
- {bub-0.5.1/src/bub → bub-0.6.0a2/src/bub/core}/sidecars.py +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/envelope.py +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/errors.py +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/gateway_installer.py +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/hooks/__init__.py +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/inquirer.py +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/model_selection.py +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/skills.py +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/bub/streaming.py +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/skills/README.md +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/skills/gh/SKILL.md +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/skills/skill-creator/SKILL.md +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/skills/skill-creator/license.txt +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/skills/skill-creator/scripts/init_skill.py +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/skills/skill-creator/scripts/quick_validate.py +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/skills/telegram/SKILL.md +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/skills/telegram/scripts/telegram_edit.py +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/skills/telegram/scripts/telegram_rich.py +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/src/skills/telegram/scripts/telegram_send.py +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_cli_help.py +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_configure.py +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_envelope.py +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_errors.py +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_gateway_installer.py +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_shell_manager.py +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_skills.py +0 -0
- {bub-0.5.1 → bub-0.6.0a2}/tests/test_utils.py +0 -0
bub-0.6.0a2/PKG-INFO
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: bub
|
|
3
|
+
Version: 0.6.0a2
|
|
4
|
+
Summary: A tiny agent runtime, composable with plugins.
|
|
5
|
+
Project-URL: Homepage, https://bub.build
|
|
6
|
+
Project-URL: Repository, https://github.com/bubbuild/bub
|
|
7
|
+
Project-URL: Documentation, https://bub.build
|
|
8
|
+
Author-email: Chojan Shang <psiace@apache.org>, Frost Ming <me@frostming.com>, Yihong <zouzou0208@gmail.com>
|
|
9
|
+
License: Apache-2.0
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
|
+
Requires-Python: <4.0,>=3.12
|
|
19
|
+
Requires-Dist: loguru>=0.7.3
|
|
20
|
+
Requires-Dist: pydantic>=2.12.5
|
|
21
|
+
Requires-Dist: republic>=0.6.0a1
|
|
22
|
+
Requires-Dist: typing-extensions>=4.15.0
|
|
23
|
+
Provides-Extra: app
|
|
24
|
+
Requires-Dist: aiohttp>=3.14.3; extra == 'app'
|
|
25
|
+
Requires-Dist: httpx[socks]>=0.28.1; extra == 'app'
|
|
26
|
+
Requires-Dist: inquirer-textual>=0.8.0; extra == 'app'
|
|
27
|
+
Requires-Dist: pluggy>=1.6.0; extra == 'app'
|
|
28
|
+
Requires-Dist: prompt-toolkit>=3.0.52; extra == 'app'
|
|
29
|
+
Requires-Dist: pydantic-settings>=2.14.2; extra == 'app'
|
|
30
|
+
Requires-Dist: python-telegram-bot>=22.7; extra == 'app'
|
|
31
|
+
Requires-Dist: pyyaml>=6.0.3; extra == 'app'
|
|
32
|
+
Requires-Dist: rapidfuzz>=3.14.5; extra == 'app'
|
|
33
|
+
Requires-Dist: rich>=14.3.4; extra == 'app'
|
|
34
|
+
Requires-Dist: typer>=0.24.1; extra == 'app'
|
|
35
|
+
Provides-Extra: logfire
|
|
36
|
+
Requires-Dist: aiohttp>=3.14.3; extra == 'logfire'
|
|
37
|
+
Requires-Dist: httpx[socks]>=0.28.1; extra == 'logfire'
|
|
38
|
+
Requires-Dist: inquirer-textual>=0.8.0; extra == 'logfire'
|
|
39
|
+
Requires-Dist: logfire>=4.32.0; extra == 'logfire'
|
|
40
|
+
Requires-Dist: opentelemetry-api>=1.39.0; extra == 'logfire'
|
|
41
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.39.0; extra == 'logfire'
|
|
42
|
+
Requires-Dist: opentelemetry-sdk>=1.39.0; extra == 'logfire'
|
|
43
|
+
Requires-Dist: pluggy>=1.6.0; extra == 'logfire'
|
|
44
|
+
Requires-Dist: prompt-toolkit>=3.0.52; extra == 'logfire'
|
|
45
|
+
Requires-Dist: pydantic-settings>=2.14.2; extra == 'logfire'
|
|
46
|
+
Requires-Dist: python-telegram-bot>=22.7; extra == 'logfire'
|
|
47
|
+
Requires-Dist: pyyaml>=6.0.3; extra == 'logfire'
|
|
48
|
+
Requires-Dist: rapidfuzz>=3.14.5; extra == 'logfire'
|
|
49
|
+
Requires-Dist: rich>=14.3.4; extra == 'logfire'
|
|
50
|
+
Requires-Dist: typer>=0.24.1; extra == 'logfire'
|
|
51
|
+
Provides-Extra: trace
|
|
52
|
+
Requires-Dist: opentelemetry-api>=1.39.0; extra == 'trace'
|
|
53
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.39.0; extra == 'trace'
|
|
54
|
+
Requires-Dist: opentelemetry-sdk>=1.39.0; extra == 'trace'
|
|
55
|
+
Description-Content-Type: text/markdown
|
|
56
|
+
|
|
57
|
+
# Bub
|
|
58
|
+
|
|
59
|
+
<div align="center">
|
|
60
|
+
|
|
61
|
+
<picture>
|
|
62
|
+
<source srcset="https://raw.githubusercontent.com/bubbuild/bub/refs/heads/main/website/src/assets/bub-logo-dark.png" media="(prefers-color-scheme: dark)">
|
|
63
|
+
<img alt="Bub logo" src="https://raw.githubusercontent.com/bubbuild/bub/refs/heads/main/website/src/assets/bub-logo.png" width="200">
|
|
64
|
+
</picture>
|
|
65
|
+
|
|
66
|
+
<p><strong>A tiny agent runtime, composable with plugins.</strong></p>
|
|
67
|
+
|
|
68
|
+
[Website](https://bub.build) · [Docs](https://bub.build/docs/getting-started/) · [Hub](https://hub.bub.build)
|
|
69
|
+
|
|
70
|
+
</div>
|
|
71
|
+
|
|
72
|
+
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.
|
|
73
|
+
|
|
74
|
+
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 replaceable, and the same runtime drives CLI, Telegram, and any channel you add.
|
|
75
|
+
|
|
76
|
+
## Quick Start
|
|
77
|
+
|
|
78
|
+
macOS and Linux:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
curl -fsSL https://bub.build/install.sh | bash
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Windows PowerShell:
|
|
85
|
+
|
|
86
|
+
```powershell
|
|
87
|
+
powershell -ExecutionPolicy ByPass -c "irm https://bub.build/install.ps1 | iex"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Then:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
bub chat # interactive session
|
|
94
|
+
bub run "summarize this repo" # one-shot task
|
|
95
|
+
bub gateway # channel listener mode
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
See [Getting Started](https://bub.build/docs/getting-started/) for installer presets and source installs, and [Configure](https://bub.build/docs/operate/configure/) for model and runtime settings.
|
|
99
|
+
|
|
100
|
+
## Why Bub
|
|
101
|
+
|
|
102
|
+
- **Composable by design.** Every turn stage is a plugin hook. Override one stage or replace the whole flow without forking the runtime.
|
|
103
|
+
- **Tape context.** Context is rebuilt from append-only records, not carried around as mutable session state. Easier to inspect, replay, and hand off.
|
|
104
|
+
- **One runtime across surfaces.** The same inbound pipeline runs across CLI, Telegram, and custom channels. Adapters change the surface, not the runtime model.
|
|
105
|
+
- **Batteries included.** CLI, Telegram, tools, skills, and model execution ship with the core runtime. Use the defaults first, replace them later.
|
|
106
|
+
- **Operator equivalence.** Humans and agents work inside the same runtime boundaries, with the same evidence trail and handoff model.
|
|
107
|
+
- **Embeddable Python SDK.** `pip install bub` installs only `bub.core`, which exposes the agent loop on its own (the CLI, channels and plugins come with `bub[app]`) — bring your own model, tools, prompts, and tape store, with no settings or plugins required.
|
|
108
|
+
|
|
109
|
+
## How It Works
|
|
110
|
+
|
|
111
|
+
Every inbound message goes through one turn pipeline. Each stage is a hook.
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
resolve_session → load_state → build_prompt → run_model
|
|
115
|
+
↓
|
|
116
|
+
dispatch_outbound ← render_outbound ← save_state
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Builtins are registered first and external plugins load after them, so later plugins take precedence. There are no framework-only shortcuts.
|
|
120
|
+
|
|
121
|
+
## Docs
|
|
122
|
+
|
|
123
|
+
- [Getting Started](https://bub.build/docs/getting-started/) — install Bub and run the first turn
|
|
124
|
+
- [Concepts](https://bub.build/docs/concepts/) — the mental model behind the runtime
|
|
125
|
+
- [Python SDK](https://bub.build/docs/build/sdk/) — embed Bub's agent loop in your own application
|
|
126
|
+
- [Build](https://bub.build/docs/build/) — write plugins, override hooks, ship tools and skills
|
|
127
|
+
- [Bub Hub](https://hub.bub.build) — browse community plugins, skills, and distributions
|
|
128
|
+
- [Channels](https://bub.build/docs/operate/channels/) — run Bub in CLI, Telegram, or your own channel
|
|
129
|
+
- [Deployment](https://bub.build/docs/operate/deploy/) — Docker, environment, upgrades
|
|
130
|
+
|
|
131
|
+
## Background
|
|
132
|
+
|
|
133
|
+
- [Why We Rewrote Bub](https://bub.build/posts/why-rewrite-bub/)
|
|
134
|
+
- [Socialized Evaluation and Agent Partnership](https://bub.build/posts/socialized-evaluation/)
|
|
135
|
+
- [Context from Tape](https://tape.systems)
|
|
136
|
+
|
|
137
|
+
## License
|
|
138
|
+
|
|
139
|
+
[Apache-2.0](https://github.com/bubbuild/bub/blob/main/LICENSE)
|
bub-0.6.0a2/README.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Bub
|
|
2
|
+
|
|
3
|
+
<div align="center">
|
|
4
|
+
|
|
5
|
+
<picture>
|
|
6
|
+
<source srcset="https://raw.githubusercontent.com/bubbuild/bub/refs/heads/main/website/src/assets/bub-logo-dark.png" media="(prefers-color-scheme: dark)">
|
|
7
|
+
<img alt="Bub logo" src="https://raw.githubusercontent.com/bubbuild/bub/refs/heads/main/website/src/assets/bub-logo.png" width="200">
|
|
8
|
+
</picture>
|
|
9
|
+
|
|
10
|
+
<p><strong>A tiny agent runtime, composable with plugins.</strong></p>
|
|
11
|
+
|
|
12
|
+
[Website](https://bub.build) · [Docs](https://bub.build/docs/getting-started/) · [Hub](https://hub.bub.build)
|
|
13
|
+
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
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.
|
|
17
|
+
|
|
18
|
+
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 replaceable, and the same runtime drives CLI, Telegram, and any channel you add.
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
macOS and Linux:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
curl -fsSL https://bub.build/install.sh | bash
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Windows PowerShell:
|
|
29
|
+
|
|
30
|
+
```powershell
|
|
31
|
+
powershell -ExecutionPolicy ByPass -c "irm https://bub.build/install.ps1 | iex"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Then:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
bub chat # interactive session
|
|
38
|
+
bub run "summarize this repo" # one-shot task
|
|
39
|
+
bub gateway # channel listener mode
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
See [Getting Started](https://bub.build/docs/getting-started/) for installer presets and source installs, and [Configure](https://bub.build/docs/operate/configure/) for model and runtime settings.
|
|
43
|
+
|
|
44
|
+
## Why Bub
|
|
45
|
+
|
|
46
|
+
- **Composable by design.** Every turn stage is a plugin hook. Override one stage or replace the whole flow without forking the runtime.
|
|
47
|
+
- **Tape context.** Context is rebuilt from append-only records, not carried around as mutable session state. Easier to inspect, replay, and hand off.
|
|
48
|
+
- **One runtime across surfaces.** The same inbound pipeline runs across CLI, Telegram, and custom channels. Adapters change the surface, not the runtime model.
|
|
49
|
+
- **Batteries included.** CLI, Telegram, tools, skills, and model execution ship with the core runtime. Use the defaults first, replace them later.
|
|
50
|
+
- **Operator equivalence.** Humans and agents work inside the same runtime boundaries, with the same evidence trail and handoff model.
|
|
51
|
+
- **Embeddable Python SDK.** `pip install bub` installs only `bub.core`, which exposes the agent loop on its own (the CLI, channels and plugins come with `bub[app]`) — bring your own model, tools, prompts, and tape store, with no settings or plugins required.
|
|
52
|
+
|
|
53
|
+
## How It Works
|
|
54
|
+
|
|
55
|
+
Every inbound message goes through one turn pipeline. Each stage is a hook.
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
resolve_session → load_state → build_prompt → run_model
|
|
59
|
+
↓
|
|
60
|
+
dispatch_outbound ← render_outbound ← save_state
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Builtins are registered first and external plugins load after them, so later plugins take precedence. There are no framework-only shortcuts.
|
|
64
|
+
|
|
65
|
+
## Docs
|
|
66
|
+
|
|
67
|
+
- [Getting Started](https://bub.build/docs/getting-started/) — install Bub and run the first turn
|
|
68
|
+
- [Concepts](https://bub.build/docs/concepts/) — the mental model behind the runtime
|
|
69
|
+
- [Python SDK](https://bub.build/docs/build/sdk/) — embed Bub's agent loop in your own application
|
|
70
|
+
- [Build](https://bub.build/docs/build/) — write plugins, override hooks, ship tools and skills
|
|
71
|
+
- [Bub Hub](https://hub.bub.build) — browse community plugins, skills, and distributions
|
|
72
|
+
- [Channels](https://bub.build/docs/operate/channels/) — run Bub in CLI, Telegram, or your own channel
|
|
73
|
+
- [Deployment](https://bub.build/docs/operate/deploy/) — Docker, environment, upgrades
|
|
74
|
+
|
|
75
|
+
## Background
|
|
76
|
+
|
|
77
|
+
- [Why We Rewrote Bub](https://bub.build/posts/why-rewrite-bub/)
|
|
78
|
+
- [Socialized Evaluation and Agent Partnership](https://bub.build/posts/socialized-evaluation/)
|
|
79
|
+
- [Context from Tape](https://tape.systems)
|
|
80
|
+
|
|
81
|
+
## License
|
|
82
|
+
|
|
83
|
+
[Apache-2.0](https://github.com/bubbuild/bub/blob/main/LICENSE)
|
|
@@ -20,22 +20,11 @@ classifiers = [
|
|
|
20
20
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
21
21
|
]
|
|
22
22
|
|
|
23
|
+
# The agent kernel, bub.core. Everything else (framework, CLI, channels, builtin agent) is in the `app` extra.
|
|
23
24
|
dependencies = [
|
|
25
|
+
"republic>=0.6.0a1",
|
|
24
26
|
"pydantic>=2.12.5",
|
|
25
|
-
"pydantic-settings>=2.14.2",
|
|
26
|
-
"pyyaml>=6.0.3",
|
|
27
|
-
"pluggy>=1.6.0",
|
|
28
|
-
"inquirer-textual>=0.8.0",
|
|
29
|
-
"typer>=0.24.1",
|
|
30
|
-
"authlib>=1.7.2",
|
|
31
|
-
"any-llm-sdk[anthropic]>=1.22.1",
|
|
32
|
-
"rich>=14.3.4",
|
|
33
|
-
"prompt-toolkit>=3.0.52",
|
|
34
|
-
"python-telegram-bot>=22.7",
|
|
35
27
|
"loguru>=0.7.3",
|
|
36
|
-
"rapidfuzz>=3.14.5",
|
|
37
|
-
"aiohttp>=3.14.3",
|
|
38
|
-
"httpx[socks]>=0.28.1",
|
|
39
28
|
"typing-extensions>=4.15.0",
|
|
40
29
|
]
|
|
41
30
|
|
|
@@ -45,21 +34,35 @@ Repository = "https://github.com/bubbuild/bub"
|
|
|
45
34
|
Documentation = "https://bub.build"
|
|
46
35
|
|
|
47
36
|
[project.scripts]
|
|
48
|
-
bub = "bub.__main__:
|
|
37
|
+
bub = "bub.__main__:main"
|
|
49
38
|
|
|
50
39
|
[project.optional-dependencies]
|
|
40
|
+
app = [
|
|
41
|
+
"pydantic-settings>=2.14.2",
|
|
42
|
+
"pyyaml>=6.0.3",
|
|
43
|
+
"pluggy>=1.6.0",
|
|
44
|
+
"inquirer-textual>=0.8.0",
|
|
45
|
+
"typer>=0.24.1",
|
|
46
|
+
"rich>=14.3.4",
|
|
47
|
+
"prompt-toolkit>=3.0.52",
|
|
48
|
+
"python-telegram-bot>=22.7",
|
|
49
|
+
"rapidfuzz>=3.14.5",
|
|
50
|
+
"aiohttp>=3.14.3",
|
|
51
|
+
"httpx[socks]>=0.28.1",
|
|
52
|
+
]
|
|
51
53
|
trace = [
|
|
52
54
|
"opentelemetry-api>=1.39.0",
|
|
53
55
|
"opentelemetry-sdk>=1.39.0",
|
|
54
56
|
"opentelemetry-exporter-otlp-proto-http>=1.39.0",
|
|
55
57
|
]
|
|
56
58
|
logfire = [
|
|
57
|
-
"bub[trace]",
|
|
59
|
+
"bub[app,trace]",
|
|
58
60
|
"logfire>=4.32.0",
|
|
59
61
|
]
|
|
60
62
|
|
|
61
63
|
[dependency-groups]
|
|
62
64
|
dev = [
|
|
65
|
+
"bub[app]",
|
|
63
66
|
"pytest>=9.0.3",
|
|
64
67
|
"tox-uv>=1.35.1",
|
|
65
68
|
"types-PyYAML>=6.0.12.20260408",
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Bub framework package.
|
|
2
|
+
|
|
3
|
+
The top-level names are imported on first access, so ``import bub.core`` does not load
|
|
4
|
+
the framework, its settings or the CLI.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
from importlib import import_module
|
|
11
|
+
from importlib.metadata import PackageNotFoundError
|
|
12
|
+
from importlib.metadata import version as metadata_version
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import TYPE_CHECKING, Any
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from bub.configure import Settings, config, ensure_config
|
|
18
|
+
from bub.core.tools import tool
|
|
19
|
+
from bub.framework import BubFramework
|
|
20
|
+
from bub.hooks import hookimpl
|
|
21
|
+
|
|
22
|
+
home: Path
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
"BubFramework",
|
|
26
|
+
"Settings",
|
|
27
|
+
"config",
|
|
28
|
+
"ensure_config",
|
|
29
|
+
"home",
|
|
30
|
+
"hookimpl",
|
|
31
|
+
"tool",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
_EXPORTS = {
|
|
35
|
+
"BubFramework": "bub.framework",
|
|
36
|
+
"Settings": "bub.configure",
|
|
37
|
+
"config": "bub.configure",
|
|
38
|
+
"ensure_config": "bub.configure",
|
|
39
|
+
"hookimpl": "bub.hooks",
|
|
40
|
+
"tool": "bub.core.tools",
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
try:
|
|
44
|
+
__version__ = import_module("bub._version").version
|
|
45
|
+
except ModuleNotFoundError:
|
|
46
|
+
try:
|
|
47
|
+
__version__ = metadata_version("bub")
|
|
48
|
+
except PackageNotFoundError:
|
|
49
|
+
__version__ = "0.0.0"
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def __getattr__(name: str) -> Any:
|
|
53
|
+
if name == "home":
|
|
54
|
+
# Importing bub.configure loads ``.env``, which may set ``BUB_HOME``.
|
|
55
|
+
from bub.configure import DEFAULT_HOME
|
|
56
|
+
|
|
57
|
+
if "BUB_HOME" in os.environ:
|
|
58
|
+
return Path(os.path.expanduser(os.environ["BUB_HOME"]))
|
|
59
|
+
return DEFAULT_HOME
|
|
60
|
+
if name not in _EXPORTS:
|
|
61
|
+
raise AttributeError(f"module {__name__} has no attribute {name}")
|
|
62
|
+
return getattr(import_module(_EXPORTS[name]), name)
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""Bub framework CLI bootstrap.
|
|
2
|
+
|
|
3
|
+
The CLI needs the ``app`` extra, so this module imports it only when the command runs:
|
|
4
|
+
``main`` reports missing requirements instead of failing on an import.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
import re
|
|
11
|
+
import sys
|
|
12
|
+
from importlib.metadata import PackageNotFoundError, distribution, requires
|
|
13
|
+
from typing import TYPE_CHECKING
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
import typer
|
|
17
|
+
|
|
18
|
+
LOG_LEVEL = {
|
|
19
|
+
0: "INFO",
|
|
20
|
+
1: "DEBUG",
|
|
21
|
+
2: "TRACE",
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
_APP_REQUIREMENT = re.compile(r"""^([A-Za-z0-9][A-Za-z0-9._-]*).*;.*\bextra\s*==\s*["']app["']""")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def missing_app_requirements() -> list[str]:
|
|
28
|
+
"""Return the distributions required by ``bub[app]`` that are not installed."""
|
|
29
|
+
try:
|
|
30
|
+
requirements = requires("bub") or []
|
|
31
|
+
except PackageNotFoundError: # Running from a source tree that is not installed.
|
|
32
|
+
return []
|
|
33
|
+
missing: list[str] = []
|
|
34
|
+
for requirement in requirements:
|
|
35
|
+
if (match := _APP_REQUIREMENT.match(requirement)) is None:
|
|
36
|
+
continue
|
|
37
|
+
try:
|
|
38
|
+
distribution(match.group(1))
|
|
39
|
+
except PackageNotFoundError:
|
|
40
|
+
missing.append(match.group(1))
|
|
41
|
+
return missing
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _instrument_bub(level: str) -> None:
|
|
45
|
+
from loguru import logger
|
|
46
|
+
|
|
47
|
+
logger.remove()
|
|
48
|
+
logger.add(sys.stderr, level=level, colorize=True, diagnose=False)
|
|
49
|
+
|
|
50
|
+
if os.getenv("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT") or os.getenv("OTEL_EXPORTER_OTLP_ENDPOINT"):
|
|
51
|
+
from bub.tracing import configure_otlp
|
|
52
|
+
|
|
53
|
+
try:
|
|
54
|
+
configure_otlp()
|
|
55
|
+
except Exception as exc:
|
|
56
|
+
logger.warning("OTLP instrumentation disabled: {}", exc)
|
|
57
|
+
return
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
import logfire
|
|
61
|
+
from logfire.integrations.loguru import LogfireHandler
|
|
62
|
+
|
|
63
|
+
logfire.configure()
|
|
64
|
+
logger.add(LogfireHandler(), level=level, format="{message}", diagnose=False)
|
|
65
|
+
except Exception as exc:
|
|
66
|
+
logger.debug("logfire instrumentation disabled: {}", exc)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def create_cli_app() -> typer.Typer:
|
|
70
|
+
import typer
|
|
71
|
+
|
|
72
|
+
from bub.builtin.settings import load_settings
|
|
73
|
+
from bub.framework import BubFramework
|
|
74
|
+
|
|
75
|
+
framework = BubFramework()
|
|
76
|
+
_instrument_bub(LOG_LEVEL[load_settings().verbose])
|
|
77
|
+
framework.load_hooks()
|
|
78
|
+
app = framework.create_cli_app()
|
|
79
|
+
|
|
80
|
+
if not app.registered_commands:
|
|
81
|
+
|
|
82
|
+
@app.command("help")
|
|
83
|
+
def _help() -> None:
|
|
84
|
+
typer.echo("No CLI command loaded.")
|
|
85
|
+
|
|
86
|
+
return app
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def main() -> None:
|
|
90
|
+
"""Run the ``bub`` command."""
|
|
91
|
+
if missing := missing_app_requirements():
|
|
92
|
+
sys.exit(
|
|
93
|
+
"The bub command needs the 'app' extra, which is not installed "
|
|
94
|
+
f"(missing: {', '.join(missing)}).\n"
|
|
95
|
+
"Install it with: uv tool install 'bub[app]' or pip install 'bub[app]'"
|
|
96
|
+
)
|
|
97
|
+
create_cli_app()()
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
if __name__ == "__main__":
|
|
101
|
+
main()
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.
|
|
22
|
-
__version_tuple__ = version_tuple = (0,
|
|
21
|
+
__version__ = version = '0.6.0a2'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 6, 0, 'a2')
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|