This document provides guidelines for AI coding agents working in this codebase.
mini-openclaw is a Python-based chatbot agent that integrates with Telegram and Feishu (飞书) messaging platforms. It uses OpenAI-compatible APIs for LLM functionality and provides tools for command execution, file operations, web search, and memory management.
This project uses uv for dependency management.
# Install dependencies
uv sync
# Add a new dependency
uv add <package-name>
# Run the application
uv run python main.pyThe project uses Ruff for linting and formatting.
# Run linting
uv run ruff check .
# Run linting with auto-fix
uv run ruff check . --fix
# Format code
uv run ruff format .
# Check formatting without changes
uv run ruff format . --checkNo test framework is currently configured. When adding tests, use pytest:
# Run all tests
uv run pytest
# Run a single test file
uv run pytest tests/test_example.py
# Run a single test function
uv run pytest tests/test_example.py::test_function_name -vOrganize imports in the following order, separated by blank lines:
- Standard library imports
- Third-party imports
- Local imports
import os
import json
from typing import Optional
from dotenv import load_dotenv
from openai import OpenAI
from agent.core import Agent
from adapters.base import BaseAdapter- Use 4 spaces for indentation (no tabs)
- Maximum line length: 88 characters (Ruff default)
- Use double quotes for strings
- Use f-strings for string formatting
- Use Python 3.11+ type hint syntax (e.g.,
list[dict],dict[str, str]) - Use
Optional[str]for optional return types - Use type hints for function parameters and return types
def load_session(platform: str, user_id: str) -> list[dict]:
...
def get_skill(name: str) -> Optional[Skill]:
...- Functions and variables:
snake_case - Classes:
PascalCase - Constants:
UPPER_SNAKE_CASE - Private methods: prefix with underscore
_private_method - Module-level "private" variables: prefix with underscore
_VARIABLE
MAX_RECENT_MESSAGES = 10
class TelegramAdapter(BaseAdapter):
platform_name = "telegram"
def _handle_message_event(self, data):
...
def compress_session(platform: str, user_id: str, client, model: str):
...- Use dataclasses for simple data containers
- Use ABC (Abstract Base Classes) for interfaces
- Define class attributes at the class level for constants
@dataclass
class Skill:
name: str
description: str
path: str
content: Optional[str] = None
class BaseAdapter(ABC):
platform_name: str
@abstractmethod
def start(self):
pass- Use specific exception types when possible
- Log errors before returning error messages
- Return user-friendly error strings for tool functions
try:
result = subprocess.run(command, shell=True, capture_output=True, text=True, timeout=30)
return result.stdout or result.stderr or "(命令执行完成,无输出)"
except Exception as e:
return f"命令执行失败: {str(e)}"- Use the
loggingmodule, notprint()for production code - Get logger with
logger = logging.getLogger(__name__)
import logging
logger = logging.getLogger(__name__)
def run(self, platform: str, user_id: str, user_message: str) -> str:
logger.info(f"[Agent] start run - platform={platform}, user_id={user_id}")- Write comments in Chinese (中文注释) to match the existing codebase
- Use docstrings for public functions and classes
def _handle_message_event(self, data):
"""处理收到的消息事件"""
# 消息去重:检查是否已处理过该消息
...- Each adapter should inherit from
BaseAdapterinadapters/base.py - Each job should inherit from
Jobinjobs/base.py - Tools are defined in
agent/tools.pywithTOOL_FUNCTIONSandTOOLS_SCHEMA - Skills are stored in
skills/<name>/SKILL.mdwith YAML frontmatter
- Use
python-dotenvfor loading.envfiles - Define all required env vars in
.env.example - Access via
os.getenv("VAR_NAME")with optional default
from dotenv import load_dotenv
load_dotenv()
api_key = os.getenv("OPENAI_API_KEY")
bot_token = os.getenv("TELEGRAM_BOT_TOKEN")- Use
async/awaitfor adapter methods that need to be async - For calling async from sync context, use
asyncio.run()
import asyncio
async def send_message(self, chat_id: str, text: str):
...
def _run_news_job(self):
asyncio.run(self.adapter.send_to_owner(message))BaseAdapter: Abstract base class defining the adapter interfaceTelegramAdapter: Telegram bot integration using python-telegram-botFeishuAdapter: Feishu/Lark integration using lark-oapi WebSocket client
Agent: Core LLM interaction class with tool calling supportTOOLS_SCHEMA: OpenAI function definitionsTOOL_FUNCTIONS: Mapping of tool names to Python functions
- Scheduled tasks that run periodically (news, weekly reports)
- Each job inherits from
Jobbase class
- Extensible skill system stored in
skills/directory - Each skill has a
SKILL.mdfile with YAML frontmatter - Skills are dynamically loaded and injected into the system prompt
- Session data stored in
~/.mini-openclaw/sessions/ - Memory stored in
~/.mini-openclaw/memory/ - Uses JSONL format for session files