Architecture Deep Dive

Understanding jaato's architecture will help you navigate the codebase and identify where to make changes. This guide covers the core components, plugin system, and execution flows.

High-Level Architecture

At its core, jaato is a client framework that orchestrates communication between your application, AI models, and tool execution. Here's the layered architecture:

graph TB subgraph ClientLayer["Your Application Layer"] App["Generic Client Application
(Your code that uses jaato)"] end subgraph JaatoLayer["Jaato Framework Layer"] subgraph JaatoClient["JaatoClient (Main Orchestrator)"] API["Public API:
• connect()
• configure_tools()
• send_message()
• get_history()"] end subgraph CoreComponents["Core Components"] TE["ToolExecutor
(Runs tool functions)"] PR["PluginRegistry
(Manages plugins)"] TL["TokenLedger
(Token accounting)"] end subgraph PluginLayer["Plugin Layer"] PERM["PermissionPlugin
(Access control)"] TOOLS["Tool Plugins
(CLI, MCP, Todo, etc.)"] end end subgraph ProviderLayer["Provider Abstraction Layer"] Provider["ModelProviderPlugin
(Provider-agnostic interface)"] end subgraph ExternalServices["External AI Services"] Google["Google GenAI
(Gemini models)"] Anthropic["Anthropic
(Claude models)"] Others["Others..."] end App --> API API --> TE API --> PR API --> TL TE --> PERM PR --> TOOLS TE --> TOOLS API --> Provider Provider --> Google Provider --> Anthropic Provider --> Others classDef clientStyle fill:#e1f5ff,stroke:#0288d1,stroke-width:2px classDef frameworkStyle fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px classDef providerStyle fill:#fff3e0,stroke:#f57c00,stroke-width:2px classDef externalStyle fill:#e8f5e9,stroke:#388e3c,stroke-width:2px class App clientStyle class API,TE,PR,TL,PERM,TOOLS frameworkStyle class Provider providerStyle class Google,Anthropic,Others externalStyle

Key layers:

  • Application Layer (Blue) - Your code using jaato
  • Framework Layer (Purple) - jaato's core orchestration and plugin system
  • Provider Layer (Orange) - Abstract AI provider interface
  • External Services (Green) - AI model providers (Google, Anthropic, etc.)

Component Diagram

This diagram shows how the major components relate to each other and which external services they interact with.

flowchart TB subgraph Client["Generic Client Application"] App[Your Application] end subgraph Framework["JAATO Framework (shared/)"] JC[JaatoClient
jaato_client.py] subgraph Core["Core Components"] TE[ToolExecutor
ai_tool_runner.py] TL[TokenLedger
token_accounting.py] end subgraph Plugins["Plugin System"] PR[PluginRegistry
plugins/registry.py] subgraph Available["Available Plugins"] BG[BackgroundPlugin] CLI[CLIToolPlugin] MCP[MCPToolPlugin] PERM[PermissionPlugin] TODO[TodoPlugin] REFS[ReferencesPlugin] FEDIT[FileEditPlugin] SESS[SessionPlugin] end end MCM[MCPClientManager
mcp_context_manager.py] end subgraph External["External Services"] VAI[AI Provider
Models] MCPS[MCP Servers] Shell[Local Shell] end App --> JC JC --> TE JC --> TL JC --> PR PR --> BG PR --> CLI PR --> MCP PR --> PERM PR --> TODO PR --> REFS PR --> FEDIT TE --> PERM TE --> BG BG --> CLI BG --> MCP MCP --> MCM MCM --> MCPS CLI --> Shell JC --> VAI

Message Flow Sequence

When a user sends a message, jaato orchestrates communication between the model and tools. Here's the typical flow:

sequenceDiagram participant App as Generic Client participant JC as JaatoClient participant Provider as ModelProviderPlugin participant TE as ToolExecutor participant Plugin as Tool Plugin participant TL as TokenLedger App->>JC: send_message("List files") JC->>Provider: send_message() Provider->>Provider: Model generates response alt Response has function_calls Provider-->>JC: function_call: cli_based_tool JC->>TE: execute("cli_based_tool", args) TE->>Plugin: call registered executor Plugin-->>TE: result TE-->>JC: function response JC->>Provider: send_tool_results() Provider->>Provider: Model processes result end Provider-->>JC: final text response JC->>TL: record token usage JC-->>App: "Here are the files: ..."
Function Calling Loop

The sequence above can repeat multiple times if the model makes additional function calls based on previous results. JaatoClient handles this loop automatically until the model returns a final text response.

Plugin System Architecture

jaato has three distinct plugin systems, each serving a different purpose:

1. Tool Plugins

Managed by PluginRegistry, these provide tools for the model to call via function calling. Examples: CLI, MCP, file editing, web search.

  • Location: shared/plugins/*/
  • Entry Point: jaato.plugins
  • Protocol: ToolPlugin
  • Key Methods: get_tool_schemas(), get_executors()

2. GC (Garbage Collection) Plugins

Manage context window overflow by removing or summarizing old conversation turns. Strategies: truncate, summarize, hybrid.

  • Location: shared/plugins/gc_*/
  • Entry Point: jaato.gc_plugins
  • Protocol: GCPlugin
  • Key Methods: should_collect(), collect()

3. Model Provider Plugins

Abstract AI provider SDKs to provide a uniform interface. Supports Anthropic, Google GenAI, GitHub Models, Claude CLI, Antigravity, and Ollama.

  • Location: shared/plugins/model_provider/*/
  • Entry Point: jaato.model_providers
  • Protocol: ModelProviderPlugin
  • Key Methods: connect(), send_message(), get_history()

File Structure

Understanding where code lives will help you navigate the codebase:

jaato/
├── shared/                     # Core framework (internal)
│   ├── __init__.py             # Package exports
│   ├── jaato_client.py         # JaatoClient - main orchestrator
│   ├── ai_tool_runner.py       # ToolExecutor - function loop
│   ├── token_accounting.py     # TokenLedger - usage tracking
│   ├── mcp_context_manager.py  # MCP server connections
│   │
│   └── plugins/                # Plugin system
│       ├── base.py             # ToolPlugin protocol
│       ├── registry.py         # PluginRegistry
│       │
│       ├── model_provider/     # Provider abstraction
│       │   ├── base.py         # ModelProviderPlugin protocol
│       │   ├── types.py        # Provider-agnostic types
│       │   ├── anthropic/      # Anthropic Claude
│       │   ├── google_genai/   # Google GenAI / Vertex AI
│       │   ├── github_models/  # GitHub Models API
│       │   ├── claude_cli/     # Claude CLI wrapper
│       │   ├── antigravity/    # Google IDE backend
│       │   └── ollama/         # Ollama local models
│       │
│       ├── cli/                # CLI tool plugin
│       ├── mcp/                # MCP integration
│       ├── permission/         # Permission control
│       ├── todo/               # Task planning
│       ├── file_edit/          # File operations
│       ├── web_search/         # DuckDuckGo search
│       ├── session/            # Session persistence
│       │
│       ├── gc_truncate/        # GC: truncation strategy
│       ├── gc_summarize/       # GC: summarization strategy
│       └── gc_hybrid/          # GC: hybrid strategy
│
├── jaato/                      # Public API (for external use)
│   └── __init__.py             # Re-exports from shared/
│
├── simple-client/              # Reference implementation
│   └── interactive_client.py   # Interactive CLI client
│
└── docs/                       # Documentation
    ├── api/                    # HTML API docs (this site)
    └── architecture.md         # Architecture markdown

UI Hooks System

The framework provides a UI hooks system (AgentUIHooks protocol) that enables rich terminal UIs to integrate with agent execution. This provides visibility into agent lifecycle, tool execution, and accounting.

Key Hooks

Hook When Called Purpose
on_agent_status_changed Status change Start/stop spinner ("active", "done", "error")
on_tool_call_start Tool begins Show active tool below spinner
on_tool_call_end Tool completes Remove tool from display
on_agent_output Any output Route to agent's output buffer
on_agent_turn_completed Turn ends Update per-turn accounting

Tool Call Visualization

The on_tool_call_start and on_tool_call_end hooks enable real-time visualization of active tool calls. When a tool is executing, the UI can show it below the spinner:

Model> ⠋ thinking...
       ├─ cli_execute({'cmd': 'ls -la'})
       └─ web_search({'query': 'python docs'})

These hooks are emitted automatically for all plugins from JaatoSession._run_chat_loop(). No plugin-specific changes are required.

Hook and Callback Propagation

Hooks and callbacks are set at multiple levels to ensure all agents behave consistently:

  • JaatoClient.set_ui_hooks(hooks) - Main agent, passes to session
  • JaatoSession.set_ui_hooks(hooks, agent_id) - Tool lifecycle emission
  • JaatoSession.set_retry_callback(callback) - Routes retry notifications through custom handler
  • SubagentPlugin.set_ui_hooks(hooks) - Passes to spawned sessions
  • SubagentPlugin.set_retry_callback(callback) - Passes to spawned sessions
  • SubagentPlugin.set_plan_reporter(reporter) - Injects plan reporter into subagent TodoPlugins

The retry callback ensures rate limit retry messages from subagents are routed through the same channel as the parent (e.g., to the rich client's output panel) instead of printing to console.

The plan reporter ensures subagent plans are displayed in the UI (e.g., status bar popup) instead of the console. The reporter is injected via _injected_reporter in the TodoPlugin config.

See Subagent UI Hooks API for complete documentation.

Key Abstractions

Provider-Agnostic Types

To support multiple AI providers, jaato defines its own types in shared/plugins/model_provider/types.py:

  • ToolSchema - Function declaration (replaces SDK-specific types)
  • Message - Conversation message with role and parts
  • Part - Message content (text, function_call, function_response)
  • ProviderResponse - Unified response from any provider

Plugin Discovery

Plugins register via Python entry points in pyproject.toml:

[project.entry-points."jaato.plugins"]
cli = "shared.plugins.cli:create_plugin"
mcp = "shared.plugins.mcp:create_plugin"
todo = "shared.plugins.todo:create_plugin"

[project.entry-points."jaato.gc_plugins"]
gc_truncate = "shared.plugins.gc_truncate:create_plugin"
gc_summarize = "shared.plugins.gc_summarize:create_plugin"

User Commands vs Model Tools

Plugins can provide two types of capabilities:

Type Invoked By History Example
Model Tools AI via function calling Always in history cli_execute, web_search
User Commands User types directly Configurable plan, sessions

Related Pages

🏁 Getting Started

Set up your development environment and run tests.

🔌 Plugin Concepts

Learn how the plugin system works from a user perspective.

🛠️ Building Plugins

Step-by-step guide to creating your own tool plugin.

📄 Full Architecture Doc

Complete architecture markdown with all diagrams and details.