Skip to content
Closed
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
23 changes: 22 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,32 @@ jobs:
python-version: ${{ matrix.python-version }}

- name: Run tests
run: uv run python -m pytest tests
run: uv run python -m pytest

- name: Check typing
run: uv run mypy

bubling-standalone:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.12", "3.13", "3.14"]
fail-fast: false
steps:
- name: Check out
uses: actions/checkout@v6

- name: Set up the environment
uses: ./.github/actions/setup-python-env
with:
python-version: ${{ matrix.python-version }}

# Install only bubling, without bub, so the kernel's tests prove it stands alone.
- name: Run bubling tests without bub
run: >-
uv run --isolated --no-project --python ${{ matrix.python-version }}
--with ./packages/bubling --with pytest --with pytest-asyncio
pytest packages/bubling/tests



Expand Down
12 changes: 10 additions & 2 deletions .github/workflows/on-release-main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,16 @@ jobs:
- name: Set up the environment
uses: ./.github/actions/setup-python-env

- name: Build package
run: uv build
# bub and bubling are released together: build both at the tag's version and pin bub to that bubling.
- name: Pin bubling to the release version
run: python scripts/release.py pin "${GITHUB_REF_NAME#v}"

- name: Build packages
# Pinning dirties the checkout, which would make hatch-vcs compute a dev version.
run: SETUPTOOLS_SCM_PRETEND_VERSION="${GITHUB_REF_NAME#v}" uv build --all-packages

- name: Check release metadata
run: python scripts/release.py check "${GITHUB_REF_NAME#v}" dist

- name: Publish package
run: uv publish --trusted-publishing always
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ repos:
- id: import-linter
name: import-linter
# Contracts live in pyproject.toml; grimp finds the packages through PYTHONPATH without installing them.
entry: env PYTHONPATH=src lint-imports
entry: env PYTHONPATH=src:packages/bubling/src lint-imports
language: python
additional_dependencies: ["import-linter==2.15"]
pass_filenames: false
files: ^(src/.*\.py|pyproject\.toml)$
files: ^((src|packages/[^/]+/src)/.*\.py|pyproject\.toml)$
15 changes: 10 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@

## Project Structure & Module Organization

Core code lives under `src/`:
Core code lives under `src/` and `packages/`:

- `src/bub/__main__.py`: Typer CLI entrypoint.
- `src/bub/core/`: agent kernel with no settings or plugin dependencies: agent loop over a tape store (`agent.py`), model protocol and Republic chat model adapter (`model.py`), agent events and their bus (`events.py`), the tape recorder handler (`recorder.py`), system prompt sections (`system_prompt.py`), command prompts (`commands.py`), tools, tape, store, and tape context, plus the kernel vocabulary it shares with the framework (`errors.py`, `prompt.py`, `streaming.py`, `tracing.py`, `turn.py`). Nothing in `bub.core` imports the rest of `bub`; the old top-level paths (`bub.errors`, `bub.store`, ...) are compatibility aliases.
- `packages/bubling/`: the agent kernel, published as the separate `bubling` distribution and released in lockstep with `bub`; it has no settings or plugin dependencies: agent loop over a tape store (`agent.py`), model protocol and Republic chat model adapter (`model.py`), agent events and their bus (`events.py`), the tape recorder handler (`recorder.py`), system prompt sections (`system_prompt.py`), command prompts (`commands.py`), tools, tape, store, and tape context, plus the kernel vocabulary it shares with the framework (`errors.py`, `prompt.py`, `streaming.py`, `tracing.py`, `turn.py`). Nothing in `bubling` imports `bub`. Its tests live in `packages/bubling/tests/` and must run with only `bubling` installed.
- `src/bub/{errors,tracing,streaming,store,tape,tools,sidecars}.py`: compatibility aliases of the `bubling` modules of the same name.
- `src/bub/framework.py`: turn orchestration and outbound routing.
- `src/bub/hooks/`: hook specifications, execution helpers, and interception contracts.
- `src/bub/channels/`: channel bases, routing contracts, admission policy, and lifecycle manager.
- `src/bub/{envelope,turn,model_selection}.py`: small framework vocabulary owned by each concern.
- `src/bub/builtin/`: builtin runtime: `BubAgent` (a `bub.core.Agent` subclass adding settings, skills, commands, steering), `BubModel`, tape archiving, CLI wiring, tools, tape services, and the fuzzy-searching file tape store.
- `src/bub/builtin/`: builtin runtime: `BubAgent` (a `bubling.Agent` subclass adding settings, skills, commands, steering), `BubModel`, tape archiving, CLI wiring, tools, tape services, and the fuzzy-searching file tape store.
- `src/bub/channels/`: channel abstractions plus CLI and Telegram adapters.
- `src/bub/skills.py` / `src/bub/tools.py`: skill discovery and tool registry.
- `src/skills/`: bundled skills shipped with Bub.
Expand All @@ -26,10 +27,13 @@ Tests live in `tests/`. The website and docs runtime lives in `website/`.
- `uv run bub run "hello"`: run one inbound message through the full framework pipeline.
- `uv run bub hooks`: inspect discovered hook bindings.
- `uv run ruff check .`: run Ruff directly when you only want lint feedback.
- `uv run mypy src`: run mypy directly against `src/`.
- `uv run prek run import-linter -a`: check the import contracts in `pyproject.toml` (`bub.core` must not import the rest of `bub` or application dependencies); `prek` and `make check` run it too.
- `uv run mypy`: run mypy against `src/` and `packages/bubling/src/`.
- `uv run prek run import-linter -a`: check the import contracts in `pyproject.toml` (`bubling` must not import `bub` or application dependencies); `prek` and `make check` run it too.
- `uv run pytest -q`: run the main test suite without doctests.
- `make test`: run pytest with doctests enabled.
- `uv run --isolated --no-project --with ./packages/bubling --with pytest --with pytest-asyncio pytest packages/bubling/tests`: run `bubling`'s tests with only `bubling` installed, as CI does.
- `make build`: build the distributions of both `bub` and `bubling`.
- Releases: publishing a GitHub release builds `bub` and `bubling` at the tag's version, with `bub` pinned to `bubling==<tag>` by `scripts/release.py` (the repository keeps a range for development). Rehearse with `python scripts/release.py pin X`, `SETUPTOOLS_SCM_PRETEND_VERSION=X uv build --all-packages`, `python scripts/release.py check X dist`, then revert `pyproject.toml`.
- `make check`: lock validation, `prek` (including import contracts), and typing.
- `make docs` / `make docs-test` / `make docs-preview`: serve, build, or preview the Astro website/docs in `website/`.

Expand All @@ -43,6 +47,7 @@ Tests live in `tests/`. The website and docs runtime lives in `website/`.
## Testing Guidelines
- Framework: `pytest`.
- Name test files `tests/test_<feature>.py`.
- Tests that need only the kernel go in `packages/bubling/tests/` and must not import `bub` or `tests`.
- Prefer behavior-oriented test names such as `test_gateway_uses_enabled_channels_only`.
- Cover hook precedence, turn lifecycle, CLI/channel behavior, and tape persistence when changing runtime behavior.
- Update or add tests in the same change when behavior moves.
Expand Down
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ WORKDIR /app
COPY pyproject.toml uv.lock README.md LICENSE entrypoint.sh ./
# Copy the full source and install
COPY src ./src
COPY packages ./packages
RUN uv sync --locked --no-dev --no-editable && \
chmod +x /app/entrypoint.sh

Expand Down
10 changes: 5 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ install: ## Sync Python deps, install website deps, and install prek hooks
@echo "==> Installing prek hooks"
uv run prek install

check: ## Validate lockfile, run prek across the repo, and type-check src
check: ## Validate lockfile, run prek across the repo, and type-check
@echo "==> Verifying uv.lock matches pyproject.toml"
uv lock --locked
@echo "==> Running prek hooks"
uv run prek run -a
@echo "==> Running mypy on src"
uv run mypy src
@echo "==> Running mypy"
uv run mypy

vulture: ## Run the optional unused-code check
@echo "==> Running vulture via prek"
Expand All @@ -33,9 +33,9 @@ clean-build: ## Remove local build artifacts
@echo "==> Removing dist/"
rm -rf dist

build: clean-build ## Build source and wheel distributions
build: clean-build ## Build source and wheel distributions of bub and bubling
@echo "==> Building package distributions"
uv build
uv build --all-packages

publish: ## Publish the contents of dist/ with uv
@echo "==> Publishing dist/ with uv"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ See [Getting Started](https://bub.build/docs/getting-started/) for installer pre
- **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.
- **Embeddable Python SDK.** `bub.core` exposes the agent loop on its own — bring your own model, tools, prompts, and tape store, with no settings or plugins required.
- **Embeddable Python SDK.** The [`bubling`](packages/bubling) package exposes the agent loop on its own — bring your own model, tools, prompts, and tape store, with no settings or plugins required.

## How It Works

Expand Down
Loading
Loading