From the project root:
cd xbot
cargo run --release -- onboardFor packaged installs through npm, .deb, or cargo install, see Installation.
This creates:
~/.xbot/config.json~/.xbot/workspace/- a hidden runtime state directory at
<workspace>/.xbot/ - workspace bootstrap files such as
.xbot/AGENTS.md,.xbot/SOUL.md,.xbot/USER.md,.xbot/TOOLS.md,.xbot/HEARTBEAT.md, and memory files - starter workspace skills under
.xbot/skills/, including a memory-hygiene skill and editable project templates
Instead of manually editing ~/.xbot/config.json, you can use the interactive CLI:
Configure your LLM providers (OpenAI, Anthropic, OpenRouter, Ollama, vLLM, etc.):
cargo run --release -- config --providerThe CLI will guide you through:
- Selecting a provider from the list.
- Entering your API key (if required).
- Fetching and selecting from available models.
- Setting the default model and provider for the agent.
- Optionally configuring a separate provider/API base or model for background subagents.
Configure communication channels (Telegram, Slack, Email, etc.):
cargo run --release -- config --channelYou can selectively enable channels, set permissions (allowFrom), and provide necessary tokens or secrets interactively.
xbot talks to providers through an OpenAI-compatible chat interface.
Supported practical modes:
- Remote API providers such as OpenAI-compatible gateways
- Local engines such as Ollama and vLLM
- Custom local or remote OpenAI-compatible servers
{
"agents": {
"defaults": {
"model": "minimax/minimax-m2.7",
"provider": "openrouter"
}
},
"providers": {
"openrouter": {
"apiKey": "sk-or-v1-...",
"extraHeaders": {}
}
}
}{
"agents": {
"defaults": {
"model": "openai/gpt-4.1-mini",
"provider": "openai"
}
},
"providers": {
"openai": {
"apiKey": "sk-..."
}
}
}xbot supports Ollama as a local provider without requiring an API key.
Start Ollama first:
ollama serve
ollama pull qwen2.5-coder:7bThen configure:
{
"agents": {
"defaults": {
"model": "ollama/qwen2.5-coder:7b",
"provider": "ollama"
}
},
"providers": {
"ollama": {
"apiBase": "http://localhost:11434/v1"
}
}
}If you are serving a model with vLLM on port 8000:
{
"agents": {
"defaults": {
"model": "vllm/Qwen/Qwen2.5-7B-Instruct",
"provider": "vllm"
}
},
"providers": {
"vllm": {
"apiBase": "http://localhost:8000/v1"
}
}
}Use the custom provider:
{
"agents": {
"defaults": {
"model": "custom/local-model",
"provider": "custom"
}
},
"providers": {
"custom": {
"apiBase": "http://127.0.0.1:1234/v1",
"apiKey": ""
}
}
}Notes:
- Known local providers such as
ollamaandvllmdo not require an API key. - Custom providers can use an empty API key when the upstream server does not require auth.
- The model string can be any identifier accepted by the target backend.
By default, background subagents use the same provider and model as the main task. You can run subagents on a cheaper or faster model by setting agents.subagents.
For a complete remote-main/local-subagent walkthrough, including DeepSeek deepseek-v4-pro as the main model and a local Qwen model for subagents, see Hybrid Remote Main + Local Subagents.
Example: main task uses a heavier OpenAI model, while subagents use a local OpenAI-compatible server:
{
"agents": {
"defaults": {
"model": "openai/gpt-4.1",
"provider": "openai"
},
"subagents": {
"model": "qwen2.5-coder:7b",
"provider": "subagent-fast",
"apiBase": "http://127.0.0.1:8001/v1"
}
},
"providers": {
"openai": {
"apiKey": "sk-..."
},
"subagent-fast": {
"apiKey": "",
"apiBase": "http://127.0.0.1:8001/v1"
}
}
}agents.subagents.model is optional. If it is empty or omitted, subagents inherit the main task model. agents.subagents.provider defaults to "auto". For an OpenAI-compatible local or remote backend, use a provider key such as subagent-fast and set apiBase either under agents.subagents or in the matching providers entry.
cargo run --release -- chat "summarize the codebase"cargo run --release -- replThe interactive shell is designed for day-to-day agent work:
replandchatbootstrap the current directory as a project workspace by creating<cwd>/.xbot/by default- persistent command history in
<workspace>/.xbot/history.txt - streamed model output instead of waiting for the full reply
- queued prompts while a turn is already running; queued turns start automatically when the current turn ends
- local shell commands:
/help,/clear,/exit - agent commands forwarded to the runtime:
/new,/status,/stop - multiline input by ending a line with
\ - the welcome header shows both the current working directory and the active workspace
- the header also shows the active hidden state root under
<workspace>/.xbot - tool activity is shown with emoji-based pills such as file, shell, web, message, and cron actions
- fenced code blocks in replies are syntax-highlighted in the CLI by language when ANSI colors are available
- CLI session history is scoped by current working directory, so different projects do not share the same chat thread
To force repl or chat to use the configured global workspace, pass --global:
xbot repl --globalTo use a specific workspace path instead, pass --workspace:
xbot repl --workspace ~/.xbot/workspacexbot uses two memory files inside workspace/.xbot/:
.xbot/memory/MEMORY.md: permanent memory store, capped atagents.defaults.memoryMaxBytesbytes.xbot/memory/HISTORY.md: resettable history log for later search and consolidation
Operational rule:
- completed user tasks are summarized into
MEMORY.mdwith title, summary, attention points, and finish time through thememory-entry-writerskill - explicit
memorizeor/memorize <text>requests are summarized through the same skill and stored inMEMORY.mdas user instructed memory - new tasks load only topic-relevant slices from
MEMORY.md, not the entire file clear//clear/new//newresets the current session and restoresHISTORY.mdto the default template
New workspaces now include starter guidance, an always-on memory skill, and a dedicated memory-entry-writer skill so memory writes stay compact instead of copying large reply fragments.
Example config:
{
"agents": {
"defaults": {
"memoryMaxBytes": 32768
}
}
}cargo run --release -- runrun uses the workspace configured in ~/.xbot/config.json by default. To run the backend against a project-local workspace, pass it explicitly:
xbot run --workspace .run starts:
- the provider client
- the agent runtime
- cron jobs
- heartbeat review
- enabled channels
- the HTTP gateway
- the admin API and UI
- the metrics endpoint
Slack supports two practical modes in xbot:
webhook: Slack sends Events API requests to your public HTTPS endpointsocket:xbotopens an outbound WebSocket to Slack and does not require a public webhook URL (Public)
Example Socket Mode config:
{
"channels": {
"slack": {
"enabled": true,
"mode": "socket",
"allowFrom": ["*"],
"botToken": "xoxb-...",
"appToken": "xapp-...",
"replyInThread": true,
"groupPolicy": "mention"
}
}
}Notes:
mode: "socket"requires bothbotTokenandappToken- you do not need
signingSecretor a public/slack/eventsURL in socket mode - in webhook mode, you still need a public HTTPS URL configured in Slack Event Subscriptions
When run is active, the gateway exposes:
GET /healthzGET /readyzGET /statusGET /metricsGET /adminGET /api/admin/overviewGET /api/admin/sessionsGET /api/admin/cron
The bind address comes from:
{
"gateway": {
"host": "0.0.0.0",
"port": 18790
}
}Admin and metrics paths can also be customized:
{
"gateway": {
"admin": {
"enabled": true,
"path": "/admin"
},
"metrics": {
"enabled": true,
"path": "/metrics"
}
}
}Email is polling-driven and does not require webhooks.
{
"channels": {
"email": {
"enabled": true,
"allowFrom": ["*"],
"consentGranted": true,
"imapHost": "imap.example.com",
"imapPort": 993,
"imapUsername": "bot@example.com",
"imapPassword": "...",
"imapMailbox": "INBOX",
"imapUseSsl": true,
"smtpHost": "smtp.example.com",
"smtpPort": 587,
"smtpUsername": "bot@example.com",
"smtpPassword": "...",
"smtpUseTls": true,
"fromAddress": "bot@example.com",
"autoReplyEnabled": true,
"pollIntervalSeconds": 30
}
}
}Slack is currently webhook-driven in xbot.
{
"channels": {
"sendProgress": true,
"sendToolHints": false,
"slack": {
"enabled": true,
"allowFrom": ["*"],
"botToken": "xoxb-...",
"signingSecret": "...",
"webhookPath": "/slack/events",
"replyInThread": true,
"groupPolicy": "mention"
}
}
}Operational notes:
signingSecretis required for startup validation.- Point Slack event subscriptions at
http://<host>:<port>/slack/events. - Send software-development tasks as normal messages or mentions, for example:
review this repo, run tests, and fix failures. channels.sendToolHintsdefaults tofalse; in that mode,xbotsends a muted-tool notice on the first tool call and batch summaries every 10 tool calls or before the next non-tool reply.- Set
channels.sendToolHintstotrueif you want every tool execution hint sent back to Slack while a task is running.
Telegram is currently webhook-driven in xbot.
{
"channels": {
"sendProgress": true,
"sendToolHints": false,
"telegram": {
"enabled": true,
"allowFrom": ["*"],
"token": "<bot-token>",
"webhookPath": "/telegram/webhook",
"webhookSecret": "optional-shared-secret",
"replyToMessage": true,
"groupPolicy": "mention"
}
}
}Set the Telegram webhook externally to:
https://<your-domain>/telegram/webhook
If webhookSecret is configured, Telegram requests must include the matching secret header.
Usage notes:
- Send development or analysis tasks as plain messages to the bot.
- In groups,
groupPolicy: "mention"keeps the bot from reacting to every message. channels.sendToolHintsdefaults tofalse; in that mode,xbotsends a muted-tool notice on the first tool call and batch summaries every 10 tool calls or before the next non-tool reply.- Set
channels.sendToolHintstotrueif you want every tool execution hint sent back to Telegram while a task is running.
Feishu runs through the webhook gateway and supports inbound text, post, interactive cards, replies, and media/resource download.
{
"channels": {
"sendProgress": true,
"sendToolHints": false,
"feishu": {
"enabled": true,
"allowFrom": ["*"],
"appId": "cli_xxx",
"appSecret": "...",
"verificationToken": "...",
"webhookPath": "/feishu/events",
"groupPolicy": "mention",
"replyToMessage": true,
"reactEmoji": "THUMBSUP"
}
}
}Point Feishu event subscriptions at:
https://<your-domain>/feishu/events
Usage notes:
- Mention the bot in group chats when using
groupPolicy: "mention". - Development tasks can be sent as normal text instructions, and Feishu replies can include dedicated tool-hint cards during execution.
channels.sendToolHintsdefaults tofalse; in that mode,xbotsends a muted-tool notice on the first tool call and batch summaries every 10 tool calls or before the next non-tool reply.- Set
channels.sendToolHintstotrueif you want every tool execution hint card sent back during execution. Non-tool progress messages are still controlled bychannels.sendProgress.
{
"agents": {
"defaults": {
"workspace": "~/.xbot/workspace",
"model": "ollama/qwen2.5-coder:7b",
"provider": "ollama",
"maxToolIterations": 0,
"contextWindowTokens": 65536
},
"subagents": {
"model": "",
"provider": "auto"
}
},
"providers": {
"ollama": {
"apiBase": "http://localhost:11434/v1"
}
},
"gateway": {
"host": "0.0.0.0",
"port": 18790,
"heartbeat": {
"enabled": true,
"intervalS": 1800
}
},
"channels": {
"telegram": {
"enabled": true,
"allowFrom": ["*"],
"token": "<bot-token>",
"webhookPath": "/telegram/webhook"
}
}
}maxToolIterations: 0 means the agent loop is unbounded. Use a positive number only when you want a hard ceiling on tool calls.
xbot supports MCP over stdio. Enabled MCP tools are registered as native tools using names like mcp_<server>_<tool>.
Example:
{
"tools": {
"mcpServers": {
"github": {
"enabled": true,
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"enabledTools": ["*"],
"toolTimeout": 30
}
}
}
}Current scope:
stdiotransport is supported- startup validation fails fast if an enabled MCP server has no command
- unsupported transports are rejected during startup
Built-in skills ship with the repository under xbot/skills/.
Current built-in set:
memory-hygiene(always-on)memory(always-on)memory-entry-writerworkspace-operatorsoftware-engineerdata-analystgithub-cligithubscheduled-opscronclawhubskill-creatorsummarizeweathertmux
Behavior:
- always-on skills are injected automatically
- relevant task-specific skills are suggested and loaded based on prompt keywords
- skills with unmet requirements (missing binaries, env vars, or OS) are marked unavailable
- workspace-local skills live under
<workspace>/.xbot/skills/<name>/SKILL.md - new workspaces also get starter workspace skill templates that you can edit for project-specific context and delivery rules
List all skills and their availability:
cargo run -- skills listScaffold a new skill:
cargo run -- skills init my-custom-skillThis creates <workspace>/.xbot/skills/my-custom-skill/SKILL.md with a starter template.
Print the resolved config:
cargo run -- print-configRun a different model without changing config:
cargo run --release -- run --model ollama/qwen2.5-coder:7bStart a one-shot request against a specific model:
cargo run --release -- chat --model ollama/qwen2.5-coder:7b "list the next implementation tasks"Inspect runtime state without starting the daemon:
cargo run -- sessions # List active chat sessions
cargo run -- jobs # List scheduled cron jobs
cargo run -- print-config # Print current resolved config
cargo run -- config --provider # Interactive provider setup
cargo run -- config --channel # Interactive channel setupcargo run -- channels list # List all available channels
cargo run -- channels status # Show enabled/disabled state per channel
cargo run -- channels login # Interactive login (e.g. Weixin QR code scan)
cargo run -- channels login weixin # Login to a specific channel
cargo run -- channels setup # Show setup instructions for a channel
cargo run -- channels setup discord # Setup instructions for a specific channelcargo run -- skills list # List skills with availability status
cargo run -- skills init NAME # Scaffold a new skill directoryrunvalidates enabled channel config before startup.runalso validates enabled MCP server configuration before startup.- Local providers are accepted without API keys when the provider is recognized as local.
- Outbound runtime/system errors are surfaced through the runtime logs instead of being silently dropped.
- Feishu media downloads are stored under
~/.xbot/media/feishu. - The admin UI polls the runtime every few seconds and exposes channel controls plus heartbeat triggering.
- The metrics endpoint exposes Prometheus-compatible counters and gauges for message counts, provider requests, token totals, latency, and throughput.
Each channel section below includes how to obtain the required credentials and the config format. You can also run xbot channels setup <name> to see setup instructions in the terminal.
DingTalk uses the Stream gateway WebSocket protocol.
How to obtain credentials:
- Go to https://open-dev.dingtalk.com and create a robot application
- Under Credentials, copy the Client ID (AppKey) and Client Secret (AppSecret)
- Under Robot, enable the robot and copy the Robot Code
{
"channels": {
"dingtalk": {
"enabled": true,
"allowFrom": ["*"],
"clientId": "<AppKey from developer console>",
"clientSecret": "<AppSecret from developer console>",
"robotCode": "<Robot Code>"
}
}
}Discord connects via the Gateway v10 WebSocket.
How to obtain credentials:
- Go to https://discord.com/developers/applications and create an application
- Under Bot, click "Add Bot" and copy the bot token
- Under Bot, enable "Message Content Intent" in Privileged Gateway Intents
- Under OAuth2 > URL Generator, select
botscope withSend Messagespermission - Use the generated URL to invite the bot to your server
{
"channels": {
"discord": {
"enabled": true,
"allowFrom": ["*"],
"botToken": "<your-bot-token>",
"groupPolicy": "mention"
}
}
}groupPolicy options: "mention" (respond only when @mentioned), "open" (respond to all messages).
Matrix uses the CS API v3 long-poll /sync endpoint.
How to obtain credentials:
- Create a bot account on your Matrix homeserver
- Obtain an access token (e.g. via Element: Settings > Help & About > Access Token)
- Note the full user ID (e.g.
@bot:example.com) - Invite the bot to the rooms where it should respond
{
"channels": {
"matrix": {
"enabled": true,
"allowFrom": ["*"],
"homeserverUrl": "https://matrix.example.com",
"accessToken": "<your-access-token>",
"userId": "@bot:example.com"
}
}
}Note: End-to-end encrypted rooms (m.room.encrypted) are not supported; the bot will skip encrypted messages.
WhatsApp connects to a Node.js Baileys bridge via WebSocket.
Setup steps:
- Install Node.js v18+
- Clone the Baileys bridge:
git clone https://github.com/nicepkg/whatsapp-bridge cd whatsapp-bridge && npm install && npm start- Scan the QR code displayed in the bridge terminal with WhatsApp
- The bridge saves auth state — subsequent starts reconnect automatically
Run xbot channels login whatsapp for step-by-step guidance.
{
"channels": {
"whatsapp": {
"enabled": true,
"allowFrom": ["*"],
"bridgeUrl": "ws://localhost:3001",
"bridgeToken": "",
"groupPolicy": "open"
}
}
}The bridge must be running before xbot run. Set bridgeToken if your bridge instance requires authentication.
QQ uses the QQ Bot API with WebSocket gateway.
How to obtain credentials:
- Go to https://q.qq.com and register as a QQ Bot developer
- Create a bot application and obtain the App ID and Secret
- Configure the bot's intents and permissions in the developer console
{
"channels": {
"qq": {
"enabled": true,
"allowFrom": ["*"],
"appId": "<your-app-id>",
"secret": "<your-secret>"
}
}
}WeCom (Enterprise WeChat) uses the AI Bot WebSocket protocol.
How to obtain credentials:
- Log in to https://work.weixin.qq.com admin console
- Create a self-built application under App Management
- Note the Corp ID (from My Enterprise), Agent ID, and Secret
{
"channels": {
"wecom": {
"enabled": true,
"allowFrom": ["*"],
"corpId": "<your-corp-id>",
"agentId": "<your-agent-id>",
"secret": "<your-secret>"
}
}
}All three fields (corpId, agentId, secret) are required — agentId/secret for WebSocket auth, corpId for outbound message delivery.
Weixin (personal WeChat) uses HTTP long-poll with QR code login via the ilinkai API.
Login flow:
- Enable the channel in config (no token needed initially)
- Run
xbot channels login weixin— a QR code URL will be printed - Open the URL in WeChat and scan to authorize
- The token is saved to
<stateDir>/account.jsonfor future sessions
Alternatively, run xbot run and the QR login starts automatically if no saved token is found.
{
"channels": {
"weixin": {
"enabled": true,
"allowFrom": ["*"]
}
}
}Mochat connects to a Mochat/OpenClaw instance via HTTP polling.
How to obtain credentials:
- Obtain a Claw Token from your Mochat or OpenClaw instance admin
- Note the session IDs and/or panel IDs you want the bot to monitor
{
"channels": {
"mochat": {
"enabled": true,
"allowFrom": ["*"],
"baseUrl": "https://your-instance.com",
"clawToken": "<your-token>",
"sessions": ["session-id-1"],
"panels": []
}
}
}Anthropic is supported natively with the Messages API:
{
"agents": {
"defaults": {
"model": "anthropic/claude-sonnet-4-20250514",
"provider": "anthropic"
}
},
"providers": {
"anthropic": {
"apiKey": "sk-ant-..."
}
}
}Optional reasoningEffort can be set to control extended thinking behavior.
GitHub Copilot is an OAuth provider and does not require an API key:
{
"agents": {
"defaults": {
"model": "github_copilot/gpt-4o",
"provider": "github_copilot"
}
},
"providers": {
"github_copilot": {}
}
}Cursor requires an explicit apiBase:
{
"agents": {
"defaults": {
"model": "cursor/gpt-4o",
"provider": "cursor"
}
},
"providers": {
"cursor": {
"apiKey": "your-key",
"apiBase": "https://your-cursor-api-base"
}
}
}Control how many inbound messages are processed concurrently:
{
"agents": {
"defaults": {
"maxConcurrentRequests": 3
}
}
}Messages for the same session are always serialized regardless of this setting.
Configure outbound delivery behavior:
{
"channels": {
"sendProgress": true,
"sendToolHints": false,
"sendMaxRetries": 3
}
}sendMaxRetries: number of delivery attempts with exponential backoff (1s, 2s, 4s...) before giving up.
The supported production channel set in this repository is:
emailslacktelegramfeishudingtalkdiscordmatrixwhatsappqqwecomweixinmochat
The runtime is designed so additional providers and transports can be added behind the same trait boundaries without changing the agent loop.