Intelligent agent bridge that connects IM channels with local ACP agents.
For a first-time setup, the least confusing path is:
- Install Baton
- Confirm the
batoncommand works - Install one ACP runtime
- Create a minimal config file, then start with Feishu
curl -fsSL https://raw.githubusercontent.com/williamfzc/baton/main/install.sh | bashThe install script automatically:
- detects your OS and architecture
- downloads the latest release
- installs to
XDG_BIN_HOMEif set, otherwise~/.local/bin
No sudo required.
After installation, run:
baton --helpIf the command is not found, your install directory is probably not in PATH yet. Add this to your shell config such as ~/.zshrc:
export PATH="$HOME/.local/bin:$PATH"Baton is the bridge. You still need an ACP runtime to execute tasks.
Supported options:
opencode: default runtime viaopencode acpcodex: usescodex-acpclaude-code: usesclaude-code-acp
If you already have opencode installed, you can usually keep the default executor. Otherwise, switch the executor in the config file.
Official repositories:
- Codex ACP: https://github.com/zed-industries/codex-acp
- Claude Code ACP: https://github.com/zed-industries/claude-code-acp
Verify commands:
opencode acp --help
codex-acp --help
claude-code-acp --helpThe recommended place is your project root as baton.config.json.
By default, Baton looks for these file names from the current directory upward for up to 5 levels:
baton.config.json.batonrc.jsonbaton.json
If you prefer another location, you can pass it explicitly:
baton --config /absolute/path/to/baton.config.json feishuFor a first run, this minimal config is enough, with Feishu as the default channel:
{
"project": {
"path": "/path/to/your/project",
"name": "my-project"
},
"language": "en",
"feishu": {
"appId": "cli_xxxxxxxxxxxxxxxx",
"appSecret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"domain": "feishu"
},
"acp": {
"executor": "opencode"
}
}The four values you usually need to replace are:
project.path: absolute path to your local projectproject.name: display name shown inside Batonfeishu.appId: your Feishu app IDfeishu.appSecret: your Feishu app secret
If you do not want to store secrets in the file, use environment variables instead:
export BATON_FEISHU_APP_ID=cli_xxx
export BATON_FEISHU_APP_SECRET=xxx
export BATON_EXECUTOR=opencodebaton feishuIf your config already contains feishu.appId and feishu.appSecret, you can also run:
batonIn that case, Baton auto-detects Feishu mode.
If you only want to verify the local agent chain first, start with CLI mode:
baton cliDownload from Releases:
baton-linux-x64baton-darwin-x64(Intel)baton-darwin-arm64(Apple Silicon)
chmod +x baton-*
mkdir -p ~/.local/bin
mv baton-* ~/.local/bin/batongit clone https://github.com/williamfzc/baton.git
cd baton
bun install
bun run start:cli| Platform | Status | Notes |
|---|---|---|
| Feishu | ✅ | WebSocket long-connection |
| Telegram | ✅ | Bot API long polling |
| ✅ | Webhook + Graph API | |
| Slack | ✅ | Events API webhook |
| CLI | ✅ | Local terminal interaction |
| Discord | 🔮 | Planned |
Baton is based on the ACP protocol and currently supports:
| Runtime | Command | Notes |
|---|---|---|
| opencode | opencode acp |
Default, requires opencode CLI |
| codex | codex-acp |
Requires codex-acp in PATH |
| claude | claude-code-acp |
Requires claude-code-acp in PATH |
Create baton.config.json:
{
"project": {
"path": "/path/to/your/project",
"name": "my-project"
},
"language": "en",
"feishu": {
"appId": "cli_xxxxxxxxxxxxxxxx",
"appSecret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"domain": "feishu"
},
"telegram": {
"botToken": "123456:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
"whatsapp": {
"permissionTimeout": 300,
"wacli": {
"bin": "wacli",
"storeDir": "~/.wacli",
"pollIntervalMs": 2000
}
},
"slack": {
"botToken": "xoxb-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"signingSecret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"port": 8081,
"webhookPath": "/webhook/slack"
},
"acp": {
"executor": "opencode"
}
}{
"acp": {
"executor": "codex",
"command": "codex-acp",
"args": [],
"cwd": ".",
"env": {
"OPENAI_API_KEY": "sk-***"
}
}
}executor: select default command (opencode/codex/claude-code)command+args: override default commandcwd: ACP working directory (relative to repo root)env: environment variables passed only to ACP child process
Switch executor via env:
export BATON_EXECUTOR=codexStore secrets in env:
export BATON_FEISHU_APP_ID=cli_xxx
export BATON_FEISHU_APP_SECRET=xxx
export BATON_TELEGRAM_BOT_TOKEN=123456:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
export BATON_SLACK_BOT_TOKEN=xoxb-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
export BATON_SLACK_SIGNING_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
export BATON_SLACK_API_BASE=https://slack.com/api
export BATON_SLACK_PORT=8081
export BATON_SLACK_WEBHOOK_PATH=/webhook/slack# Feishu mode
baton feishu
# Telegram mode
baton telegram
# WhatsApp mode
baton whatsapp
# Slack mode
baton slack
# CLI mode
baton cli
# Set language
baton --mode cli --lang zh-CN| Command | Usage | Description |
|---|---|---|
/repo |
/repo |
List repos and open selection |
/repo [index/name] |
/repo 2 or /repo my-repo |
Switch to target repo |
/current |
/current |
Show session, queue, task status |
/stop |
/stop |
Stop current task |
/stop [id] |
/stop 3 |
Stop specific task |
/stop all |
/stop all |
Stop current task and clear queue |
/reset |
/reset |
Reset current session |
/new |
/new |
Alias of /reset |
/mode |
/mode |
Open mode selection |
/mode [name] |
/mode code |
Switch Agent Mode directly |
/model |
/model |
Open model selection |
/model [name] |
/model gpt-5 |
Switch model directly |
/help |
/help |
Show help |
| Any text | fix this bug |
Forward prompt to ACP agent |
- Any slash command not in the list is forwarded as a normal prompt.
- For selections or permissions, prefer numeric replies (
1,2, ...). - Text replies also work:
allow/deny/cancel/yes/no/y/n, or the option name.
Apache 2.0 © Baton Contributors