A bridge connecting AI agents with chat applications, enabling interaction with AI programming assistants (such as Claude Code, Codex, OpenCode) through chat software like Mattermost, OpenAI-compatible interfaces, etc.
On your phone, continue the unfinished work from your computer.
The core design philosophy of Agent Bridge is separation of concerns and unified abstraction:
- Platform-Agent Separation: Chat platforms only handle message sending/receiving, AI agents only handle code generation and interaction, with Agent Bridge connecting them
- Unified Interface Design: All chat platforms implement the same
Platforminterface, all AI agents implement the sameAgentinterface, enabling plug-and-play functionality - Streaming Response Support: Supports streaming output, allowing users to see AI agent's thinking process and generation results in real-time
- Session State Management: Maintains binding relationships between chat sessions and AI agent sessions, supporting multi-turn conversations and session switching
Agent Bridge uses a callback-driven architecture rather than event-driven. This means:
- Platform only needs to call
HandleFunconce: No need to manage event channel lifecycle, no need for persistent goroutines listening for events, no need to handle channel closures - Agent directly invokes callbacks: When the agent wants to reply, it directly calls the
replycallback — Platform doesn't need to actively poll or wait - Purer separation of concerns: Platform only handles message sending/receiving, without needing to understand Agent's internal state and lifecycle
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Chat Apps │ │ Agent Bridge │ │ AI Agents │
│ (Mattermost, │───►│ │───►│ (Claude Code, │
│ OpenAI API, │ │ - Platform API │ │ Codex, │
│ etc.) │◄─┐ │ - Agent API │ │ OpenCode) │
└─────────────────┘ │ │ - Bridge Core │ └─────────────────┘
│ └─────────────────┘ │
│ │
└────── reply callback ◄─────────┘
Message Flow:
- User sends a message in the chat application
- Platform receives the message and converts it to a unified format
- Bridge processes the message (parses commands, manages sessions)
- Agent receives the prompt and calls the AI agent
- AI agent returns results, pushing them one by one through the reply callback
- Platform sends the results back to the chat application
Platform is an abstraction layer for chat applications, responsible for:
- Receiving messages from chat applications
- Converting messages to the unified
bridge.Messageformat - Calling
HandleFuncto process messages - Sending AI agent replies back to the chat application
type Platform interface {
Name() string
Serve(ctx context.Context, handle HandleFunc) error
Send(ctx context.Context, req *bridge.Message) (*bridge.Message, error)
}HandleFunc Signature:
type HandleFunc func(ctx context.Context, req *bridge.Message, reply bridge.ReplyFunc) errorreply is a callback function that is called each time the AI agent produces a response. For chat platforms supporting streaming output, messages can be sent immediately when reply is called; for scenarios requiring only final results, messages can be temporarily stored in the callback and used after the handle returns.
Agent is an abstraction layer for AI agents, responsible for:
- Managing AI agent sessions
- Sending prompts and retrieving responses
- Handling permission requests and user questions
- Retrieving session history and model information
type Agent interface {
// Model management
ListModels(ctx context.Context, directory string) ([]types.ModelInfo, error)
ResolveModel(ctx context.Context, spec, directory string) (types.ModelRef, error)
// Agent management
ListAgents(ctx context.Context, directory string) ([]types.AgentInfo, error)
// Session management
ListSessions(ctx context.Context, directory string) ([]types.Session, error)
CreateSession(ctx context.Context, request types.CreateSessionRequest) (*types.Session, error)
GetSession(ctx context.Context, sessionID string) (*types.Session, error)
// Message interaction
Prompt(ctx context.Context, sessionID string, prompt string, opts ...types.PromptOptionFunc) (*types.PromptHandle, error)
PollMessagesAfter(ctx context.Context, sessionID string, afterCompletedAt float64, output types.MessageOutputOptions) ([]*types.Message, error)
// Permission and question handling
ListPendingPermissions(ctx context.Context, sessionID string) ([]types.PermissionRequest, error)
ReplyPermission(ctx context.Context, sessionID string, requestID string, reply types.PermissionReply) error
ListPendingQuestions(ctx context.Context, sessionID string) ([]types.QuestionRequest, error)
ReplyQuestion(ctx context.Context, sessionID string, requestID string, answers [][]string) error
}Bridge is the core component, responsible for:
- Parsing user input (regular messages or slash commands)
- Managing session binding relationships
- Handling slash commands (
/new,/session,/model, etc.) - Coordinating interaction between Platform and Agent
# Build from source
git clone https://github.com/gitsang/agent-bridge.git
cd agent-bridge
go build -o agent-bridge ./cmd/agent-bridge
# Or use go install
go install github.com/gitsang/agent-bridge/cmd/agent-bridge@latestCreate configuration file config.yaml:
# Logging configuration
log:
handlers:
default: "default"
providers:
default:
- format: "json"
level: "info"
output:
stdout:
enable: true
# Platform configuration
platforms:
# OpenAI-compatible API (supports any OpenAI SDK client)
openai-compatible:
openai-compatible:
listen: ":24368"
# Mattermost integration
mattermost:
mattermost:
mode: "websocket" # webhook or websocket
websocket:
server_url: "https://mattermost.example.com"
ws_url: "wss://mattermost.example.com"
access_token: "your-bot-token"
# AI agent configuration
agent:
driver: claude # Supported: opencode, opencode2, codex, claude, pi, acp
claude:
command: "claude"
args:
- "-p"
- "--output-format"
- "stream-json"
- "--verbose"
timeout: 30m
# Session storage configuration
conversation:
store:
type: "sqlite" # memory, file, sqlite
path: "data/conversation.db"
ttl: 24h
max_items: 1024# Start with configuration file
./agent-bridge --config config.yaml
# Or use environment variables
export ANTHROPIC_API_KEY="your-api-key"
./agent-bridge --config config.yamlTest the OpenAI-compatible API using curl:
curl http://localhost:24368/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-4-20250514",
"messages": [
{"role": "user", "content": "Hello, how are you?"}
]
}'Provides standard OpenAI Chat Completions API interface, supporting any OpenAI SDK client.
platforms:
openai-compatible:
openai-compatible:
listen: ":24368" # Listen addressSuitable for scenarios where Mattermost cannot directly access Agent Bridge (such as internal network environments), actively connecting to Mattermost via WebSocket.
platforms:
mattermost:
mattermost:
mode: "websocket"
command_prefix: "!" # Command prefix, default "/"
websocket:
server_url: "https://mattermost.example.com"
ws_url: "wss://mattermost.example.com"
access_token: "bot-access-token"Receives messages through Mattermost's Outgoing Webhook or Slash Command.
platforms:
mattermost:
mattermost:
mode: "webhook"
webhook:
listen: ":24370"
token: "mattermost-token"
response_url_hosts:
- "mattermost.example.com"Uses Claude Code CLI's non-interactive mode as the AI agent.
agent:
driver: claude
claude:
command: "claude"
args:
- "-p"
- "--output-format"
- "stream-json"
- "--verbose"
timeout: 30mNotes:
- Use
--bareparameter to skip Claude Code's hooks, plugins, MCP and other features - Authentication via
ANTHROPIC_API_KEYenvironment variable - Current version does not support
/permissionand/questioncommands
Uses Codex app-server as the AI agent.
agent:
driver: codex
codex:
command: "codex"
args:
- "app-server"
- "--listen"
- "stdio://"
timeout: 30m
initialize_timeout: 15sUses OpenCode 1.x as the AI agent (default driver).
agent:
driver: opencode
opencode:
base_url: "http://127.0.0.1:4096"
timeout: 10m
db_path: "/root/.local/share/opencode/opencode.db"OpenCode 2 replaced the 1.x HTTP API with a new one under /api, so it has its
own driver. The server prints a password on startup unless you set one:
OPENCODE_SERVER_PASSWORD=changeit opencode serve --port 4096agent:
driver: opencode2
opencode2:
base_url: "http://127.0.0.1:4096"
username: "opencode" # OpenCode 2 requires this exact username
password: "changeit"
timeout: 30m
poll_interval: 1sNotes:
- Models, agents, permissions, and questions all map to the 2.x HttpApi
- A prompt is accepted immediately and the driver then waits for the session to become idle and for the log to advance past the prompt
- Session routes are scoped to a working directory, which the driver learns from the session payload and reuses
/session list --globalonly covers directories the bridge has seen, because the API has no cross-project session list
Drives the pi coding agent through its RPC mode.
agent:
driver: pi
pi:
command: "pi"
args: ["--mode", "rpc"]
env: {}
timeout: 30mNotes:
- Model and provider selection uses pi's own model catalog
- Extension dialogs (select, confirm, input, editor) are surfaced as
/question; pi has no per-tool permission prompt, so/permissionreports nothing - Cancelling a prompt sends
abortto pi
agent.driver: acp speaks the Agent Client Protocol
over a child process, so any ACP agent works without a dedicated driver.
DeepSeek Harness (dsh) is one such agent:
agent:
driver: acp
acp:
command: "dsh"
args: ["--profile", "acp"]
timeout: 30m
initialize_timeout: 30sOpenCode 2 and other ACP agents work the same way by changing command and
args:
agent:
driver: acp
acp:
command: "opencode"
args: ["acp"]Notes:
- Models come from the session configuration options the agent advertises, so the driver opens one throwaway session per directory to list them
/permissionmaps onto ACP permission requests, andonce/always/rejectchoose the matching option the agent offered/questionis not available over ACP; agents surface their prompts as permission requests instead- Sessions are listed through
session/listwhen the agent supports it
You can configure the types of messages returned by the AI agent:
agent:
message_output:
include:
- answer # Answer content
- reasoning # Thinking process
- action # Tool calls
- artifact # Code changes
- diagnostic # Diagnostic informationconversation:
store:
type: "sqlite" # memory, file, sqlite
path: "data/conversation.db" # File path (for file and sqlite types)
ttl: 24h # Session expiration time
max_items: 1024 # Maximum number of sessions
message:
include_user_identity: false # Whether to include user identity in messagesEnable debug logging:
log:
providers:
default:
- format: "json"
level: "debug"
verbosity: 3
output:
stdout:
enable: trueAgent Bridge supports the following slash commands:
# Create new session
/new [--model <provider/model|model>] [--agent <name>] [--directory <path>] [--title <title>]
# Session operations
/session attach <agent-session-id> # Bind to existing session
/session detach # Unbind current session
/session current # Show current session information
/session list [--directory <path>] # List sessions# Model management
/model set <provider/model|model> # Set default model
/model list # List available models
# Agent management
/agent set <name> # Set default agent
/agent list # List available agents# Set working directory
/directory set <path># Permission requests
/permission <once|always|reject> [id|index]
# Question answers
/question [id|index] <answer...>
/question reject [id|index]/help [new|session|model|agent|directory|permission|question]- OpenAI-compatible API (supports any OpenAI SDK client)
- Mattermost (WebSocket mode)
- Mattermost (Webhook mode)
- Slack (planned)
- OpenCode 1.x (default)
- OpenCode 2.x
- Claude Code
- Codex
- pi
- Any ACP agent (including DeepSeek Harness)
- Support Message command list
- Support agent multi-turn responses (pushing one by one through reply callback)
- Support SO/gRPC plugins
- Support Capability Claim
- Agent should not declare polling interfaces; for systems that don't support event push, polling should be wrapped to provide event-push semantics
- Use event callbacks instead of Message callbacks
Welcome to contribute code, report issues, or suggest improvements!
- Fork the project
- Create a feature branch:
git checkout -b feat/your-feature - Commit changes:
git commit -m 'feat: Add some feature' - Push the branch:
git push origin feat/your-feature - Create a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.