OpenKIWI sits in the same automation space as other tools like Openclaw, but differentiates itself with a security-first design and a streamlined onboarding experience that gets you started in minutes.
How is OpenKIWI different?
- Everything runs in isolated Docker containers
- Agents can only access what you explicitly grant
- Switch between providers or run local models without rebuilding your workflow logic.
- OpenKIWI plays by the rules and aims to be enterprise-ready, with a clear and auditable security posture.
- Clone the repo, run one command and you're up in about 30 seconds. A few quick settings in the UI and you're running your first agent. The whole process takes about 3 minutes.
- No 20-minute YouTube tutorial required.
- Clone this repo
cdto the directory where you cloned the repo- You should see a
docker-compose.ymlfile in this directory
- You should see a
- Run
docker compose up --build
- Copy the gateway token from the logs:
- Go to
http://localhost:3000and click on Gateway
- Enter your token and click Connect
- If done correctly, you will see
GATEWAY CONNECTEDat the top of the page.
Connect WhatsApp so you can message your agents from your phone.
- Go to the Settings page and click the WhatsApp tab
- Scan the QR code with your phone (WhatsApp > Linked Devices > Link a Device)
- Once paired, the status will show as connected
Start messaging agents from your phone:
By default, any WhatsApp number that messages the linked account can interact with agents. Add an allowlist to restrict access:
WHATSAPP_ALLOW_LIST=447958673279, 1234567890
Accepts comma-separated phone numbers (digits only, no + prefix required). Numbers not on the list are silently ignored. LID-based JIDs (used by some WhatsApp versions) are automatically resolved to phone numbers for matching.
Agents can send scheduled heartbeat messages to WhatsApp. Add a channel to the agent's config.json:
{
"heartbeat": {
"enabled": true,
"schedule": "0 9 * * 1",
"channels": [
{ "type": "whatsapp", "jid": "447958673279@s.whatsapp.net" }
]
}
}The jid is the recipient's phone number followed by @s.whatsapp.net. WhatsApp must be connected for delivery to work β if disconnected, the channel is skipped and a warning is logged.
Connect a Telegram bot so you can message your agents from Telegram.
- Open Telegram and message @BotFather
- Send
/newbotand follow the prompts to name your bot - Copy the bot token BotFather gives you
Add to your .env file:
TELEGRAM_BOT_TOKEN=your_bot_token_here
By default, anyone who finds your bot can message it. Add an allowlist to restrict access to specific users:
TELEGRAM_ALLOW_LIST=123456789, @yourusername
Accepts comma-separated Telegram user IDs and/or @usernames. To find your user ID, message @userinfobot on Telegram.
- Send any message to your bot β it goes to the default agent
- Mention a specific agent by name:
@Oracle what happened this week? - Use
/agentsto list all available agents
Agents can send scheduled heartbeat messages to Telegram. Add a channel to the agent's config.json:
{
"heartbeat": {
"enabled": true,
"schedule": "0 16 * * 5",
"channels": [
{ "type": "telegram", "chatId": "123456789" }
]
}
}The chatId is the Telegram chat where messages will be delivered (usually your user ID).
OpenKIWI ships with several built-in tools that extend your agents' capabilities. Enable them in the Settings page:
| Tool | Description | Docs |
|---|---|---|
| Filesystem | Read/write workspace files | Built-in |
| Vision | Analyse images | Built-in |
| Web Browser | Browse and extract web content | Built-in |
| GitHub | Read/write files in GitHub repos | tools/github/ |
| Google Tasks | Manage Google Tasks lists and items | tools/google_tasks/ |
| Qdrant | Semantic search across vector stores | tools/qdrant/ |
See tools/README.md for the full list and how to create your own.
Heartbeats let agents run autonomously on a schedule β no user prompt required. Each heartbeat reads the agent's HEARTBEAT.md file, executes the instructions via the LLM (with full tool access), and delivers the response to configured channels.
- The Heartbeat Manager reads each agent's
config.jsonat startup - Agents with
heartbeat.enabled: trueare scheduled using their cron expression - When the cron fires, the agent's
HEARTBEAT.mdis loaded as the prompt - The agent runs a full agent loop (including tool calls) and produces a response
- The response is delivered to all configured channels
- A session is saved so the conversation history is preserved
In the agent's config.json:
{
"name": "Oracle (Analyst)",
"emoji": "π",
"provider": "qwen3-30b-a3b-thinking-2507-mlx",
"heartbeat": {
"enabled": true,
"schedule": "0 16 * * 5",
"channels": [
{ "type": "telegram", "chatId": "123456789" },
{ "type": "whatsapp", "jid": "123456789@s.whatsapp.net" },
{ "type": "websocket" }
]
}
}Uses standard cron syntax (5 fields: minute, hour, day-of-month, month, day-of-week):
| Example | Meaning |
|---|---|
0 9 * * * |
Every day at 09:00 |
0 16 * * 5 |
Every Friday at 16:00 |
0 23,1,3,5,7 * * * |
Every 2 hours overnight (23:00-07:00) |
15 8,17 * * * |
Twice daily at 08:15 and 17:15 |
0 9 * * 1 |
Every Monday at 09:00 |
| Channel | Config | Description |
|---|---|---|
| Telegram | { "type": "telegram", "chatId": "123456789" } |
Sends message to a Telegram chat. Requires TELEGRAM_BOT_TOKEN in .env. |
{ "type": "whatsapp", "jid": "123456789@s.whatsapp.net" } |
Sends message via WhatsApp. Requires WhatsApp integration to be connected. | |
| WebSocket | { "type": "websocket" } |
Broadcasts to all connected UI clients in real time. |
Multiple channels can be configured β the response is delivered to all of them. If one channel fails (e.g. Telegram disconnected), the others still receive the message.
The HEARTBEAT.md file in the agent's directory contains the instructions the agent will execute on each heartbeat. Write it as you would a user prompt:
# Weekly Summary
Review what happened this week and produce a summary.
## What to Do
1. Check Google Tasks for completed and overdue items
2. Review GitHub activity across the repos
3. Identify wins and misses
4. Suggest adjustments for next week
5. End with a 3-5 bullet executive summary
Always sign off with your name and emoji.The agent has full access to its configured tools during heartbeat execution, so it can call GitHub, Google Tasks, Qdrant, or any other enabled tool.
- Heartbeats won't overlap β if a previous execution is still running, the next trigger is skipped
- Thinking/reasoning tags (
<think>...</think>) are stripped from channel messages but preserved in saved sessions - Sessions are persisted per channel (e.g.
tg-123456789_analyst) so conversation history accumulates over time - The agent's state is set to "working" during execution and returns to "idle" when finished
OpenKIWI supports allowlists for both messaging platforms to control who can interact with your agents. Without an allowlist, anyone who can reach the bot/linked account can send messages.
Add to your .env file:
| Variable | Format | Example |
|---|---|---|
TELEGRAM_ALLOW_LIST |
Comma-separated user IDs and/or @usernames |
123456789, @johndoe |
WHATSAPP_ALLOW_LIST |
Comma-separated phone numbers (digits only) | 447958673279, 1234567890 |
| Telegram | ||
|---|---|---|
| Accepts | Numeric user IDs, @usernames |
Phone numbers (digits only) |
| If not set | All users allowed | All numbers allowed |
| Blocked messages | Silently ignored (logged) | Silently ignored (logged) |
| LID resolution | N/A | Automatic β LID JIDs are resolved to phone numbers for matching |
- Telegram user ID: Message @userinfobot on Telegram
- Telegram chat ID: Same as user ID for direct messages; for groups, use @getidsbot
- WhatsApp JID: Your phone number in international format without the
+prefix, followed by@s.whatsapp.net(e.g.447958673279@s.whatsapp.net)
- Start chatting with your agent
- Analyze images
- Write code
- Build websites
- Schedule ongoing tasks for your agents
- Import your ChatGPT history
- And much more











