A bridge service connecting DingTalk chatbot to OpenCode AI assistant with real-time streaming response support.
- DingTalk Stream Integration: Receive messages via DingTalk Stream mode (no public IP required)
- Interactive Card Streaming: Real-time typewriter effect using DingTalk interactive cards
- Session Management: Persistent sessions with configurable timeout (default 8 hours)
- Tool Whitelist: Security-focused tool restriction via TypeScript plugin
- Graceful Shutdown: Clean termination with signal handling
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ DingTalk │ │ dingtalk-bridge │ │ OpenCode │
│ (Stream SDK) │◄───►│ (Go) │◄───►│ Server API │
└─────────────────┘ └──────────────────┘ └─────────────────┘
│
▼
┌──────────────────┐
│ Plugin │
│ (TypeScript) │
└──────────────────┘
- Go 1.23+ - Install from https://go.dev/
- OpenCode CLI - Install from https://opencode.ai/
- DingTalk Bot App - Create at https://open-dev.dingtalk.com
brew install gogit clone <your-repo-url>
cd dingtalk-bridge
cp .env.example .envEdit .env with your credentials:
# DingTalk App Credentials (from developer console)
DINGTALK_CLIENT_ID=your_client_id
DINGTALK_CLIENT_SECRET=your_client_secret
# OpenCode Server
OPENCODE_SERVER_PASSWORD=your_secure_passwordOPENCODE_SERVER_PASSWORD=your_secure_password opencode servemake deps
make run| Variable | Required | Default | Description |
|---|---|---|---|
DINGTALK_CLIENT_ID |
Yes | - | DingTalk app Client ID |
DINGTALK_CLIENT_SECRET |
Yes | - | DingTalk app Client Secret |
OPENCODE_SERVER_URL |
No | http://127.0.0.1:4096 |
OpenCode server URL |
OPENCODE_SERVER_PASSWORD |
Yes | - | OpenCode server password |
BRIDGE_MODE |
No | advanced |
Streaming mode: advanced or mvp |
SESSION_TIMEOUT |
No | 28800 |
Session timeout in seconds (8 hours) |
LOG_LEVEL |
No | info |
Log level: debug, info, warn, error |
| Mode | Description | Best For |
|---|---|---|
advanced |
Interactive card streaming with typewriter effect | Best UX |
mvp |
Multi-message fallback | Compatibility |
Edit config/tool_whitelist.json to configure allowed/blocked tools:
{
"default_allowed": ["read", "glob", "grep"],
"default_blocked": ["bash", "write", "edit"],
"user_overrides": {
"user_id_here": {
"allowed": ["write", "edit"],
"blocked": []
}
}
}dingtalk-bridge/
├── cmd/dingtalk-bridge/main.go # Entry point
├── internal/
│ ├── config/config.go # Configuration management
│ ├── logger/logger.go # Structured logging
│ ├── dingtalk/
│ │ ├── client.go # Stream SDK client
│ │ ├── card_client.go # Interactive card API
│ │ ├── card_template.go # Card templates
│ │ └── replier.go # Text reply fallback
│ ├── opencode/
│ │ ├── server_client.go # HTTP API client
│ │ └── sse_reader.go # SSE event parser
│ ├── session/store.go # Session persistence
│ └── bridge/router.go # Message routing
├── plugins/
│ └── dingtalk-guard.ts # TypeScript guard plugin
├── config/
│ ├── tool_whitelist.json # Tool whitelist config
│ └── user_whitelist.json # User whitelist config
├── Makefile
├── go.mod
├── .env.example
└── README.md
make buildmake testLOG_LEVEL=debug make run- Go to https://open-dev.dingtalk.com
- Create a new application
- Enable "机器人" (Bot) feature
- Copy Client ID and Client Secret to
.env - Configure message receiving mode: Stream
- Localhost Only: Bridge binds to
127.0.0.1only - Password Protected: OpenCode server requires authentication
- Tool Whitelist: Dangerous tools blocked by default
- User Whitelist: Optional DingTalk user restrictions
- Verify DingTalk credentials are correct
- Check network connectivity to
api.dingtalk.comandwss-open-connection.dingtalk.com - Ensure OpenCode server is running
- Check if
BRIDGE_MODE=advanced - Verify DingTalk app has card permissions
- Check logs for API errors
- Review
config/tool_whitelist.json - Add user-specific overrides if needed
- Check plugin is loaded correctly
MIT
- Fork the repository
- Create a feature branch
- Make your changes
- Run tests
- Submit a pull request