# DeepTutor System Architecture: An Agent-Native Platform with Two-Layer Registry

> Explore the DeepTutor system architecture, an agent-native platform with a two-layer registry. Discover its modular design for efficient task execution and request routing.

- Repository: [✨Data Intelligence Lab@HKU✨/DeepTutor](https://github.com/HKUDS/DeepTutor)
- Tags: architecture
- Published: 2026-04-08

---

**DeepTutor implements a modular, agent-native architecture that decouples *what* the system can do from *how* it executes tasks, using a central ChatOrchestrator to route requests through separate registries for lightweight tools and multi-step capabilities.**

The DeepTutor system architecture, as defined in the HKUDS/DeepTutor repository, centers on the **ChatOrchestrator** class in [`deeptutor/runtime/orchestrator.py`](https://github.com/HKUDS/DeepTutor/blob/main/deeptutor/runtime/orchestrator.py). This design creates a clean separation between single-function utilities and complex reasoning pipelines, enabling developers to extend functionality without modifying core routing logic.

## Core Architectural Components

### The ChatOrchestrator

The **ChatOrchestrator** serves as the central router for all incoming requests. Regardless of whether a request originates from the CLI, WebSocket, or Python SDK, the orchestrator creates a **UnifiedContext** and streams events back to the caller. According to the source code in [`deeptutor/runtime/orchestrator.py`](https://github.com/HKUDS/DeepTutor/blob/main/deeptutor/runtime/orchestrator.py), the orchestrator handles capability selection, tool injection, and event coordination through a unified async interface.

### UnifiedContext Dataclass

Every request in DeepTutor travels through the system as an immutable **UnifiedContext** object defined in [`deeptutor/core/context.py`](https://github.com/HKUDS/DeepTutor/blob/main/deeptutor/core/context.py). This dataclass encapsulates session state, including the user message, conversation history, enabled tools, knowledge base references, and the active capability. By passing a single context object through every layer, DeepTutor maintains consistent state without global variables.

## The Two-Layer Registry System

DeepTutor separates functionality into two distinct registry layers to isolate simple utilities from complex workflows.

### Level 1: Tool Registry

The **ToolRegistry** ([`deeptutor/runtime/registry/tool_registry.py`](https://github.com/HKUDS/DeepTutor/blob/main/deeptutor/runtime/registry/tool_registry.py)) manages **Level 1** components: lightweight, single-function tools such as `rag`, `web_search`, and `code_execution`. These tools inherit from `BaseTool` and declare schemas via `ToolSchema`. The registry handles discovery, registration, and automatic OpenAI-compatible schema generation for LLM function calling.

### Level 2: Capability Registry

The **CapabilityRegistry** ([`deeptutor/runtime/registry/capability_registry.py`](https://github.com/HKUDS/DeepTutor/blob/main/deeptutor/runtime/registry/capability_registry.py)) holds **Level 2** multi-step pipelines like `chat`, `deep_solve`, and `deep_question`. Capabilities orchestrate sequences of tool calls and reasoning steps. The registry exposes these high-level behaviors to the orchestrator, which selects the appropriate capability based on `context.active_capability` (defaulting to `chat` when unspecified).

## Execution Flow and Data Pipeline

The request lifecycle follows a strict pipeline from entry to completion:

1. **Context Creation**: Entry points (CLI, WebSocket, SDK) instantiate a `UnifiedContext` with session metadata and user input.
2. **Capability Resolution**: The orchestrator queries the **CapabilityRegistry** to load the requested capability.
3. **Tool Injection**: The capability dynamically requests tools from the **ToolRegistry** as needed during execution.
4. **Streaming Output**: The capability publishes `StreamEvent` objects to the **StreamBus** ([`deeptutor/core/stream_bus.py`](https://github.com/HKUDS/DeepTutor/blob/main/deeptutor/core/stream_bus.py)), which the orchestrator yields to the client in real-time.
5. **Completion Signaling**: Upon finishing, the orchestrator posts a `CAPABILITY_COMPLETE` event to the global **EventBus** ([`deeptutor/events/event_bus.py`](https://github.com/HKUDS/DeepTutor/blob/main/deeptutor/events/event_bus.py)) for analytics and logging.

## Entry Points and Integration

DeepTutor exposes three primary entry points that uniformly invoke the orchestrator:

- **CLI**: Implemented in [`deeptutor_cli/main.py`](https://github.com/HKUDS/DeepTutor/blob/main/deeptutor_cli/main.py) using Typer for command-line interactions.
- **WebSocket**: The `/api/v1/ws` endpoint defined in [`deeptutor/api/routers/unified_ws.py`](https://github.com/HKUDS/DeepTutor/blob/main/deeptutor/api/routers/unified_ws.py) handles browser-based streaming connections.
- **Python SDK**: Direct programmatic access via the `ChatOrchestrator` class for embedded applications.

All entry points transform their specific input formats into a `UnifiedContext` before calling `ChatOrchestrator.handle()`.

## Streaming and Event Architecture

Real-time communication relies on the **StreamBus** and **EventBus** components. Capabilities push `StreamEvent` instances containing content chunks, error messages, or termination signals (`DONE`) to the StreamBus. The orchestrator asynchronously forwards these events to the client. Simultaneously, the EventBus publishes lifecycle events like `CAPABILITY_COMPLETE` to decouple analytics from core execution.

## Extensibility via Plugins

The **Playground** system in `deeptutor/plugins/` allows third-party extensions. The plugin loader ([`deeptutor/plugins/loader.py`](https://github.com/HKUDS/DeepTutor/blob/main/deeptutor/plugins/loader.py)) discovers additional capabilities at runtime, exposing them alongside built-in features like `deep_research`. This architecture ensures the core system remains lean while supporting experimental functionality through optional extensions.

## Practical Implementation Examples

### Invoking Capabilities via CLI

You can execute specific capabilities directly from the terminal using the Typer-based CLI:

```bash

# Install CLI dependencies

pip install -r requirements/cli.txt && pip install -e .

# Invoke the deep_solve capability with RAG tool enabled

deeptutor run deep_solve "Solve x^2 = 4" -t rag --kb my-kb

```

As documented in [`AGENTS.md`](https://github.com/HKUDS/DeepTutor/blob/main/AGENTS.md), this command routes through the orchestrator to execute a planning-reasoning-writing pipeline.

### Programmatic Usage with Python SDK

For embedded applications, instantiate the orchestrator directly and stream events:

```python
from deeptutor.runtime.orchestrator import ChatOrchestrator
from deeptutor.core.context import UnifiedContext
import asyncio

async def demo():
    ctx = UnifiedContext(
        user_message="Explain the Fourier transform",
        enabled_tools=["rag"],
        knowledge_bases=["docs"],
        active_capability="chat",
    )
    
    orchestrator = ChatOrchestrator()
    
    async for event in orchestrator.handle(ctx):
        if event.type == "content":
            print(event.content)
        elif event.type == "error":
            print("Error:", event.content)

asyncio.run(demo())

```

This example demonstrates how `ChatOrchestrator.handle()` processes the context and yields `StreamEvent` objects defined in [`deeptutor/core/stream.py`](https://github.com/HKUDS/DeepTutor/blob/main/deeptutor/core/stream.py).

### Registering Custom Tools

To add functionality, create a tool class and register it in the ToolRegistry:

```python
from deeptutor.core.tool_protocol import BaseTool, ToolSchema

class MyTool(BaseTool):
    schema = ToolSchema(
        name="my_tool",
        description="Demonstrates a custom tool",
        parameters={},
    )

    async def run(self, context, bus):
        await bus.content("MyTool executed!", source=self.name)

```

After placing this in [`deeptutor/tools/builtin/my_tool.py`](https://github.com/HKUDS/DeepTutor/blob/main/deeptutor/tools/builtin/my_tool.py) and registering it in [`deeptutor/runtime/registry/tool_registry.py`](https://github.com/HKUDS/DeepTutor/blob/main/deeptutor/runtime/registry/tool_registry.py), the tool becomes selectable via `context.enabled_tools`.

## Summary

- **DeepTutor** employs an agent-native architecture separating tools (Level 1) from capabilities (Level 2) through distinct registries.
- The **ChatOrchestrator** in [`deeptutor/runtime/orchestrator.py`](https://github.com/HKUDS/DeepTutor/blob/main/deeptutor/runtime/orchestrator.py) serves as the central dispatcher, managing execution flow and streaming responses.
- **UnifiedContext** ([`deeptutor/core/context.py`](https://github.com/HKUDS/DeepTutor/blob/main/deeptutor/core/context.py)) provides immutable, comprehensive session state that travels through every processing layer.
- Real-time communication uses the **StreamBus** for client-facing events and the **EventBus** for system-level analytics.
- The system supports CLI, WebSocket, and SDK entry points uniformly, with plugin-based extensibility via [`deeptutor/plugins/loader.py`](https://github.com/HKUDS/DeepTutor/blob/main/deeptutor/plugins/loader.py).

## Frequently Asked Questions

### What is the difference between tools and capabilities in DeepTutor?

**Tools** are Level 1 single-function utilities (e.g., `rag`, `web_search`) managed by [`deeptutor/runtime/registry/tool_registry.py`](https://github.com/HKUDS/DeepTutor/blob/main/deeptutor/runtime/registry/tool_registry.py), while **capabilities** are Level 2 multi-step pipelines (e.g., `deep_solve`, `chat`) that orchestrate tool sequences from [`deeptutor/runtime/registry/capability_registry.py`](https://github.com/HKUDS/DeepTutor/blob/main/deeptutor/runtime/registry/capability_registry.py). Capabilities define *how* to solve problems; tools provide specific *functions*.

### How does DeepTutor handle real-time streaming responses?

Capabilities emit `StreamEvent` objects to the **StreamBus** ([`deeptutor/core/stream_bus.py`](https://github.com/HKUDS/DeepTutor/blob/main/deeptutor/core/stream_bus.py)) during execution. The `ChatOrchestrator` asynchronously yields these events to the client, enabling real-time content delivery. Events include types for content chunks, errors, and completion signals.

### Where are plugins loaded in the DeepTutor architecture?

The **Plugin Loader** in [`deeptutor/plugins/loader.py`](https://github.com/HKUDS/DeepTutor/blob/main/deeptutor/plugins/loader.py) scans the `deeptutor/plugins/` directory at runtime to discover and register third-party capabilities. These extensions integrate seamlessly with the CapabilityRegistry, appearing alongside built-in features like `deep_research` without requiring core code modifications.

### What is the purpose of the UnifiedContext dataclass?

**UnifiedContext** ([`deeptutor/core/context.py`](https://github.com/HKUDS/DeepTutor/blob/main/deeptutor/core/context.py)) is an immutable dataclass that encapsulates all request state—including session ID, user message, enabled tools, and knowledge bases—ensuring consistent data propagation through every layer of the architecture. This design eliminates global state and enables thread-safe, asynchronous processing across the orchestrator, tools, and capabilities.