Extension development
The first step in extending nanobot is not writing code. It is deciding which boundary should own the capability. A misplaced capability is often harder to maintain than an imperfect implementation.
Corresponding source
| Extension type | Source |
|---|---|
| Tool | nanobot/agent/tools/base.py, loader.py, registry.py |
| Skill | nanobot/agent/skills.py, nanobot/skills/, nanobot/agent/context.py |
| MCP | nanobot/agent/tools/mcp.py, nanobot/config/schema.py, nanobot/agent/loop.py |
| Provider | nanobot/providers/base.py, registry.py, factory.py |
| Channel | nanobot/channels/base.py, registry.py, manager.py |
| Command, API, SDK, and WebUI | nanobot/command/, api/, sdk/, webui/, webui/src/ |
Learning objectives
After this section, you should be able to:
- choose Tool, Skill, MCP, Provider, Channel, or a runtime surface from the requirement;
- locate discovery, registration, configuration, testing, and security contracts for each extension type;
- keep the modification scope small and prevent platform or UI details from entering the Agent core;
- design an implementation sequence that is verifiable before adding complexity.
Prerequisites
- Complete One Turn.
- Complete Engineering and Security.
- Understand the difference between a Tool Call and an ordinary natural-language instruction.
1. Choose the boundary first
| Requirement | Prefer | Reason |
|---|---|---|
| Teach the model how to combine existing capabilities | Skill | the main change is instructions and workflow |
| Give the model a new local Python action | Tool | requires structured arguments and deterministic execution |
| Reuse an existing external tool service | MCP | the protocol already exists; no core client needed |
| Integrate a new model API | Provider | normalize upstream responses into LLMResponse |
| Integrate a new chat platform | Channel | handle inbound/outbound messages and platform lifecycle |
| Add a user control command | Command | the model should not decide whether it runs |
| Expose capability to a Python application | SDK | typed, in-process calls |
| Expose a compatible interface to HTTP clients | API | out-of-process request/response protocol |
| Add browser interaction | WebUI | frontend state plus WebSocket/HTTP protocol |
2. Three commonly misplaced features
“Calls an external API” is not automatically a Provider
It is a Provider only when the API is an LLM inference backend that must produce LLMResponse. Weather, search, and database queries are more likely a Tool or MCP integration.
“A workflow” is not automatically a Tool
If existing Tools can already complete the task but the model does not know the right sequence, write a Skill first. A Skill adds no new execution permission.
“The browser needs a state” does not automatically require AgentRunner
The core should publish a general runtime event. WebSocket envelopes, replay sequences, component state, and styles belong in the coordinator, Channel, or WebUI.
3. Complexity ladder
flowchart LR A["Skill<br/>instructions only"] --> B["Tool<br/>local contract"] B --> C["MCP<br/>external process/service"] C --> D["Provider<br/>model protocol"] D --> E["Channel<br/>long connection and platform semantics"] E --> F["API / SDK / WebUI<br/>multi-consumer contract"]
This is not a value ranking. Test and failure surfaces commonly increase from left to right. Beginners should start with a Skill and a read-only Tool.
4. Recommended reading order
- Add a Tool
- Add a Skill
- Integrate MCP
- Add a Provider
- Add a Channel
- Command, API, SDK, and WebUI extension boundaries
5. Nine questions for every extension
- Who discovers or registers it?
- What is its stable name?
- Where is its input contract defined?
- How does output return to the Turn?
- Where is configuration loaded and validated?
- Who starts, cancels, and closes its lifecycle?
- Which side effects can it produce?
- How does the minimum test avoid real networks and credentials?
- Which documentation, UI, or indexes must change with it?
Each lesson uses these questions to bound the implementation.
Read-only source baseline
example/nanobot/code-ENremains a read-only fact baseline throughout the learning path. Hands-on changes belong only inlearning-EN/examples, a separate temporary workspace, or an explicitly copied isolated source tree.
Next: Add a Tool