Build autonomous AI agents with pluggable brains, tools, skills, and channels
Project description
x-agent-kit
Build autonomous AI agents with pluggable brains (LLM providers), tools, skills, and communication channels. Agents can run one-shot tasks or long-running daemons with cron scheduling and bidirectional messaging via Feishu/Lark.
Install
# Core only
pip install x-agent-kit
# With specific providers
pip install x-agent-kit[gemini]
pip install x-agent-kit[openai]
pip install x-agent-kit[feishu]
# Everything
pip install x-agent-kit[all]
Requires Python >= 3.11.
Quick Start
1. Create project structure
my-agent/
├── .agent/
│ ├── settings.json # Agent configuration
│ ├── skills/ # Markdown knowledge files
│ └── memory/ # Auto-created, SQLite storage
└── main.py
2. Configure the agent
Create .agent/settings.json:
{
"brain": {
"provider": "gemini",
"model": "gemini-2.5-flash"
},
"providers": {
"gemini": {
"type": "api",
"api_key_env": "GOOGLE_API_KEY",
"default_model": "gemini-2.5-flash"
}
},
"channels": {
"default": "cli"
},
"skills": {
"paths": [".agent/skills"]
},
"agent": {
"max_iterations": 50
},
"memory": {
"enabled": true,
"dir": ".agent/memory"
},
"locale": "zh_CN"
}
3. Write your agent
from x_agent_kit import Agent, tool
@tool("Search the web for information", label="🔍 Search")
def search(query: str) -> str:
"""
query: Keywords to search for
"""
return f"Results for: {query}"
@tool("Save a note to file", label="📝 Save Note")
def save_note(filename: str, content: str) -> str:
"""
filename: Name of the file to save
content: Text content to write
"""
with open(filename, "w") as f:
f.write(content)
return f"Saved to {filename}"
agent = Agent(config_dir=".agent")
agent.register_tools([search, save_note])
result = agent.run("Search for Python best practices and save a summary")
print(result)
Architecture
User / Cron / Feishu Message
│
▼
┌─────────┐
│ Agent │ ← orchestrator (think → tool_call → execute loop)
└────┬────┘
│
┌────┴─────────────────────┐
│ │ │
▼ ▼ ▼
Brain Tools Channel
(LLM) (functions) (output)
│ │ │
├─ Gemini ├─ @tool defs ├─ CLI
├─ OpenAI ├─ Built-ins └─ Feishu
└─ Claude │ (memory,
│ skills,
│ plans,
│ approval)
│
┌────┴────┐
│ │
Skills Memory
(.md) (SQLite)
Configuration Reference
Full .agent/settings.json example with all options:
{
"brain": {
"provider": "gemini",
"model": "gemini-2.5-flash"
},
"providers": {
"gemini": {
"type": "api",
"api_key_env": "GOOGLE_API_KEY",
"default_model": "gemini-2.5-flash"
},
"openai": {
"type": "api",
"api_key_env": "OPENAI_API_KEY",
"default_model": "gpt-4o"
},
"claude": {
"type": "cli"
}
},
"channels": {
"default": "cli",
"feishu": {
"app_id_env": "LARK_APP_ID",
"app_secret_env": "LARK_APP_SECRET",
"default_chat_id_env": "LARK_CHAT_ID"
}
},
"skills": {
"paths": [".agent/skills"]
},
"agent": {
"max_iterations": 50,
"approval_timeout": 3600
},
"memory": {
"enabled": true,
"dir": ".agent/memory"
},
"locale": "zh_CN",
"schedules": [
{"cron": "0 9 * * *", "task": "Run daily analysis"},
{"cron": "0 */6 * * *", "task": "Check for updates every 6 hours"}
]
}
Configuration Fields
| Field | Type | Default | Description |
|---|---|---|---|
brain.provider |
string | required | Provider name (must exist in providers) |
brain.model |
string | "" |
Model override (falls back to provider's default_model) |
providers.<name>.type |
string | required | "api" for SDK-based, "cli" for Claude CLI |
providers.<name>.api_key_env |
string | "" |
Environment variable containing the API key |
providers.<name>.default_model |
string | "" |
Default model for this provider |
channels.default |
string | "cli" |
Default output channel |
channels.feishu |
object | — | Feishu channel config (see Feishu section) |
skills.paths |
list | [".agent/skills"] |
Directories to search for skill files |
agent.max_iterations |
int | 50 |
Max think-execute cycles per run() call |
agent.approval_timeout |
int | 3600 |
Timeout (seconds) for approval requests |
memory.enabled |
bool | true |
Enable persistent memory |
memory.dir |
string | ".agent/memory" |
Directory for SQLite databases |
locale |
string | "zh_CN" |
UI language ("zh_CN" or "en") |
schedules |
list | [] |
Cron schedules for serve() mode |
Environment Variables
Set these based on your configured providers:
# Gemini
export GOOGLE_API_KEY="your-key"
# OpenAI
export OPENAI_API_KEY="your-key"
# Feishu/Lark
export LARK_APP_ID="your-app-id"
export LARK_APP_SECRET="your-app-secret"
export LARK_CHAT_ID="your-chat-id"
Brains (LLM Providers)
Gemini
{
"brain": { "provider": "gemini", "model": "gemini-2.5-flash" },
"providers": {
"gemini": { "type": "api", "api_key_env": "GOOGLE_API_KEY" }
}
}
Install: pip install x-agent-kit[gemini]
OpenAI
{
"brain": { "provider": "openai", "model": "gpt-4o" },
"providers": {
"openai": { "type": "api", "api_key_env": "OPENAI_API_KEY" }
}
}
Install: pip install x-agent-kit[openai]
Claude (Local CLI)
Uses the Claude CLI with stateful sessions — no API key needed, no history re-sending.
{
"brain": { "provider": "claude" },
"providers": {
"claude": { "type": "cli" }
}
}
Requires claude CLI installed and authenticated.
Tools
Creating Tools
Use the @tool decorator on any function. Parameter schemas are auto-generated from type annotations. Parameter descriptions are extracted from docstrings.
from x_agent_kit import tool
@tool("Calculate compound interest", label="💰 Calculate Interest")
def compound_interest(principal: float, rate: float, years: int) -> str:
"""
principal: Initial investment amount in dollars
rate: Annual interest rate (e.g., 0.05 for 5%)
years: Number of years to compound
"""
result = principal * (1 + rate) ** years
return f"${result:,.2f}"
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
description |
str | yes | Tool description sent to the LLM |
label |
str | no | Display label shown in streaming progress cards |
Type mapping:
| Python Type | JSON Schema Type |
|---|---|
str |
"string" |
int |
"integer" |
float |
"number" |
bool |
"boolean" |
dict |
"object" |
list |
"array" |
Parameters without defaults are marked as required. Parameters with defaults include the default value in the schema.
Registering Tools
agent = Agent(config_dir=".agent")
agent.register_tools([compound_interest, search, save_note])
Built-in Tools
When memory is enabled, the agent automatically registers these tools:
| Tool | Description |
|---|---|
save_memory |
Save key-value pairs to persistent SQLite storage |
recall_memories |
Recall recent memories from previous sessions |
search_memory |
Full-text search across all memories |
clear_memory |
Delete all stored memories |
load_skill |
Load a markdown skill file by name |
list_skills |
List all available skill names |
notify |
Send a message to the user via the configured channel |
request_approval |
Submit an action for human approval |
create_plan |
Create a structured multi-step execution plan |
submit_plan |
Send a plan for human approval via interactive card |
get_plan |
Retrieve plan status and step details |
execute_approved_steps |
Execute all approved steps in a plan |
update_step |
Modify a plan step after rejection/negotiation |
resubmit_step |
Resubmit a modified step for re-approval |
Skills
Skills are markdown files that provide domain knowledge to the agent on demand. The LLM decides when to load them.
Standalone Skill
Create .agent/skills/my-topic.md:
# My Topic
Expert knowledge about this topic.
## Key Rules
- Rule 1: Always do X
- Rule 2: Never do Y
## Reference Data
| Metric | Target |
|--------|--------|
| CPA | < $50 |
| ROAS | > 3.0 |
Directory Skill (with references)
For complex skills with multiple reference files:
.agent/skills/ad-optimization/
├── SKILL.md # Main skill content
└── references/
├── bidding-guide.md # Additional reference
└── audience-tips.md # Additional reference
All reference files are automatically concatenated when the skill is loaded.
How Skills Work
- Agent starts with
list_skillsandload_skilltools registered - LLM sees available skills and decides when domain knowledge is needed
- LLM calls
load_skill(name="my-topic")to inject the content - Duplicate loads within the same run are automatically skipped
Memory
SQLite-backed persistent memory with FTS5 full-text search. Memories persist across agent runs.
# The agent automatically uses memory tools:
# save_memory(key="analysis-2024-01", content="...")
# search_memory(query="campaign performance")
# recall_memories() # recent entries
# Memory summary is prepended to each task automatically
How It Works
- Stored in
{memory.dir}/memory.db(SQLite with FTS5) - Each entry has:
key,content,timestamp search_memoryuses full-text search with automatic fallback to LIKE queriesrecall_memoriesreturns a formatted summary of recent entries- Memory summary is automatically prepended to each
run()call
Plan System
The plan system enables structured, multi-step execution with human approval via interactive Feishu cards.
Lifecycle
draft → pending_approval → partial_approved → executing → completed
↓
cancelled
How It Works
- LLM analyzes data and calls
create_plan()with structured steps - Each step has:
action,tool_name,tool_args,priority,risk_level submit_plan()sends an interactive card to Feishu with per-step approve/reject buttons- Human reviews each step individually
- Approved steps are auto-executed immediately
- Rejected steps can be modified and resubmitted
Plan Types
Plan types are customizable via locale files. Default types:
| Type | Label (zh_CN) | Label (en) |
|---|---|---|
daily |
日常计划 | Daily Plan |
weekly |
周度策略 | Weekly Strategy |
monthly |
月度复盘 | Monthly Review |
Business agents can add custom types by extending locale files.
Channels
CLI Channel
Terminal output with formatted cards and interactive approval prompts.
{ "channels": { "default": "cli" } }
Feishu/Lark Channel
Full integration with Feishu including:
- Streaming cards — Real-time progress updates during agent execution
- Interactive approval cards — Per-step approve/reject buttons for plans
- @mention detection — In group chats, only responds when @mentioned
- Emoji reactions — Shows "OnIt" while processing, "DONE" when complete
- Markdown rendering — Long responses rendered as rich cards
- WebSocket — Real-time bidirectional messaging
{
"channels": {
"default": "feishu",
"feishu": {
"app_id_env": "LARK_APP_ID",
"app_secret_env": "LARK_APP_SECRET",
"default_chat_id_env": "LARK_CHAT_ID"
}
}
}
Install: pip install x-agent-kit[feishu]
Running Modes
One-shot Mode
Execute a single task and exit:
agent = Agent(config_dir=".agent")
result = agent.run("Analyze today's performance data")
print(result)
Serve Mode (Daemon)
Run as a long-lived process with cron scheduling and Feishu message handling:
agent = Agent(config_dir=".agent")
# Starts cron jobs from config + Feishu WebSocket listener
agent.serve()
# Keep alive
import time
try:
while True:
time.sleep(60)
except KeyboardInterrupt:
print("Stopped.")
Schedules are configured in settings.json:
{
"schedules": [
{"cron": "0 9 * * *", "task": "Run morning analysis and send report"},
{"cron": "0 */6 * * *", "task": "Check metrics and alert if anomalies found"}
]
}
In serve mode, incoming Feishu messages trigger agent.run() with conversation context, enabling multi-turn dialogue.
i18n (Internationalization)
The framework supports multiple languages. Default is Chinese (zh_CN), English (en) is also included.
Switch Language
In settings.json:
{ "locale": "en" }
Extend with Custom Translations
Business agents can add their own translations without modifying the framework:
from x_agent_kit.i18n import load_extra_locale
# Merge custom keys into current locale
load_extra_locale("path/to/my_translations.json")
Custom locale file example:
{
"plan.type.quarterly": "Quarterly Review",
"plan.type.campaign_launch": "Campaign Launch Plan"
}
Programmatic API
from x_agent_kit.i18n import t, set_locale, get_locale
set_locale("en")
print(t("agent.thinking")) # "🤔 Thinking..."
print(t("plan.pending_count",
pending=3, total=5)) # "3 pending / 5 total"
print(t("custom.key",
default="fallback")) # "fallback" if key missing
Custom Stop Conditions
By default, the agent loop runs until the brain signals done or max_iterations is reached. You can inject custom termination logic:
# Stop after memory is saved (useful for analysis-then-save workflows)
agent = Agent(
config_dir=".agent",
stop_condition=lambda tool_name, result: tool_name == "save_memory"
)
# Stop after any approval is submitted
agent = Agent(
config_dir=".agent",
stop_condition=lambda tool_name, result: tool_name == "request_approval"
)
The callback receives (tool_name: str, result: Any) after each tool execution and returns bool.
Complete Example
Here's a full example of a data analysis agent:
import json
from x_agent_kit import Agent, tool
# Define domain-specific tools
@tool("Query sales data for a date range", label="📊 Query Sales")
def query_sales(start_date: str, end_date: str) -> str:
"""
start_date: Start date in YYYY-MM-DD format
end_date: End date in YYYY-MM-DD format
"""
# Your data source here
return json.dumps({"total": 15000, "orders": 342})
@tool("Generate a report from data", label="📄 Generate Report")
def generate_report(title: str, data: str) -> str:
"""
title: Report title
data: JSON data to include in the report
"""
return f"Report '{title}' generated with {len(data)} chars of data"
# Create agent with custom stop condition
agent = Agent(
config_dir=".agent",
stop_condition=lambda name, _: name == "save_memory"
)
agent.register_tools([query_sales, generate_report])
# One-shot execution
result = agent.run("Analyze last week's sales and generate a summary report")
print(result)
Development
# Clone the repo
git clone https://github.com/your-org/x-agent-kit.git
cd x-agent-kit
# Install with dev dependencies
pip install -e ".[dev]"
# Run all tests
pytest
# Run a specific test file
pytest tests/test_agent.py -v
# Run a specific test
pytest tests/test_tools.py::TestToolLabel::test_tool_with_label -v
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file x_agent_kit-0.3.8.tar.gz.
File metadata
- Download URL: x_agent_kit-0.3.8.tar.gz
- Upload date:
- Size: 57.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
60828ba728a82dc1b0a1b09a14ee42e18a86c85ec38123d4420ced6b7cf695b8
|
|
| MD5 |
d6e1af9792e6c095ac835bf2d19938f4
|
|
| BLAKE2b-256 |
7ef49a97beff871a7ebbcfbc7eb0e1972c7bee5649fd2f2f6d4c318226be0a06
|
File details
Details for the file x_agent_kit-0.3.8-py3-none-any.whl.
File metadata
- Download URL: x_agent_kit-0.3.8-py3-none-any.whl
- Upload date:
- Size: 47.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6f2a42eaefc2d342eba67951c56ee5b7e1dbbc546ba963438f1a753b669e9cbd
|
|
| MD5 |
c3077fbbd193cbc34acd6daff682f6d1
|
|
| BLAKE2b-256 |
e54a4038b68712e782c52ce061de81c537e4efcb1713e0ddfd4255b8c09f4251
|