Five entry points and their runtime boundaries

Corresponding source

Entry pointSource
CLI and Gateway commandsnanobot/cli/commands.py::agent, _run_gateway
Gateway runtimenanobot/gateway/runtime.py, nanobot/gateway/service.py
HTTP APInanobot/api/server.py
Python facade and SDKnanobot/nanobot.py::Nanobot, nanobot/sdk/
Channelnanobot/channels/base.py, nanobot/channels/manager.py, nanobot/channels/
WebUI Turn coordinationnanobot/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_message

Properties:

  • 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 agent

Interactive 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 gateway

Gateway 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.py is not the core assembly flow

The current core Gateway assembly lives mainly in cli/commands.py::_run_gateway. nanobot/gateway/runtime.py also controls process and service execution. Do not infer the entry point from a directory name.

4. OpenAI-compatible HTTP API

Command:

nanobot serve

Primary endpoints:

  • POST /v1/chat/completions
  • GET /v1/models
  • GET /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 to api:default;
  • a separate asyncio.Lock for 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 behavior

5. Python SDK

Entry class:

from nanobot import Nanobot

Primary source:

  • nanobot/nanobot.py::Nanobot
  • nanobot/sdk/streaming.py
  • nanobot/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
  ↔ AgentLoop

In 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_end and _goal_status should not live in core AgentLoop;
  • WebUI/WebSocket details stay in the coordinator or Channel adapter.

Entry-point comparison

Entry pointResident process?Core pathMain outputBest use
CLI -mNoprocess_directterminal text/streamminimal validation
Interactive CLIDuring the sessionMessageBusterminal interactionmulti-turn debugging
Gateway/ChannelYesMessageBusChannel messageschat platforms and automation
HTTP APIDuring service lifetimeprocess_directJSON/SSEexternal program calls
Python SDKManaged by hostprocess_directPython objects/eventsapplication embedding
WebUIRequires GatewayWebSocket Channel + MessageBusWebSocket/UIbrowser interaction

Debugging starting points

SymptomInspect first
Every entry point failsConfig, Provider factory, AgentLoop/Runner
CLI works, API failsparsing, session handling, and SSE in api/server.py
CLI works, Channel does not respondChannel, allowFrom/Pairing, ChannelManager
CLI works, WebUI does not updateWebSocket, RuntimeEventBus, WebuiTurnCoordinator
Normal messages work, Cron does not runGateway, CronService, workspace cron store
SDK stream is incompleteSDK streaming adapter and process_direct callbacks

Source and tests

SubjectSourceTests
CLInanobot/cli/commands.pytests/cli/
Gatewaynanobot/cli/commands.py::_run_gatewaytests/cli/test_gateway_commands.py
APInanobot/api/server.pytests/test_openai_api.py or the current API test
SDKnanobot/nanobot.py, nanobot/sdk/search tests for Nanobot and streaming
Channelnanobot/channels/tests/channels/
Runtime UI coordinationnanobot/session/webui_turns.pytests/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

  1. Why can nanobot serve call the core without first publishing to MessageBus?
  2. Why does Gateway create both MessageBus and RuntimeEventBus?
  3. If CLI works and WebUI fails, why should AgentRunner not be your first edit?
  4. Why is WebUI not another Agent implementation?

Next step

Read Source tree and reading order.