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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Below is the list of packages currently included in this repository.
| ------------------------------------------------------------------------------------ | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`packages/bub-codex`](./packages/bub-codex/README.md) | `codex` | Provides a `run_model` hook that delegates model execution to the Codex CLI. |
| [`packages/bub-cursor`](./packages/bub-cursor/README.md) | `cursor` | Provides a `run_model` hook that delegates model execution to the Cursor CLI, plus `bub login cursor`. |
| [`packages/bub-acp-server`](./packages/bub-acp-server/README.md) | `acp-server` | Exposes Bub as an Agent Client Protocol agent with `bub acp serve` for ACP-compatible editors. |
| [`packages/bub-tg-feed`](./packages/bub-tg-feed/README.md) | `tg-feed` | Provides an AMQP-based channel adapter for Telegram feed messages. |
| [`packages/bub-schedule`](./packages/bub-schedule/README.md) | `schedule` | Provides scheduling channel/tools backed by APScheduler with a JSON job store. |
| [`packages/bub-tapestore-sqlalchemy`](./packages/bub-tapestore-sqlalchemy/README.md) | `tapestore-sqlalchemy` | Provides a SQLAlchemy-backed tape store for Bub conversation history. |
Expand Down
106 changes: 106 additions & 0 deletions packages/bub-acp-server/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# bub-acp-server

Expose Bub as an Agent Client Protocol agent.

## What It Provides

- Bub plugin entry point: `acp-server`
- CLI command registered on Bub: `bub acp serve`
- Standalone console script: `bub-acp-server`
- ACP agent methods for `initialize`, `session/new`, `session/load`, `session/resume`, `session/list`, `session/close`, and `session/prompt`
- Streaming ACP `session/update` events from Bub stream events

## Installation

```bash
uv pip install "git+https://github.com/bubbuild/bub-contrib.git#subdirectory=packages/bub-acp-server"
```

Or from a Bub project:

```bash
bub install bub-acp-server@main
```

## Usage

Configure an ACP-compatible client to launch one of:

```bash
bub acp serve
```

or:

```bash
bub-acp-server
```

The process speaks ACP over stdio. Prompts are sent through Bub's hook pipeline with stream output enabled, so model chunks and tool events can be displayed by the ACP client as they arrive.

Bub keeps using its own configuration, tools, skills, and tapes. The ACP client starts the process and displays the session; it does not replace Bub's model setup.

ACP session metadata is stored under Bub home as `acp-sessions.json` so compatible clients can list sessions again after restarting. Keep `BUB_HOME` stable if you want the same ACP thread list across editor launches.

`bub-acp-server` supports both ACP session load and resume. `session/load` restores the matching Bub history through the same ACP streaming path used by live turns. `session/resume` attaches the editor back to the Bub session without replaying history, so later turns keep streaming through Bub's normal hook pipeline.

## Use In Zed

Zed supports external terminal agents through ACP. Custom agents are configured in Zed's `settings.json` under `agent_servers`.

Prerequisites:

- `bub` is installed and available to Zed.
- `bub-acp-server` is installed in the Bub environment:

```bash
bub install bub-acp-server@main
```

Open Zed's settings with the `zed: open settings` command and add a custom agent server:

```json
{
"agent_servers": {
"Bub": {
"type": "custom",
"command": "bub",
"args": ["acp", "serve"],
"env": {}
}
}
}
```

If Zed cannot find `bub`, use the absolute path printed by `command -v bub`:

```json
{
"agent_servers": {
"Bub": {
"type": "custom",
"command": "/absolute/path/to/bub",
"args": ["acp", "serve"],
"env": {}
}
}
}
```

After saving the settings, open Zed's agent panel with `cmd-?` on macOS or `ctrl-?` on Linux/Windows, then start a new thread and select `Bub`.

Useful Zed commands while testing:

- `dev: open acp logs` shows the JSON-RPC traffic between Zed and Bub.
- `zed: open settings` opens `settings.json`.

Notes:

- Zed launches Bub as a separate ACP process. Bub reads its own local configuration and credentials directly.
- Use `env` only for settings your Bub installation actually needs.
- If your Bub configuration is loaded from a project `.env`, use a wrapper command that loads that file before running `bub acp serve`.

References:

- Zed external agents documentation: https://zed.dev/docs/ai/external-agents
- Zed ACP client page: https://zed.dev/acp/editor/zed
29 changes: 29 additions & 0 deletions packages/bub-acp-server/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[project]
name = "bub-acp-server"
version = "0.1.0"
description = "Expose Bub as an ACP agent"
readme = "README.md"
authors = [
{ name = "Frost Ming", email = "me@frostming.com" }
]
requires-python = ">=3.12"
dependencies = [
"agent-client-protocol==0.10.1",
"bub",
]

[project.entry-points.bub]
acp-server = "bub_acp_server.plugin:ACPServerPlugin"

[project.scripts]
bub-acp-server = "bub_acp_server.cli:main"

[build-system]
requires = ["uv_build>=0.10.4,<0.11.0"]
build-backend = "uv_build"

[dependency-groups]
dev = [
"pytest>=9.0.3",
"pytest-asyncio>=0.21.0",
]
7 changes: 7 additions & 0 deletions packages/bub-acp-server/src/bub_acp_server/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"""Expose Bub as an ACP agent."""

from __future__ import annotations

__all__ = ["ACPServerPlugin", "BubACPAgent", "run_acp_agent"]

from bub_acp_server.plugin import ACPServerPlugin, BubACPAgent, run_acp_agent
13 changes: 13 additions & 0 deletions packages/bub-acp-server/src/bub_acp_server/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from __future__ import annotations

import asyncio

from bub.framework import BubFramework

from bub_acp_server.plugin import run_acp_agent


def main() -> None:
framework = BubFramework()
framework.load_hooks()
asyncio.run(run_acp_agent(framework))
12 changes: 12 additions & 0 deletions packages/bub-acp-server/src/bub_acp_server/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from __future__ import annotations

import bub
from pydantic_settings import SettingsConfigDict


@bub.config(name="acp-server")
class ACPServerSettings(bub.Settings):
model_config = SettingsConfigDict(env_prefix="BUB_ACP_SERVER_", extra="ignore")

channel_name: str = "acp-server"
send_user_message_updates: bool = False
Loading