A minimal AI agent framework with tool-calling, multi-step workflows, scaffold generation, and configurable prompts. Works with any Anthropic-compatible API (Anthropic Claude, ZhiPu glm, MiniMax, etc.).
User Task → Agent constructs prompt (tools + history) → LLM decides action
↑ │
│ ┌──────────┴──────────┐
│ │ │
│ Tool Call Direct Answer
│ │ │
│ Execute Tool │
│ │ │
└──── Append result ─────────┘ │
▼
Return Result
pip install -e .
cp .env.example .env # edit with your API key
python main.pySet LLM_PROVIDER environment variable to select backend:
| Provider | Model | Notes |
|---|---|---|
glm (default) |
glm-5.1 | ZhiPu API |
minimax |
MiniMax-M2.7 | MiniMax API |
Provider API keys and endpoints are stored in config/llm_config.json. You can also override individually:
export LLM_PROVIDER=minimax
export ANTHROPIC_AUTH_TOKEN=your_api_key
export ANTHROPIC_BASE_URL=https://api.minimaxi.com/anthropic| Variable | Description | Default |
|---|---|---|
ANTHROPIC_DEFAULT_SONNET_MODEL |
Model name | claude-sonnet-4-20250514 |
AGENT_MAX_STEPS |
Max tool-call iterations | 5 |
AGENT_LOG_LEVEL |
Logging level | INFO |
AGENT_MAX_CONTEXT_TOKENS |
Context window size | 100000 |
AGENT_COMPACT_THRESHOLD |
When to compact (0-1) | 0.8 |
AGENT_KEEP_RECENT_MESSAGES |
Messages to keep before compacting | 4 |
from dotenv import load_dotenv
from simple_agent import SimpleAgent
from simple_agent.tools import SearchTool, CalculatorTool
load_dotenv()
agent = SimpleAgent()
agent.register_tool(SearchTool())
agent.register_tool(CalculatorTool())
result = agent.run("What is 2^10 + 3*7?")
print(result)Create a .md file describing what you want to build:
# student_mgmt.md
Create a student registration management GUI app (tkinter + SQLite).
Requires: db.py (database layer with students/courses/grades tables CRUD),
app.py (GUI layer with 4 tabs: Student Management / Course Management /
Grade Entry / Grade Query).
Database schema:
- Students table: id, name, gender, birthday, class, phone
- Courses table: id, name, credits, teacher
- Grades table: id, student_id, course_id, score, semesterpython build_with_workflow.py student_mgmt.mdOutput goes to demo/student_mgmt/. The workflow runs 4 phases:
- Plan — LLM analyzes requirements and generates a task plan
- Decompose — Breaks plan into atomic tasks (e.g., "Create db.py", "Add CRUD methods")
- Define Contracts — Generates interface specs between modules so all tasks use consistent APIs
- Execute — Runs each task sequentially, injecting the contract for consistency
Some tasks may fail (timeout, complex UI). Retry only the failures:
python build_with_workflow.py student_mgmt.md --retryThe retry reads existing files first, then re-executes only failed tasks with full code context.
cd demo/student_mgmt && python main.pyfrom simple_agent import SimpleAgent, DevWorkflow
from simple_agent.tools import WriteTool, ReadTool, EditTool, GrepTool, BashTool
agent = SimpleAgent(max_failures=3)
agent.register_tool(WriteTool(working_dir="my_project"))
agent.register_tool(ReadTool(working_dir="my_project"))
agent.register_tool(EditTool(working_dir="my_project"))
agent.register_tool(GrepTool(working_dir="my_project"))
agent.register_tool(BashTool(working_dir="my_project"))
wf = DevWorkflow(agent, report_dir="my_project/.reports")
requirement = "Build a REST API with Flask and SQLite..."
wf.plan_task(requirement)
wf.decompose(requirement)
wf.define_contracts(requirement)
wf.execute(max_steps_per_task=8)
# Or use the convenience method
wf.run_all(requirement)Generate projects from structured specs with role-based constraints:
from simple_agent import ScaffoldConfig, run_scaffold
config = ScaffoldConfig(
project_name="my_project",
spec={
"roles": ["frontend", "backend"],
"framework": "pyqt6",
"data_model": ["User(id, name, email)", "Order(id, user_id, total)"],
},
)
result = run_scaffold(config)
print(result.files_created)All prompts and messages have English defaults with full customization:
from simple_agent import SimpleAgent, Prompts, Messages
from simple_agent.prompts import chinese_prompts
from simple_agent.messages import chinese_messages
# English defaults (default)
agent = SimpleAgent()
# Chinese backward compatibility
agent = SimpleAgent(prompts=chinese_prompts(), messages=chinese_messages())
# Custom prompts
prompts = Prompts(
default_system_prompt="You are a Python expert...",
)
agent = SimpleAgent(prompts=prompts)from simple_agent.tools.base import BaseTool
class TranslateTool(BaseTool):
name = "translate"
@property
def _default_description(self) -> str:
return "Translate text between languages."
@property
def parameters(self):
return {
"type": "object",
"properties": {
"text": {"type": "string", "description": "Text to translate"},
"target_lang": {"type": "string", "description": "Target language"},
},
"required": ["text", "target_lang"],
}
def execute(self, **kwargs) -> str:
return translated_text
agent.register_tool(TranslateTool())Control which phases run:
from simple_agent.dev_workflow import WorkflowConfig
# Skip contract generation for simple tasks
config = WorkflowConfig(enable_contracts=False, max_steps_per_task=12)
wf = DevWorkflow(agent, workflow_config=config)| Tool | Name | Description |
|---|---|---|
WriteTool |
file_write |
Create or overwrite files |
ReadTool |
file_read |
Read file contents with line range |
EditTool |
file_edit |
Replace unique strings in files |
GrepTool |
file_grep |
Search file contents with regex |
BashTool |
bash |
Execute shell commands |
CalculatorTool |
calculate |
Evaluate math expressions |
SearchTool |
search |
Search for information (placeholder) |
MemoryTool |
memory |
Save/recall cross-session info |
Build reusable subagent skills with the skill registry:
from simple_agent import Skill, SkillRegistry, UseSkillTool
# Define a skill
skill = Skill(
name="code_review",
description="Review code for bugs and style issues",
system_prompt="You are a code reviewer...",
)
registry = SkillRegistry()
registry.register(skill)
agent.register_tool(UseSkillTool(registry))src/simple_agent/
├── __init__.py # Public API exports
├── agent.py # SimpleAgent: decision loop with failure tracking & pause/resume
├── config.py # AgentConfig dataclass from environment + LLM provider presets
├── llm_client.py # Anthropic SDK wrapper
├── dev_workflow.py # DevWorkflow, WorkflowConfig: plan → decompose → contracts → execute
├── prompts.py # Prompts dataclass + chinese_prompts()
├── messages.py # Messages dataclass + chinese_messages()
├── compactor.py # Context window compaction via LLM summarization
├── task_report.py # TaskReport: markdown execution log & checklist
├── scaffold.py # Scaffold framework for spec-driven project generation
├── exceptions.py # AgentError, LLMError, ToolError
├── skills/
│ ├── __init__.py # Skill, SkillRegistry, UseSkillTool, load_skill
│ ├── loader.py # Skill loading from files
│ ├── registry.py # SkillRegistry implementation
│ └── tool.py # UseSkillTool implementation
└── tools/
├── base.py # BaseTool ABC
├── registry.py # ToolRegistry
├── bash.py # BashTool with command denylist
├── file_read.py # ReadTool with path sandboxing
├── file_write.py # WriteTool with auto-mkdir
├── file_edit.py # EditTool with unique match enforcement
├── file_grep.py # GrepTool with regex + glob
├── calculator.py # CalculatorTool
├── search.py # SearchTool (placeholder)
└── memory.py # MemoryTool with .agent/memory.md persistence
python -m pytest tests/unit/ -v # Unit tests (mocked LLM)
python -m pytest tests/integration/ -v # Integration tests (real API)- Python >= 3.11
- anthropic >= 0.94.0
- python-dotenv >= 1.0.0