Content
# Py-Agent
Python terminal AI Agent CLI. Support ReAct tool loop, Plan-and-Execute DAG scheduling, Multi-Agent collaboration, built-in file/Shell/search/memory/MCP tools, provide Runtime API and SDK embedding capabilities.
## Features
- **ReAct Tool Loop** — thinking / tool calls / tool result / output event flow, support concurrent read and serial write sharding
- **Plan-and-Execute** — independent Planner generates DAG, sorts by dependency topology, and executes tasks in parallel without dependencies
- **Multi-Agent Collaboration** — Planner → Worker pool → Reviewer three roles, asyncio.Queue borrowing and returning mechanism, failure retry + Reviewer audit
- **Context Compression** — token usage exceeds window 80% automatic trigger summary compression, configurable retention ratio (aggressive/balanced/conservative)
- **Tool System** — 15 built-in tools + MCP dynamic registration, support whitelist/blacklist filtering, HITL approval + audit log
- **MCP Client/Server** — stdio + Streamable HTTP, can be used as MCP server to expose built-in tools
- **Skill System** — builtin/user/project three-layer coverage loading, LRU buffer + lazy loading injection, support enable/disable
- **Long-term Memory** — SQLite persistence, scope project isolation + global memory, automatic injection system prompt
- **Snapshot and Recovery** — Agent run before and after automatic creation file-level snapshot, support rollback
- **Runtime API** — thread/turn/event/background task, RESTful interface
- **Multi-modal Input** — local/remote image reference, automatic compression to data URL, degrade to text metadata when not supported
## Technical Architecture
### Prompt Splicing
System prompt is assembled by `PromptAssembler` in 4 layers:
```
You are Py-Agent... ← Basic Identity
+ Guidelines (6 behavior norms) ← Behavior Constraints
+ Custom instructions (custom_prompt_paths file content) ← User-defined Rules
+ Project memory (AGENT.md + long-term memory, total ≤8000 characters) ← Project Context
+ Skill index (available skill list) ← Skill Index
```
Three operation modes add role instructions on this basis:
| Mode | Additional Content |
|------|-------------------|
| ReAct (default) | No addition |
| Plan-and-Execute | `"You are executing one task inside a Plan-and-Execute DAG. Task id: xxx"` |
| Multi-Agent | Planner: `"Return only JSON with a steps array"` / Worker: `"Execute only the assigned step"` / Reviewer: `"Return JSON: {approved, summary, issues}"` |
### Three Operation Modes
```
User Input → QueryEngine
├─ ask() → ReAct Loop (single Agent, while turn < 20)
├─ plan() → Planner(LLM generates DAG) → asyncio.gather parallel execution
└─ team() → Planner → Worker pool (asyncio.Queue) → Reviewer → Retry
```
**ReAct Loop**: Each round `LLM thinking → tool calls → result injection → next round`, up to 20 rounds. Read tools concurrently (Semaphore 4), write tools serially. HITL approval intercepts dangerous operations.
**Plan-and-Execute**: Planner calls independent LLM (no tools, only output JSON), generates DAG. Tasks are sorted by dependency topology, tasks without dependencies are executed in parallel using `asyncio.gather`. Each task has an independent ReAct (`history=[]`), only passing context through dependency result text.
**Multi-Agent**: Planner decomposes tasks → Worker borrows from `asyncio.Queue` to execute → Reviewer audits results. If not approved, retry (up to 2 times), feedback injects into retry context. All roles share `SkillContextBuffer`, Worker clears history after each step to prevent context pollution.
### Configuration System
4-layer superimposed priority: `default value → ~/.py_agent/config.json → .py_agent/config.json → environment variables`
```python
@dataclass
class PyAgentConfig:
llm: LlmConfig # provider, model, api_key, base_url, max_tokens, temperature
render_mode: str # "inline" | "plain"
tools: ToolsConfig # enabled(whitelist), disabled(blacklist), timeout, max_concurrent_read
mcp: McpConfig # servers (inline definition), auto_start
memory: MemoryConfig # compression_threshold(0.8), token_budget_mode, long_term_db_path
policy: PolicyConfig # hitl_mode, command_blacklist, path_guard
prompt: PromptConfig # personality, agent_mode, custom_prompt_paths
features: FeatureConfig # mcp/skill/memory/audit_log/context_compression/code_index switches
```
### Tool System
15 built-in tools, classified by risk level:
| Tool | Risk Level | Read-only | Description |
|------|------------|-----------|-------------|
| read_file / list_dir / glob / grep | — | Yes | File system read |
| web_search / web_fetch | — | Yes | Network search |
| search_code | — | Yes | Local code index search |
| load_skill | — | Yes | Skill lazy loading |
| write_file | medium | No | File write, requires write permission |
| save_memory | medium | No | Long-term memory write |
| bash / execute_command | high | No | Shell command execution |
| revert_turn | high | No | Snapshot recovery |
MCP tools dynamically register in the format `mcp__<server>__<tool>`, and generate virtual resource/prompt tools.
Tool execution process: `executor.execute_all()` sharding → read-only concurrent + write serial → HITL approval intercept → PathGuard/CommandGuard verification → audit log recording.
## Environment Requirements
- Python 3.11+
- [uv](https://docs.astral.sh/uv/)
- Optional: `rg` (accelerate local search), Node.js 20+ (Chrome DevTools MCP)
## Quick Start
```bash
git clone https://github.com/itwanger/py-agent.git
cd py-agent
uv sync --extra dev
uv run py-agent --help
```
Interactive mode:
```bash
uv run py-agent
```
Single query:
```bash
uv run py-agent -p "Help me summarize this project"
```
## Configuration
Priority: `default value < ~/.py_agent/config.json < .py_agent/config.json < environment variables`
```dotenv
PY_AGENT_PROVIDER=deepseek
PY_AGENT_MODEL=deepseek-v4-flash
PY_AGENT_API_KEY=your_key_here
```
Supported provider-specific Key: `DEEPSEEK_API_KEY` / `GLM_API_KEY` / `STEP_API_KEY` / `KIMI_API_KEY`
Command-line override:
```bash
uv run py-agent --provider deepseek --model deepseek-v4-flash
```
Connect local model:
```bash
PY_AGENT_PROVIDER=openai-compatible \
PY_AGENT_BASE_URL=http://127.0.0.1:11434/v1 \
PY_AGENT_MODEL=qwen2.5-coder \
uv run py-agent -p "Explain this repository"
```
## Interactive Commands
```
/help /exit /clear /context
/memory /save /config /tools
/hitl /policy /audit /index
/search /plan /team /model
/skill /mcp /task /snapshot
/restore
```
## Built-in Tools
`read_file` `write_file` `list_dir` `glob` `grep` `bash` `web_search` `web_fetch` `save_memory` `load_skill` `search_code` `revert_turn`
Write operations and dangerous commands go through policy, HITL, and audit triple processing. Tools can be filtered through whitelist/blacklist configuration.
## Network Tools
`web_search` — DuckDuckGo HTML search, returns title, URL, and summary.
`web_fetch` — Fetch public pages, reject `file://`, loopback, private addresses, reduce SSRF risk.
Login or JS rendering pages recommend using Chrome DevTools MCP.
## MCP
Connect MCP server, remote tools dynamically register as `mcp__<server>__<tool>`:
```bash
uv run py-agent mcp init-chrome --scope project
```
Define server through configuration file (`~/.py_agent/config.json` or `.py_agent/config.json`):
```json
{
"mcp": {
"servers": [
{"name": "my-server", "type": "stdio", "command": "node", "args": ["server.js"]}
],
"auto_start": true
}
}
```
Py-Agent itself as MCP server:
```bash
uv run py-agent mcp serve --transport http --port 3000
```
## Runtime API
```bash
PY_AGENT_RUNTIME_API_KEY=dev-key uv run py-agent serve --http --port 8080
```
Provide `/v1/threads` `/v1/threads/<id>/turns` `/v1/threads/<id>/events` `/v1/tasks` endpoints.
## Image Input
```text
Analyze this screenshot @image:./screenshots/page.png
Look at this @image:https://example.com/diagram.png
```
Local images automatically compress to data URL. Models that do not support multi-modal degrade to text metadata.
## Snapshot
Each Agent run automatically creates pre-turn / post-turn snapshots, saved in `~/.py_agent/snapshots/`.
```
/snapshot # View snapshot list
/restore 1 # Restore to specified snapshot
/snapshot clean # Clean old snapshots
```
## SDK
```python
from py_agent.sdk import create_default_engine
engine = create_default_engine(cwd=".")
result = engine.ask_complete("Explain this project")
print(result.text)
```
## Development
```bash
uv sync --extra dev
uv run python -m ruff check .
uv run python -m pytest
uv build
```
## License
MIT. See [LICENSE](LICENSE).