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
- 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
uv syncDependencies: openai, anthropic, fastmcp, typer, rich, prompt-toolkit.
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=kimiuv run apeuv run ape "read README.md and summarize project structure"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/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
user input
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββ
β cli.py β Typer app, _build_runtime, REPL β
β ββββββββββββββββββββββββββββββββββββββββββ β
β β NanoCodeAgent (agent.py) β β
β β ββββββββββββ ββββββββββββββββββββ β β
β β β ChatModel βββββ model_adapters.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 | 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 |
model_adapters.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 |
| 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 |
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.
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
}
}
}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
# 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/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
βββ model_adapters.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
Apache-2.0