#artificial-intelligence #chat-bot #ai-agent #llm

bin+lib nanobot

Rust port of nanobot, a lightweight personal AI assistant with tools and multi-channel gateway support

20 releases

Uses new Rust 2024

0.2.18 Feb 13, 2026
0.2.17 Feb 13, 2026
0.1.0 Feb 9, 2026

#1386 in Command line utilities

MIT license

505KB
14K SLoC

nanobot-rs

中文文档: README.md

Ultra-Lightweight Personal AI Assistant, Rust Edition

nanobot-rs is the Rust version of HKUDS/nanobot, keeping the same ultra-lightweight agent philosophy and tool-driven workflow.

  • Rust rewrite for stronger concurrency stability and cleaner deployment ergonomics
  • Already integrated by open-vibe/open-vibe as its Rust implementation of nanobot
  • Evolving as one of the core runtimes for open-vibe
  • Inspired by OpenClaw

Open Vibe Integration

  • Current Open Vibe integration focus: DingTalk stream bridge + relay workflow into Open Vibe threads

Features

  • Agent loop: LLM calls, tool execution, session context, and error handling
  • Config system: ~/.nanobot/config.json with provider auto-matching
  • Session and memory: JSONL session persistence + two-layer memory (memory/MEMORY.md + memory/HISTORY.md)
  • Media-aware prompting: inbound image attachments are converted to OpenAI-compatible image_url content parts
  • Tooling:
    • read_file / write_file / edit_file / list_dir
    • exec
    • web_search / web_fetch / http_request
    • message / spawn / cron / sessions_list / sessions_history / sessions_send
    • spawn subagents include current-time context, edit_file capability, and skills/ path guidance
  • Scheduling and heartbeat:
    • CronService (add/list/remove/enable/run + persistence)
    • HeartbeatService
  • Multi-channel support:
    • Telegram (long polling, media download, voice transcription)
    • Discord (Gateway + REST, with typing indicator)
    • WhatsApp (Node bridge)
    • Feishu (REST send; optional WebSocket receive feature)
    • Mochat (Claw IM via HTTP watch/polling)
    • DingTalk (optional Stream receive feature)
    • Email (IMAP inbound + SMTP outbound, explicit consent required)
    • Slack (Socket Mode)
    • QQ (optional feature qq-botrs)
  • Built-in skills synced from the original project (skills/*)
  • Ops and maintenance:
    • health / doctor --fix / update
    • pairing list|approve|reject (DM-style allowlist pairing workflow)
    • sessions list|show|delete
    • WebUI (webui) with terminal-cli style control dashboard

Requirements

  • Rust stable (recommended 1.85+)
  • Optional:
    • Node.js 18+ (for WhatsApp bridge login)
    • Brave Search API key (web_search, optional; falls back to keyless DuckDuckGo search when missing)
    • Groq API key (audio transcription)

Quick Start

1. Initialize

cargo run -- onboard

This initializes workspace basics including memory/MEMORY.md, memory/HISTORY.md, and skills/ for custom local skills.

2. Configure API key

Edit ~/.nanobot/config.json:

{
  "providers": {
    "openai": {
      "apiKey": "sk-xxx"
    },
    "openrouter": {
      "apiKey": "sk-or-xxx",
      "extraHeaders": {
        "HTTP-Referer": "https://example.com",
        "X-Title": "nanobot-rs"
      }
    }
  },
  "agents": {
    "defaults": {
      "model": "gpt-4o-mini"
    }
  }
}

For MiniMax, add a providers.minimax section and use a model containing minimax (for example minimax/MiniMax-M2.1):

{
  "providers": {
    "minimax": {
      "apiKey": "minimax-xxx"
    }
  },
  "agents": {
    "defaults": {
      "model": "minimax/MiniMax-M2.1"
    }
  }
}

If your key is from MiniMax Mainland China (minimaxi.com), set:

{
  "providers": {
    "minimax": {
      "apiBase": "https://api.minimaxi.com/v1"
    }
  }
}

nanobot-rs now follows the Python nanobot LiteLLM-style routing. You can set the model directly (no litellm/ prefix required), for example:

{
  "agents": {
    "defaults": {
      "model": "anthropic/claude-3-7-sonnet"
    }
  }
}

web_search prefers Brave when a key is configured, and automatically falls back to keyless DuckDuckGo when no BRAVE_API_KEY is available.
web_fetch remains keyless and can fetch/extract content from a concrete URL directly. http_request can call APIs directly (GET/POST/PUT/PATCH/DELETE, headers, query, json/body), including localhost ports and LAN services.

To switch web_search provider (Perplexity / Grok), configure tools.web.search:

{
  "tools": {
    "web": {
      "search": {
        "provider": "perplexity",
        "maxResults": 5,
        "perplexity": {
          "apiKey": "pplx-xxx",
          "baseUrl": "https://api.perplexity.ai",
          "model": "perplexity/sonar-pro"
        }
      }
    }
  }
}

Grok example:

{
  "tools": {
    "web": {
      "search": {
        "provider": "grok",
        "grok": {
          "apiKey": "xai-xxx",
          "model": "grok-4-1-fast",
          "inlineCitations": true
        }
      }
    }
  }
}

If you use DingTalk, add this under channels:

{
  "channels": {
    "dingtalk": {
      "enabled": true,
      "clientId": "dingxxx",
      "clientSecret": "secretxxx",
      "allowFrom": []
    }
  }
}

If you use the Email channel (IMAP + SMTP):

{
  "channels": {
    "email": {
      "enabled": true,
      "consentGranted": true,
      "imapHost": "imap.gmail.com",
      "imapPort": 993,
      "imapUsername": "you@gmail.com",
      "imapPassword": "app-password",
      "smtpHost": "smtp.gmail.com",
      "smtpPort": 587,
      "smtpUsername": "you@gmail.com",
      "smtpPassword": "app-password",
      "smtpUseTls": true,
      "fromAddress": "you@gmail.com",
      "allowFrom": ["trusted@example.com"]
    }
  }
}

If you use the Slack channel (Socket Mode):

{
  "channels": {
    "slack": {
      "enabled": true,
      "mode": "socket",
      "botToken": "xoxb-...",
      "appToken": "xapp-...",
      "groupPolicy": "mention",
      "groupAllowFrom": [],
      "dm": {
        "enabled": true,
        "policy": "open",
        "allowFrom": []
      }
    }
  }
}

If you use the QQ channel (currently direct/private chat only):

{
  "channels": {
    "qq": {
      "enabled": true,
      "appId": "your-app-id",
      "secret": "your-secret",
      "allowFrom": []
    }
  }
}

If you use the Mochat channel (Claw IM):

{
  "channels": {
    "mochat": {
      "enabled": true,
      "baseUrl": "https://mochat.io",
      "clawToken": "claw_xxx",
      "agentUserId": "6982abcdef",
      "sessions": ["*"],
      "panels": ["*"],
      "allowFrom": [],
      "replyDelayMode": "non-mention",
      "replyDelayMs": 120000
    }
  }
}

3. Chat directly

cargo run -- agent -m "Hello"

4. Start gateway

cargo run -- gateway

5. Start WebUI (terminal-cli style)

cargo run -- webui --host 127.0.0.1 --port 18890

Then open http://127.0.0.1:18890.

Windows Service (NSSM)

nanobot-rs can run as a Windows background service via nssm, with built-in commands:

  • service install
  • service remove
  • service start
  • service stop
  • service restart
  • service status

Build release first (with the features you need):

cargo build --release --all-features

Install service (default service name: NanobotService, default args: gateway):

.\target\release\nanobot.exe service install

Optional service name override:

.\target\release\nanobot.exe service install --name NanobotService2

When --name is provided, the value is persisted to service.name in ~/.nanobot/config.json, so later start/stop/status can omit --name.

Service Account Modes

  1. Use LocalSystem:
.\target\release\nanobot.exe service install --system
  1. Use current user (recommended, easier access to your user-scoped ~/.nanobot/config.json):
.\target\release\nanobot.exe service install --use-current-user --password "YourWindowsPassword"

Or use environment variable to avoid plaintext password in command history:

$env:NANOBOT_SERVICE_PASSWORD="YourWindowsPassword"
.\target\release\nanobot.exe service install --use-current-user
Remove-Item Env:NANOBOT_SERVICE_PASSWORD

Common Service Commands

.\target\release\nanobot.exe service status
.\target\release\nanobot.exe service start
.\target\release\nanobot.exe service stop
.\target\release\nanobot.exe service restart
.\target\release\nanobot.exe service remove

Notes

  • Use an elevated (Administrator) PowerShell for service install/start/stop/remove.
  • For --use-current-user, password must be the Windows account password (not PIN).
  • Error 1069 usually means invalid service credentials or missing "Log on as a service" permission.
  • If you see "marked for deletion", close services.msc / Event Viewer, wait a few seconds, and retry. Reboot if needed.

Common Commands

# Status and version
cargo run -- status
cargo run -- version
cargo run -- health
cargo run -- doctor
cargo run -- doctor --fix
cargo run -- update

# Interactive mode
cargo run -- agent

# WebUI
cargo run -- webui

# Channels
cargo run -- channels status
cargo run -- channels login

# Pairing (approve unknown sender)
cargo run -- pairing list
cargo run -- pairing approve telegram <CODE>
cargo run -- pairing reject telegram <CODE>

# Sessions
cargo run -- sessions list
cargo run -- sessions show telegram:123456 --limit 30
cargo run -- sessions delete telegram:123456

# Cron jobs
cargo run -- cron list
cargo run -- cron add -n daily -m "Good morning" --cron "0 9 * * *"
cargo run -- cron enable <job_id>
cargo run -- cron run <job_id>
cargo run -- cron remove <job_id>

Interactive exit commands: exit, quit, /exit, /quit, :q, or Ctrl+C/Ctrl+D.

Feishu WebSocket Receive

Default build supports Feishu sending. To enable Feishu WebSocket receive:

cargo run --features feishu-websocket -- gateway

DingTalk Stream Receive

Default builds do not include DingTalk Stream. Enable it with:

cargo run --features dingtalk-stream -- gateway

Mochat Channel (Claw IM)

Disabled by default. Once enabled, nanobot-rs uses HTTP watch/polling to receive and send messages.

  1. Optional: ask nanobot to set up Mochat automatically
  • In agent mode, send this prompt (replace the email with yours):
Read https://raw.githubusercontent.com/HKUDS/MoChat/refs/heads/main/skills/nanobot/skill.md and register on MoChat. My Email account is xxx@xxx Bind me as your owner and DM me on MoChat.
  • nanobot will try to register and write Mochat settings into ~/.nanobot/config.json.
  1. Manual setup (recommended to verify config)
  • Configure channels.mochat in ~/.nanobot/config.json:
  • clawToken: required, sent as X-Claw-Token for Mochat API requests
  • sessions / panels: explicit IDs or ["*"] for auto discovery
  • groups + mention.requireInGroups: group mention policy
{
  "channels": {
    "mochat": {
      "enabled": true,
      "baseUrl": "https://mochat.io",
      "socketUrl": "https://mochat.io",
      "socketPath": "/socket.io",
      "clawToken": "claw_xxx",
      "agentUserId": "6982abcdef",
      "sessions": ["*"],
      "panels": ["*"],
      "replyDelayMode": "non-mention",
      "replyDelayMs": 120000
    }
  }
}
  1. Start gateway:
cargo run -- gateway
  1. Validate messaging:
  • Direct sessions use session_xxx targets
  • Group/panel messaging uses panel/group targets

QQ Channel (Direct/Private Chat Only)

QQ support is disabled by default; enable it via the qq-botrs feature.

  1. Register and create a bot
  • Go to QQ Open Platform, register as a developer, and create a bot app
  • Copy AppID and AppSecret from Developer Settings
  1. Configure sandbox for testing
  • Open sandbox settings in the bot console
  • Add your QQ account as a test member
  • Scan the bot QR code with mobile QQ and start a direct chat
  1. Configure ~/.nanobot/config.json
  • Use the qq snippet above with appId and secret
  • Leave allowFrom empty for open access, or set allowed user openids from logs
  1. Start gateway
cargo run --features qq-botrs -- gateway

After startup, send a direct QQ message to the bot and it should reply.

Slack Channel

Uses Socket Mode, so no public callback URL is required.

  1. Create a Slack app
  • Go to Slack API -> Create New App -> From scratch
  • Select a workspace and create the app
  1. Configure app capabilities
  • Socket Mode: enable it and create an App-Level Token (connections:write, starts with xapp-...)
  • OAuth & Permissions: add bot scopes chat:write, reactions:write, app_mentions:read
  • Event Subscriptions: enable and subscribe to message.im, message.channels, app_mention
  • App Home: enable Messages Tab and allow messaging from that tab
  • Install App: install to workspace and copy Bot Token (xoxb-...)
  1. Configure ~/.nanobot/config.json
{
  "channels": {
    "slack": {
      "enabled": true,
      "mode": "socket",
      "botToken": "xoxb-...",
      "appToken": "xapp-...",
      "groupPolicy": "mention",
      "groupAllowFrom": [],
      "dm": {
        "enabled": true,
        "policy": "open",
        "allowFrom": []
      }
    }
  }
}
  1. Start gateway
cargo run -- gateway

You can DM the bot directly, or @mention it in a channel.

WhatsApp Login

channels login will automatically:

  • Prepare ~/.nanobot/bridge
  • Run npm install
  • Run npm run build
  • Start bridge and print QR login flow in terminal

Development

cargo fmt
cargo test
cargo check --features feishu-websocket
cargo check --features dingtalk-stream
cargo check --features qq-botrs

License

MIT

Dependencies

~130MB
~2.5M SLoC