Five entry points and their runtime boundaries
Corresponding source
| Entry point | Source |
|---|---|
| CLI and Gateway commands | nanobot/cli/commands.py::agent, _run_gateway |
| Gateway runtime | nanobot/gateway/runtime.py, nanobot/gateway/service.py |
| HTTP API | nanobot/api/server.py |
| Python facade and SDK | nanobot/nanobot.py::Nanobot, nanobot/sdk/ |
| Channel | nanobot/channels/base.py, nanobot/channels/manager.py, nanobot/channels/ |
| WebUI Turn coordination | nanobot/session/webui_turns.py |
Learning objectives
After this lesson, you should be able to:
- distinguish the CLI, Gateway, HTTP API, Python SDK, and WebUI;
- identify which paths use MessageBus and which call
process_direct()directly; - choose the right debugging entry point for a problem;
- explain why different entry points do not imply five separate Agent implementations.
Prerequisites
- Complete the first DeepSeek request.
- Understand the basic purposes of asynchronous functions and message queues.
Build the first mental model
nanobot’s entry points share a core runtime but assemble it differently and expose different output protocols:
flowchart TD CLI1["One-shot CLI message"] --> PD["AgentLoop.process_direct"] SDK["Python SDK"] --> PD API["HTTP API"] --> PD CLI2["Interactive CLI"] --> BUS["MessageBus"] CH["Chat Channel"] --> BUS WS["WebSocket Channel / WebUI"] --> BUS BUS --> LOOP["AgentLoop.run / _dispatch"] PD --> TURN["AgentLoop._process_message"] LOOP --> TURN TURN --> RUNNER["AgentRunner"]
The shared core consists of:
AgentLoop;AgentRunner;- Provider;
- ToolRegistry;
- ContextBuilder;
- SessionManager.
The main differences are:
- who creates those objects;
- whether messages pass through MessageBus;
- how the session key is generated;
- how streams are presented;
- who keeps the process alive.
1. One-shot CLI message
Command:
nanobot agent -m "Hello"Main path:
nanobot/cli/commands.py::agent
→ AgentLoop.from_config
→ AgentLoop.process_direct
→ AgentLoop._process_messageProperties:
- short path;
- no resident Gateway;
- useful for validating configuration, Provider, and the core Turn;
- presents stream/progress through callbacks;
- default session ID is
cli:direct.
If even the one-shot CLI fails, do not start with Channel or WebUI debugging.
2. Interactive CLI
Command:
nanobot agentInteractive mode creates MessageBus and runs:
- the AgentLoop message-consumer task;
- the CLI input loop;
- the outbound-consumer task;
- stream/progress presentation.
This resembles Channel mode more closely, but it still excludes external chat-platform authentication, networking, and message conversion.
3. Gateway
Command:
nanobot gatewayGateway is the long-running assembly entry point. nanobot/cli/commands.py::_run_gateway creates and connects:
MessageBus;RuntimeEventBus;- a Provider snapshot;
SessionManager;- a workspace-scoped
CronService; AgentLoop;WebuiTurnCoordinator;ChannelManager;- an optional health server.
flowchart TD GW["_run_gateway"] --> MB["MessageBus"] GW --> RE["RuntimeEventBus"] GW --> SM["SessionManager"] GW --> CR["CronService"] GW --> AL["AgentLoop"] GW --> WC["WebuiTurnCoordinator"] GW --> CM["ChannelManager"] CM --> MB MB --> AL AL --> RE RE --> WC
Gateway primarily supports:
- chat Channels;
- WebUI;
- WebSocket;
- Cron;
- Heartbeat;
- Dream;
- long-running background tasks.
nanobot/gateway/runtime.pyis not the core assembly flowThe current core Gateway assembly lives mainly in
cli/commands.py::_run_gateway.nanobot/gateway/runtime.pyalso controls process and service execution. Do not infer the entry point from a directory name.
4. OpenAI-compatible HTTP API
Command:
nanobot servePrimary endpoints:
POST /v1/chat/completionsGET /v1/modelsGET /health
The implementation is in nanobot/api/server.py and uses aiohttp.web, not FastAPI.
Request-handling characteristics:
- JSON or multipart input;
- session key
api:<session_id>, falling back toapi:default; - a separate
asyncio.Lockfor each API session; - calls
AgentLoop.process_direct(); - SSE for streaming mode;
- SSE completion waits for
process_direct()to finish.
This separates API problems into two layers:
HTTP parsing / SSE / session lock
→ process_direct
→ general Agent behavior5. Python SDK
Entry class:
from nanobot import NanobotPrimary source:
nanobot/nanobot.py::Nanobotnanobot/sdk/streaming.pynanobot/sdk/types.py
Nanobot.from_config() creates an AgentLoop internally. run(), run_streamed(), and stream() eventually reuse process_direct() while adding:
- Python types;
- hooks;
- stream events;
- Session, Memory, and runtime clients;
- per-run overrides.
The SDK is for embedding nanobot in a Python program. It does not manage long-lived Channel connections.
6. WebSocket and WebUI
WebUI is not an independent Agent runtime. Its primary relationship is:
React/TypeScript WebUI
↔ WebSocket Channel
↔ MessageBus
↔ AgentLoopIn Gateway, WebuiTurnCoordinator subscribes to the general RuntimeEventBus and converts Turn, Goal, and runtime state into WebUI coordination behavior. Under the project’s design constraints:
- AgentLoop may publish general runtime events;
- concrete wire/UI behavior such as
_turn_endand_goal_statusshould not live in core AgentLoop; - WebUI/WebSocket details stay in the coordinator or Channel adapter.
Entry-point comparison
| Entry point | Resident process? | Core path | Main output | Best use |
|---|---|---|---|---|
CLI -m | No | process_direct | terminal text/stream | minimal validation |
| Interactive CLI | During the session | MessageBus | terminal interaction | multi-turn debugging |
| Gateway/Channel | Yes | MessageBus | Channel messages | chat platforms and automation |
| HTTP API | During service lifetime | process_direct | JSON/SSE | external program calls |
| Python SDK | Managed by host | process_direct | Python objects/events | application embedding |
| WebUI | Requires Gateway | WebSocket Channel + MessageBus | WebSocket/UI | browser interaction |
Debugging starting points
| Symptom | Inspect first |
|---|---|
| Every entry point fails | Config, Provider factory, AgentLoop/Runner |
| CLI works, API fails | parsing, session handling, and SSE in api/server.py |
| CLI works, Channel does not respond | Channel, allowFrom/Pairing, ChannelManager |
| CLI works, WebUI does not update | WebSocket, RuntimeEventBus, WebuiTurnCoordinator |
| Normal messages work, Cron does not run | Gateway, CronService, workspace cron store |
| SDK stream is incomplete | SDK streaming adapter and process_direct callbacks |
Source and tests
| Subject | Source | Tests |
|---|---|---|
| CLI | nanobot/cli/commands.py | tests/cli/ |
| Gateway | nanobot/cli/commands.py::_run_gateway | tests/cli/test_gateway_commands.py |
| API | nanobot/api/server.py | tests/test_openai_api.py or the current API test |
| SDK | nanobot/nanobot.py, nanobot/sdk/ | search tests for Nanobot and streaming |
| Channel | nanobot/channels/ | tests/channels/ |
| Runtime UI coordination | nanobot/session/webui_turns.py | tests/webui/ and related Session tests |
Verify test names against the current repository
API and SDK tests may be organized by feature rather than source directory. Run
rg --files tests | rg "api|sdk|stream"before executing a test.
Self-check
- Why can
nanobot servecall the core without first publishing to MessageBus? - Why does Gateway create both MessageBus and RuntimeEventBus?
- If CLI works and WebUI fails, why should AgentRunner not be your first edit?
- Why is WebUI not another Agent implementation?