ApeCode 🦧
A nano terminal code agent in Python — a minimal but complete implementation of a tool-calling AI agent (like Claude Code / Codex CLI / Kimi CLI), built for learning and experimentation.
Powered by ApeCode.ai
Features
- Tool-calling agent loop —
user → model → tool calls → tool results → model → response, with configurable max-steps guard - Multi-provider model adapters — OpenAI, Anthropic, and Kimi (OpenAI-compatible), all conforming to a unified
ChatModelprotocol - 7 built-in tools —
list_files,read_file,write_file,replace_in_file,grep_files,exec_command,update_plan - Sandbox + approval model —
SandboxMode(read-only / workspace-write / danger-full-access) restricts path mutations;ApprovalPolicy(on-request / always / never) controls interactive confirmation for mutating operations - Plugin system — declarative
apecode_plugin.jsonmanifests contribute tools, slash commands, and skills - MCP integration — load external tools from
.mcp.json/apecode_mcp.jsonvia thefastmcpSDK - Slash commands —
/help,/tools,/skills,/skill,/plan,/subagents,/delegate,/exit - Subagent delegation — isolated read-only agents with three default profiles:
general,reviewer,researcher - Skill templates — discoverable from
skills/*/SKILL.mddirectories or plugins - REPL + one-shot mode — interactive session with prompt-toolkit (history, tab-completion, multi-line via Alt+Enter) or single-prompt execution
- Thinking model support — displays
reasoning_contentfrom thinking models (e.g. Kimi K2.5) - AGENTS.md chain — walks from workspace root to filesystem root, loading
AGENTS.mdfiles for project-specific instructions
Installation
uv sync
Dependencies: openai, anthropic, fastmcp, typer, rich, prompt-toolkit.
Usage
API keys
export OPENAI_API_KEY=your_key # for provider=openai (default)
export ANTHROPIC_API_KEY=your_key # for provider=anthropic
export KIMI_API_KEY=your_key # for provider=kimi
Interactive REPL
uv run ape
One-shot mode
uv run ape "read README.md and summarize project structure"
CLI flags
uv run ape --provider openai --model gpt-4.1-mini # default
uv run ape --provider anthropic --model claude-sonnet-4-20250514
uv run ape --provider kimi --model kimi-k2.5
uv run ape --max-steps 30 --timeout 180
uv run ape --cwd /path/to/repo
uv run ape --sandbox-mode read-only --approval-policy never
uv run ape --plugin-dir ./plugins
uv run ape --mcp-config ./.mcp.json
uv run ape --skill-dir ./custom-skills
uv run ape --yolo "apply a simple refactor in src/"
uv run ape --version
Slash commands (inside REPL)
/help — list all commands
/tools — list registered tools
/skills — list discovered skills
/skill concise-review review src/apecode/cli.py — run a skill with extra request
/plan — show the current task plan
/subagents — list subagent profiles
/delegate reviewer:: review src/apecode/cli.py — delegate to a subagent
/exit — quit
Architecture
user input
│
▼
┌──────────────────────────────────────────────┐
│ cli.py — Typer app, _build_runtime, REPL │
│ ┌────────────────────────────────────────┐ │
│ │ NanoCodeAgent (agent.py) │ │
│ │ ┌──────────┐ ┌──────────────────┐ │ │
│ │ │ ChatModel │◄──│ openai_client.py │ │ │
│ │ │ protocol │ │ OpenAI/Anthropic/ │ │ │
│ │ │ │ │ Kimi adapters │ │ │
│ │ └──────────┘ └──────────────────┘ │ │
│ │ ┌──────────────────────────────────┐ │ │
│ │ │ ToolRegistry (tools.py) │ │ │
│ │ │ 7 built-in + plugin + MCP tools │ │ │
│ │ │ ToolContext: sandbox + approval │ │ │
│ │ └──────────────────────────────────┘ │ │
│ └────────────────────────────────────────┘ │
│ commands.py — slash command registry │
│ plugins.py — apecode_plugin.json loader │
│ mcp.py — fastmcp stdio bridge │
│ skills.py — SKILL.md discovery + catalog │
│ subagents.py — isolated read-only delegates │
│ system_prompt.py — prompt builder + AGENTS.md│
│ console.py — Rich + prompt-toolkit I/O │
└──────────────────────────────────────────────┘
Module breakdown
| Module | Purpose |
|---|---|
cli.py |
Typer entry point, assembles runtime (_build_runtime), runs REPL or one-shot |
agent.py |
NanoCodeAgent — the core tool-calling loop with ChatModel protocol |
tools.py |
ToolRegistry, ToolContext (sandbox/approval), 7 built-in tool handlers |
openai_client.py |
OpenAIChatCompletionsClient, AnthropicMessagesClient, KimiChatCompletionsClient — all adapters convert to/from internal OpenAI message format |
commands.py |
CommandRegistry + SlashCommand — /help, /tools, /exit, etc. |
plugins.py |
Loads apecode_plugin.json manifests; registers tools, commands, skills |
mcp.py |
Parses .mcp.json, connects via fastmcp.Client, registers MCP tools |
skills.py |
SkillCatalog — discovers SKILL.md files, supports plugin-contributed skills |
subagents.py |
SubagentRunner — spawns isolated agents with read-only tools and capped steps |
system_prompt.py |
Builds system prompt with environment info, AGENTS.md chain, skill catalog |
console.py |
Rich console output (panels, spinners, tool call display) + prompt-toolkit input session |
Environment Variables
| Variable | Default | Description |
|---|---|---|
APECODE_PROVIDER |
openai |
Model provider (openai / anthropic / kimi) |
APECODE_MODEL |
gpt-4.1-mini |
Model name |
APECODE_SANDBOX_MODE |
workspace-write |
Sandbox mode (read-only / workspace-write / danger-full-access) |
APECODE_APPROVAL_POLICY |
on-request |
Approval policy (on-request / always / never) |
OPENAI_API_KEY |
— | OpenAI API key |
OPENAI_BASE_URL |
https://api.openai.com/v1 |
Custom OpenAI-compatible endpoint |
ANTHROPIC_API_KEY |
— | Anthropic API key |
ANTHROPIC_BASE_URL |
https://api.anthropic.com/v1 |
Custom Anthropic endpoint |
ANTHROPIC_API_VERSION |
2023-06-01 |
Anthropic API version header |
KIMI_API_KEY |
— | Kimi API key |
KIMI_BASE_URL |
https://api.moonshot.cn/v1 |
Kimi endpoint |
Plugin System
Place a plugin manifest as apecode_plugin.json in a plugin directory:
{
"name": "EchoPlugin",
"tools": [
{
"name": "echo_text",
"description": "Echo text from JSON args",
"parameters": {
"type": "object",
"properties": { "text": { "type": "string" } },
"required": ["text"],
"additionalProperties": false
},
"argv": ["python3", "/absolute/path/to/tool.py"],
"mutating": false,
"timeout_sec": 60
}
],
"commands": [
{
"name": "quick-review",
"description": "Run plugin prompt template",
"usage": "/quick-review <task>",
"output": "Running quick review...",
"agent_input_template": "Review this task:\\n{args}"
}
],
"skills": [
{
"name": "plugin-skill",
"description": "A plugin-provided skill",
"content": "# Plugin Skill\\n\\nKeep output concise."
}
]
}
- Tools use either
argv(recommended) orcommandto specify the executable. - Tool processes receive JSON arguments on
stdinand write results tostdout. - Commands support
{args}placeholder inagent_input_template. - Skills can use inline
contentor afilepath relative to the manifest.
MCP Config
Load MCP tools from .mcp.json or apecode_mcp.json in workspace root, or via --mcp-config:
{
"mcpServers": {
"demo": {
"command": "python3",
"args": ["/absolute/path/to/mcp_server.py"],
"timeout_sec": 30
}
}
}
Skills
Create a skill as skills/<name>/SKILL.md:
# concise-review
Review code and answer with concise bullet points.
Use inside REPL:
/skill concise-review review src/apecode/agent.py
Development
# Install dev dependencies
uv sync
# Run tests
uv run pytest
# Run a single test file
uv run pytest tests/test_tools.py -v
# Lint
uv run ruff check src/ tests/
# Lint with auto-fix
uv run ruff check --fix src/ tests/
# Format
uv run ruff format src/ tests/
Project Structure
src/apecode/
├── __init__.py # package version
├── __main__.py # python -m apecode entry
├── cli.py # Typer CLI app + runtime assembly
├── agent.py # NanoCodeAgent core loop
├── tools.py # tool registry + built-in tools
├── openai_client.py # model adapters (OpenAI/Anthropic/Kimi)
├── commands.py # slash command framework
├── plugins.py # plugin manifest loader
├── mcp.py # MCP stdio bridge
├── skills.py # skill discovery + catalog
├── subagents.py # subagent delegation
├── system_prompt.py # system prompt builder
└── console.py # Rich + prompt-toolkit I/O
tests/
├── test_agent.py
├── test_commands.py
├── test_mcp.py
├── test_model_adapters.py
├── test_plugins.py
├── test_skills.py
├── test_subagents.py
└── test_tools.py
License
Apache-2.0
Metadata
Release files for apecode 0.0.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| apecode-0.0.2.tar.gz | 90.2 kB | Without provenance | Details for apecode-0.0.2.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| apecode-0.0.2-py3-none-any.whl | Python 3 | none | any | Details for apecode-0.0.2-py3-none-any.whl |
Total release size: 128.1 kB
Release files / apecode-0.0.2.tar.gz
| Download URL | apecode-0.0.2.tar.gz |
|---|---|
| Size | 90.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d50380038d64310c4e47aeca74b2b891b555996063698ef57a0b923a8b60eef7
|
|
BLAKE2b-256 checksum How to use checksums |
713c07a541e11afbe60fd31df2e538761f8f45bd0094895f38edebfc5a62ffd7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.7.15
|
Release files / apecode-0.0.2-py3-none-any.whl
| Download URL | apecode-0.0.2-py3-none-any.whl |
|---|---|
| Size | 37.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
631daeecc7145925f93f49bf8627831c2187c11e0998719f353d304a015c7828
|
|
BLAKE2b-256 checksum How to use checksums |
911e6482faf87de2a62fd367e565b0d1129ef96c99d3ee5c41f1055215487910
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.7.15
|
Security for apecode 0.0.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.