Clawlet is a lightweight personal AI agent with hybrid semantic memory search — a single static binary with no runtime and no CGO.
Bundled SQLite + sqlite-vec. Drop it on any machine and memory search just works.
This project is inspired by OpenClaw and nanobot.
Download from GitHub Releases.
macOS (Apple Silicon):
curl -L https://github.com/mosaxiv/clawlet/releases/latest/download/clawlet_Darwin_arm64.tar.gz | tar xz
mv clawlet ~/.local/bin/# Initialize
clawlet onboard \
--openrouter-api-key "sk-or-..." \
--model "openrouter/anthropic/claude-sonnet-4.5"
# Check effective configuration
clawlet status
# Chat
clawlet agent -m "What is 2+2?"Config file: ~/.clawlet/config.json
clawlet currently supports these LLM providers:
- OpenAI (
openai/<model>, API key:env.OPENAI_API_KEY) - OpenAI Codex (OAuth) (
openai-codex/<model>, no API key; login:clawlet provider login openai-codex) - OpenRouter (
openrouter/<provider>/<model>, API key:env.OPENROUTER_API_KEY) - Anthropic (
anthropic/<model>, API key:env.ANTHROPIC_API_KEY) - Gemini (
gemini/<model>, API key:env.GEMINI_API_KEYorenv.GOOGLE_API_KEY) - Local (Ollama / vLLM / OpenAI-compatible local endpoint) (
ollama/<model>orlocal/<model>, default base URL:http://localhost:11434/v1, API key optional)
Minimal config (OpenRouter):
{
"env": { "OPENROUTER_API_KEY": "sk-or-..." },
"agents": { "defaults": { "model": "openrouter/anthropic/claude-sonnet-4-5" } }
}Agent generation defaults are configurable:
{
"agents": {
"defaults": {
"model": "openrouter/anthropic/claude-sonnet-4-5",
"maxTokens": 8192,
"temperature": 0.7
}
}
}Minimal config (Local via Ollama):
{
"agents": { "defaults": { "model": "ollama/qwen2.5:14b" } }
}Minimal config (Local via vLLM using the same ollama/ route):
{
"agents": { "defaults": { "model": "ollama/meta-llama/Llama-3.1-8B-Instruct" } },
"llm": { "baseURL": "http://localhost:8000/v1" }
}OpenAI Codex (OAuth):
# one-time login
clawlet provider login openai-codex
# headless environment (SSH / container)
clawlet provider login openai-codex --device-code{
"agents": { "defaults": { "model": "openai-codex/gpt-5.1-codex" } }
}To enable semantic memory search, add memorySearch to the agent defaults:
{
"env": {
"OPENAI_API_KEY": "sk-..."
},
"agents": {
"defaults": {
"memorySearch": {
"enabled": true,
"provider": "openai",
"model": "text-embedding-3-small"
}
}
}
}Local embedding (Ollama / OpenAI-compatible local endpoint):
{
"agents": {
"defaults": {
"memorySearch": {
"enabled": true,
"provider": "openai",
"model": "nomic-embed-text",
"remote": {
"baseURL": "http://localhost:11434/v1"
}
}
}
}
}When enabled:
- The agent gains
memory_searchandmemory_gettools for retrieving past context. - clawlet indexes
MEMORY.md,memory.md, andmemory/**/*.mdfor retrieval. - The index DB is created at
{workspace}/.memory/index.sqlite.
When disabled (default):
memorySearch.enableddefaults tofalse; the search tools are not exposed to the model.- Memory files (
memory/MEMORY.md,memory/YYYY-MM-DD.md) are still injected into context as usual. - Normal chat behavior is otherwise unchanged.
tools.restrictToWorkspacedefaults totrue(tools can only access files inside the workspace directory)gateway.listendefaults to127.0.0.1:18790gateway.allowPublicBinddefaults tofalse
| Item | Status | Details |
|---|---|---|
| Gateway not publicly exposed | ✅ | Default bind is localhost only. Public bind is rejected unless gateway.allowPublicBind=true is explicitly set. |
Filesystem scoped (no /) |
✅ | File tools block root path, path traversal, encoded traversal, symlink escapes, and sensitive state paths. |
| Exec tool dangerous-command guard | ✅ | exec blocks unsafe shell constructs (command chaining, unsafe expansions, redirection/tee, dangerous patterns), blocks sensitive paths, and passes only allowlisted environment variables to subprocesses. |
Inbound channel messages can include attachments. clawlet can:
- send images to vision-capable models,
- transcribe audio using the configured provider,
- and inline text-like file attachments into the user context.
Configure under tools.media (the values below are the current default values):
{
"tools": {
"media": {
"enabled": true,
"audioEnabled": true,
"imageEnabled": true,
"attachmentEnabled": true,
"maxAttachments": 4,
"maxFileBytes": 20971520,
"maxInlineImageBytes": 5242880,
"maxTextChars": 12000,
"downloadTimeoutSec": 20
}
}
}Chat app integrations are configured under channels (examples below).
Telegram
Uses Telegram Bot API long polling (getUpdates) so no public webhook endpoint is required.
- Create a bot with
@BotFatherand copy the bot token. - (Optional but recommended) Restrict access with
allowFrom.- Telegram numeric user ID works best.
- Username is also supported (without
@).
Example config (merge into ~/.clawlet/config.json):
{
"channels": {
"telegram": {
"enabled": true,
"token": "123456:ABCDEF...",
"allowFrom": ["123456789"]
}
}
}Then run:
clawlet gatewayUses WhatsApp Web Multi-Device. No Meta webhook/public endpoint is required.
- Enable channel and (recommended) set
allowFrom. - Run login once:
clawlet channels login --channel whatsapp- Scan the QR shown in terminal from WhatsApp
Linked devices.
- Start normal runtime with
clawlet gateway.
Example config (merge into ~/.clawlet/config.json):
{
"channels": {
"whatsapp": {
"enabled": true,
"allowFrom": ["15551234567"]
}
}
}Then run:
# one-time login (required before gateway)
clawlet channels login --channel whatsapp
# normal runtime
clawlet gatewayNotes:
- Send retries are applied for transient/rate-limit errors with exponential backoff.
- Session state is persisted by default at
~/.clawlet/whatsapp-auth/session.db. - You can override store path with
sessionStorePathif needed. clawlet gatewaydoes not perform QR login; if not linked, it exits with a login command hint.
Discord
-
Create the bot and copy the token Go to https://discord.com/developers/applications, create an application, then
Bot→Add Bot. Copy the bot token. -
Invite the bot to your server (OAuth2 URL Generator) In
OAuth2→URL Generator, chooseScopes: bot. ForBot Permissions, the minimal set isView Channels,Send Messages,Read Message History. Open the generated URL and add the bot to your server. -
Enable Message Content Intent (required for guild message text) In the Developer Portal bot settings, enable MESSAGE CONTENT INTENT. Without it, the bot won't receive message text in servers.
-
Get your User ID (for allowFrom) Enable Developer Mode in Discord settings, then right-click your profile and select
Copy User ID. -
Configure clawlet
channels.discord.allowFromis the list of user IDs allowed to talk to the agent (empty = allow everyone).
Example config (merge into ~/.clawlet/config.json):
{
"channels": {
"discord": {
"enabled": true,
"token": "YOUR_BOT_TOKEN",
"allowFrom": ["YOUR_USER_ID"]
}
}
}- Run
clawlet gatewaySlack
Uses Socket Mode (no public URL required). clawlet currently supports Socket Mode only.
- Create a Slack app
- Configure the app:
- Socket Mode: ON, generate an App-Level Token (
xapp-...) withconnections:write - OAuth scopes (bot):
chat:write,reactions:write,app_mentions:read,im:history,channels:history - Event Subscriptions: subscribe to
message.im,message.channels,app_mention
- Socket Mode: ON, generate an App-Level Token (
- Install the app to your workspace and copy the Bot Token (
xoxb-...) - Set
channels.slack.enabled=true, and configurebotToken+appToken.- groupPolicy: "mention" (default — respond only when @mentioned), "open" (respond to all channel messages), or "allowlist" (restrict to specific channels).
- DM policy defaults to open. Set "dm": {"enabled": false} to disable DMs.
Example config (merge into ~/.clawlet/config.json):
{
"channels": {
"slack": {
"enabled": true,
"botToken": "xoxb-...",
"appToken": "xapp-...",
"groupPolicy": "mention",
"allowFrom": ["U012345"]
}
}
}Then run:
clawlet gateway| Command | Description |
|---|---|
clawlet onboard |
Initialize a workspace and write a minimal config. |
clawlet status |
Print the effective configuration (after defaults and routing). |
clawlet agent |
Run the agent in CLI mode (interactive or single message). |
clawlet gateway |
Run the long-lived gateway (channels + cron + heartbeat). |
clawlet channels status |
Show which chat channels are enabled/configured. |
clawlet cron list |
List scheduled jobs. |
clawlet cron add |
Add a scheduled job. |
clawlet cron remove |
Remove a scheduled job. |
clawlet cron toggle |
Enable/disable a scheduled job. |
clawlet cron run |
Run a job immediately. |
--message is required, and exactly one of --every, --cron, or --at must be set.
# Every N seconds
clawlet cron add --message "summarize my inbox" --every 3600
# Cron expression (5-field)
clawlet cron add --message "daily standup notes" --cron "0 9 * * 1-5"
# Run once at a specific time (RFC3339)
clawlet cron add --message "remind me" --at "2026-02-10T09:00:00Z"
# Deliver to a chat (requires both --channel and --to)
clawlet cron add --message "ping" --every 600 --channel slack --to U012345Pre-built images are available on GitHub Container Registry:
# docker-compose.yml
services:
clawlet:
image: ghcr.io/mosaxiv/clawlet:latest
volumes:
- ~/.clawlet:/root/.clawlet
command: gateway
restart: unless-stoppeddocker compose up -d# Build the image
docker build -t clawlet .
# Initialize config (first time only)
docker run -v ~/.clawlet:/root/.clawlet --rm clawlet onboard
# Edit config on host to add API keys
vim ~/.clawlet/config.json
# Run the gateway
docker run -v ~/.clawlet:/root/.clawlet clawlet gateway
# Or run a single command
docker run -v ~/.clawlet:/root/.clawlet --rm clawlet agent -m "Hello"
docker run -v ~/.clawlet:/root/.clawlet --rm clawlet status