A minimal Python agent framework with Feishu support β inspired by openclaw.
catbot is a clean Python implementation of the openclaw agent architecture:
- Agent loop β think β tool call β observe β repeat (like openclaw's pi-agent-core)
- openclaw-style session keys β
agent:<id>:<channel>:<type>:<chat_id> - Compaction β summarize old messages when context window fills up (mirrors openclaw's
compaction.ts) - Memory β
MEMORY.md(long-term facts) +HISTORY.md(event log) - Feishu WebSocket β native lark-oapi integration, no public server needed
- Middleware chain β rate limiting, allowlists, logging (openclaw's send-policy)
- Multi-provider β OpenAI-compatible + Anthropic (with prompt caching)
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β CHANNELS β
β Feishu (WebSocket) CLI (custom) β
ββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββ
β IncomingMessage
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β GATEWAY β
β Session keys β’ Middleware chain β’ Send policy β
β Concurrency control β’ Channel routing β
ββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββ
β
ββββββββββββββββ΄βββββββββββββββ
βΌ βΌ
βββββββββββββββββββββ βββββββββββββββββββββββββββββ
β SESSION STORE β β MEMORY β
β β β β
β β’ JSONL append β β β’ SOUL.md (personality) β
β β’ openclaw keys β β β’ AGENTS.md (instructions)β
β β’ Compaction β β β’ MEMORY.md (long-term) β
β β’ Daily reset β β β’ HISTORY.md (log) β
βββββββββββββββββββββ βββββββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β AGENT β
β Build system prompt β LLM β Tool calls β Loop β
β Compaction trigger β’ on_tool_call callbacks β
ββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββ
β
ββββββββββββββββ΄βββββββββββββββ
βΌ βΌ
βββββββββββββββββ βββββββββββββββββββββββ
β PROVIDERS β β TOOLS β
β β β β
β β’ OpenAI β β β’ @tool decorator β
β β’ Anthropic β β β’ Auto JSON schema β
β (+ caching) β β β’ read/write/exec β
βββββββββββββββββ βββββββββββββββββββββββ
pip install catbot
export OPENAI_API_KEY=sk-...
python examples/hello_world.pyOr in 5 lines:
import asyncio, os
from catbot import Agent, Gateway, GatewayConfig
from catbot.channels.cli import CLIChannel
from catbot.providers.openai import OpenAIProvider
agent = Agent(provider=OpenAIProvider(api_key=os.environ["OPENAI_API_KEY"]))
gw = Gateway(agent=agent)
gw.add_channel(CLIChannel())
asyncio.run(gw.run())- Create an app at open.feishu.cn
- Enable Bot capability
- Subscribe to
im.message.receive_v1event - Set connection mode to WebSocket (ιΏθΏζ₯樑εΌ)
- Grant permissions:
im:message,im:message:send_as_bot
pip install "catbot[feishu]"
export FEISHU_APP_ID=cli_xxx
export FEISHU_APP_SECRET=xxx
export ANTHROPIC_API_KEY=sk-ant-xxx
python examples/feishu_bot.pyFeatures:
- π reaction when processing, β when done
- Group @ detection (
only_at_in_group=True) - Supports text, image, file messages
- No public server needed (WebSocket long connection)
from catbot import tool, ToolRegistry
@tool()
async def search_web(query: str, max_results: int = 5) -> str:
"""Search the web for information.
query: The search query.
max_results: Maximum number of results to return.
"""
# your implementation
return results
tools = ToolRegistry()
tools.register(search_web)
agent = Agent(provider=..., tools=tools)from catbot import Gateway, rate_limit, allow_senders, log_messages
gw = Gateway(agent=agent)
gw.use(log_messages()) # Log all messages
gw.use(rate_limit(max_per_minute=10)) # Rate limit
gw.use(allow_senders(["ou_abc123", "ou_xyz"])) # AllowlistSession keys follow openclaw's format:
| Format | Example | Use case |
|---|---|---|
agent:main:feishu:direct:<openId> |
DM with user | 1:1 chat |
agent:main:feishu:group:<chatId> |
Group chat | Multi-user |
agent:main:cli:direct:local |
CLI session | Testing |
agent:main:cron:cron:<jobId> |
Cron job | Scheduled tasks |
catbot uses the same workspace file convention as openclaw:
~/.catbot/workspace/
βββ SOUL.md # Agent personality (loaded into system prompt)
βββ AGENTS.md # Agent instructions
βββ USER.md # User context
βββ memory/
βββ MEMORY.md # Long-term facts (loaded every turn)
βββ HISTORY.md # Append-only event log (grep-searchable)
When the session token estimate exceeds 70% of the context window, catbot automatically compacts old messages:
- Summarize messages
[0 .. -keep_last]via LLM - Replace with a summary system message
- Keep the last
keep_lastmessages verbatim
This mirrors openclaw's compaction.ts behavior.
from catbot.providers.openai import OpenAIProvider
# OpenAI
p = OpenAIProvider(api_key="sk-...", model="gpt-4o")
# DeepSeek
p = OpenAIProvider(
api_key="sk-...",
api_base="https://api.deepseek.com/v1",
model="deepseek-chat",
)from catbot.providers.anthropic import AnthropicProvider
p = AnthropicProvider(
api_key="sk-ant-...",
model="claude-opus-4-5",
enable_cache=True, # Adds cache_control to system + last N user messages
)# Core (OpenAI)
pip install catbot
# With Anthropic
pip install "catbot[anthropic]"
# With Feishu
pip install "catbot[feishu]"
# Everything
pip install "catbot[all]"MIT