gnosari-engine 0.5.0
A powerful framework for orchestrating multi-agent teams using Large Language Models. Create intelligent AI agent swarms that collaborate through streaming delegation and dynamic tool discovery.
Requires Python: <=3.14,>=3.12

<div align="center">
  <img src="docs/static/img/logo.png" alt="Gnosari Logo" width="200">

  # Gnosari Engine

  **Core Agent Orchestration Library**

</div>

The Gnosari Engine is the core orchestration layer for AI agent teams. It provides configuration-driven agent management, tool integration, knowledge retrieval (RAG), and multi-agent coordination.

---

## Table of Contents

1. [Quick Start](#quick-start)
2. [Architecture Overview](#architecture-overview)
3. [Providers](#providers)
4. [Agent Execution Flow](#agent-execution-flow)
5. [YAML Configuration Reference](#yaml-configuration-reference)
6. [CLI Commands](#cli-commands)
7. [Tools System](#tools-system)
8. [Knowledge System (RAG)](#knowledge-system-rag)
9. [Sessions](#sessions)
10. [Structured Output](#structured-output)
11. [Events System](#events-system)
12. [Non-Active Fields Reference](#non-active-fields-reference)

---

## Quick Start

### Prerequisites

- **Python 3.12+**
- **Poetry** for dependency management
- **API Keys** for LLM providers

### Installation

```bash
# Clone and install
git clone https://github.com/neomanex/gnosari-engine.git
cd gnosari-engine
poetry install

# Set up environment
cp .env.example .env
# Edit .env with your API keys
```

### Your First Team

Create `my-team.yaml`:

```yaml
id: "my-team"
name: "My First Team"

agents:
  - id: "coordinator"
    is_orchestrator: true
    model: "gpt-4o"
    instructions: |
      You coordinate tasks and delegate to specialists.
    delegations:
      - target_agent_id: "writer"
        instructions: "Delegate writing tasks"

  - id: "writer"
    model: "gpt-4o"
    instructions: |
      You create clear, engaging content.
```

### Run Your Team

```bash
# Run entire team
poetry run gnosari run my-team.yaml -m "Write a blog post about AI"

# Run specific agent
poetry run gnosari run my-team.yaml -m "Hello" -a coordinator

# With streaming
poetry run gnosari run my-team.yaml -m "Hello" --stream
```

---

## Architecture Overview

```
┌─────────────────────────────────────────────────────────────────┐
│                        CLI / Library                            │
│  gnosari run | gnosari push | gnosari knowledge | gnosari view  │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                    Configuration Service                        │
│         Parse → Validate → Build → Resolve → Index              │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                      Domain Objects                             │
│            Team, Agent, Tool, Knowledge, Trait                  │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                     GnosariRunner                               │
│              Provider autodiscovery + execution                 │
└─────────────────────────────────────────────────────────────────┘
                              │
              ┌───────────────┴───────────────┐
              ▼                               ▼
┌─────────────────────────┐     ┌─────────────────────────┐
│    OpenAI Provider      │     │    Claude Provider      │
│   (OpenAI Agents SDK)   │     │  (Claude Agent SDK)     │
│    Default provider     │     │  Best for dev/complex   │
└─────────────────────────┘     └─────────────────────────┘
```

### Directory Structure

```
src/gnosari_engine/
├── cli/                    # CLI commands and services
│   └── commands/           # run, view, push, task, start, learn, status, version
├── config/                 # Configuration loading pipeline
├── factories/              # Domain object factories
├── knowledge/              # Knowledge loading service (uses gnosisllm-knowledge library)
│   └── services/           # KnowledgeLoaderService
├── learning/               # Agent learning system (parking)
├── prompts/                # Prompt building utilities
├── queue/                  # Celery async task queue (ready, not active)
├── runners/                # Provider strategies
│   ├── provider/           # OpenAI, Claude implementations
│   └── factories/          # Stream processor factory
├── schemas/                # Pydantic domain models
│   └── domain/             # Team, Agent, Tool, Knowledge, Event, etc.
├── services/               # Business logic services
├── sessions/               # Session persistence
│   ├── providers/          # openai, claude session providers
│   └── events/             # Redis event publishing
└── tools/                  # Tool implementations
    ├── builtin/            # KnowledgeQueryTool, MemoryTool, EmitEventTool, etc.
    ├── factories/          # Tool factory
    ├── providers/          # Provider-specific tool wrappers
    └── streaming/          # Tool streaming support
```

---

## Providers

### OpenAI Provider (Default)

- Uses **OpenAI Agents SDK** (`agents` package)
- General-purpose orchestration
- Native support for handoffs, delegations (as tools), MCP servers
- Session persistence via database

### Claude Provider

- Uses **Claude Agent SDK**
- Best suited for development and complex tasks
- Session integration not yet implemented

---

## Agent Execution Flow

### The AgentRun → ctx.context Flow

This is the key pattern for understanding how context flows through the engine:

```
┌──────────────────────────────────────────────────────────────────┐
│  1. AgentRun Created                                             │
│     - agent: Agent configuration                                 │
│     - team: Team configuration                                   │
│     - message: User input                                        │
│     - context: ExecutionContext (stream, debug, etc.)            │
│     - metadata: AgentRunMetadata (session_id, account_id, etc.)  │
└──────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌──────────────────────────────────────────────────────────────────┐
│  2. Prompt Building                                              │
│     AgentPromptBuilder.build_agent_prompt()                      │
│     - Base instructions                                          │
│     - Team context                                               │
│     - Traits (name, description, instructions)                   │
│     - Knowledge sources (with query instructions)                │
│     - Available tools                                            │
│     - Handoffs/delegations info                                  │
│     - Memory (if not empty)                                      │
└──────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌──────────────────────────────────────────────────────────────────┐
│  3. OpenAI Agent Creation (OpenAIAgentFactory)                   │
│     Agent(                                                       │
│       name=agent.name,                                           │
│       instructions=processed_instructions,                       │
│       model=agent.model,                                         │
│       tools=[...regular_tools, ...delegation_tools],             │
│       handoffs=[...handoff_agents],                              │
│     )                                                            │
└──────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌──────────────────────────────────────────────────────────────────┐
│  4. Execution                                                    │
│     Runner.run(                                                  │
│       agent,                                                     │
│       input=message,                                             │
│       session=openai_session,                                    │
│       context=agent_run  ◄── AgentRun passed as context          │
│     )                                                            │
└──────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌──────────────────────────────────────────────────────────────────┐
│  5. Tool Execution                                               │
│     async def _execute_openai_tool(ctx, args):                   │
│       session_context = ctx.context  ◄── ctx.context IS AgentRun │
│       result = await base_tool.execute_core_logic(               │
│         agent_run=session_context,                               │
│         **parsed_args                                            │
│       )                                                          │
└──────────────────────────────────────────────────────────────────┘
```

### Delegation vs Handoffs

| Aspect | Delegations | Handoffs |
|--------|-------------|----------|
| Implementation | `.as_tool()` - Agent becomes a tool | Native `Agent.handoffs` array |
| Context | **Stateless** - doesn't pass conversation context | **Stateful** - transfers full control with context |
| Use Case | Sub-tasks, specialized operations | Complete workflow transfer |
| Return | Returns to calling agent | Does not return automatically |

### MCP Server Lifecycle

MCP servers require manual lifecycle management within a single async task to avoid cancel scope issues:

```python
# Task-isolated streaming pattern
async def _isolated_producer():
    connected_servers = []
    try:
        # Connect in THIS task
        for server in mcp_servers:
            await server.connect()
            connected_servers.append(server)

        # Run agent
        async for event in result.stream_events():
            await event_queue.put(event)
    finally:
        # Cleanup in THIS task (same task as connect)
        for server in connected_servers:
            await server.cleanup()
```

---

## YAML Configuration Reference

### Team Configuration

```yaml
# Required
id: "my-team"                    # Team identifier (unique)

# Optional
name: "My Team"                  # Display name (auto-generated from id if not set)
description: "Team description"  # Optional description
version: "1.0.0"                 # Configuration version
tags: ["production", "sales"]    # Team tags for organization

# Team-level configuration
config:
  max_turns: 25                  # Maximum conversation turns
  timeout: 600                   # Execution timeout in seconds
  debug: false                   # Enable debug mode

# Components
agents: [...]                    # Required - at least one agent
tools: [...]                     # Team-level tools
knowledge: [...]                 # Team-level knowledge bases
traits: [...]                    # Team-level traits
```

### Agent Configuration

```yaml
# Required
id: "ceo"                       # Agent identifier (unique within team)
instructions: |                 # Agent base instructions (min 10 chars)
  You are the CEO agent responsible for...

# Optional - Identity
name: "CEO Agent"               # Display name (auto-generated from id)
description: "Chief agent"      # Agent description

# Optional - Model Configuration
model: "gpt-4o"                 # LLM model (default: gpt-4o or env OPENAI_MODEL)

# Optional - Behavior
is_orchestrator: true           # Exactly ONE agent must be orchestrator
max_turns: 10                   # Override team max_turns
debug: false                    # Enable debug mode for this agent

# Optional - Components (reference IDs or inline definitions)
tools:                          # Tools available to this agent
  - "api_tool"
  - "mcp_server"
knowledge:                      # Knowledge bases available
  - "company_docs"
traits:                         # Personality traits
  - "helpful"
  - "professional"

# Optional - Agent Relations
handoffs:                       # Agents to transfer control to
  - target_agent_id: "specialist"
    condition: "When technical expertise needed"
    message: "Transferring to specialist"

delegations:                    # Agents to delegate tasks to
  - target_agent_id: "researcher"
    instructions: "Research the topic thoroughly"

# Optional - Memory
memory:
  content: "Previous context..."  # Persisted memory content

# Optional - Structured Output (forces typed JSON responses)
structured_output:
  example:                      # Schema inferred from example types
    task_name: "Implement feature"
    priority: "high"
    estimated_hours: 8
  strict: true                  # Enable strict mode (default: true)
```

### Tool Configuration

#### Built-in Tool

```yaml
id: "knowledge_query"           # Tool identifier
name: "Knowledge Query"         # Display name
description: "Query knowledge"  # Tool description

# Built-in tool definition
module: "gnosari_engine.tools.builtin.knowledge_query"
class_name: "KnowledgeQueryTool"

# Tool arguments
args:
  some_config: "value"
```

#### MCP Tool (HTTP/SSE)

```yaml
id: "my_mcp_server"
name: "My MCP Server"
description: "External MCP server"

# MCP configuration
url: "http://localhost:8000/mcp"
connection_type: "sse"          # "sse" | "streamable_http" | "stdio"
headers:
  Authorization: "Bearer ${API_KEY}"
timeout: 30                     # Connection timeout in seconds
```

#### MCP Tool (Stdio)

```yaml
id: "local_mcp"
name: "Local MCP"

command: "python"
connection_type: "stdio"
args:
  - "-m"
  - "my_mcp_server"
```

### Knowledge Configuration

```yaml
id: "company_docs"              # Knowledge identifier
name: "Company Documentation"   # Display name
description: "Internal docs"    # Description (shown in agent prompt)

# Knowledge type and sources
type: "website"                 # website | sitemap | youtube | pdf | text | csv | json | directory
data:                           # Data sources (URLs or file paths)
  - "https://docs.company.com"
  - "https://wiki.company.com"

# Optional - Provider configuration
config:
  provider: "opensearch"
  opensearch:
    host: "localhost"
    port: 9200
  loader_config:
    chunk_size: 6000
    chunk_overlap: 200
```

### Trait Configuration

```yaml
id: "helpful"                   # Trait identifier
name: "Helpful"                 # Display name
description: "Always helpful"   # Description (shown in agent prompt)
instructions: |                 # Behavior instructions (injected into system prompt)
  Always be helpful and supportive.
  Provide clear explanations.
```

### Environment Variable Substitution

Use `${VAR_NAME}` or `${VAR_NAME:default_value}` in YAML:

```yaml
tools:
  - id: "api_tool"
    url: "${API_URL:http://localhost:8000}"
    headers:
      Authorization: "Bearer ${API_KEY}"
```

### Complete Example

```yaml
id: "sales-team"
name: "Sales Team"
version: "1.0.0"

config:
  max_turns: 25
  timeout: 600

traits:
  - id: "professional"
    name: "Professional"
    instructions: "Maintain professional communication at all times."

  - id: "empathetic"
    name: "Empathetic"
    instructions: "Show empathy and understanding to customers."

knowledge:
  - id: "product_catalog"
    name: "Product Catalog"
    description: "All product information and pricing"
    type: "website"
    data:
      - "https://products.company.com"

tools:
  - id: "crm_api"
    name: "CRM API"
    url: "http://localhost:8001/mcp"
    connection_type: "streamable_http"
    timeout: 30

agents:
  - id: "sales_manager"
    name: "Sales Manager"
    is_orchestrator: true
    instructions: |
      You are the Sales Manager responsible for:
      - Handling customer inquiries
      - Delegating to specialists when needed
      - Closing deals
    model: "gpt-4o"
    tools:
      - "crm_api"
    knowledge:
      - "product_catalog"
    traits:
      - "professional"
      - "empathetic"
    delegations:
      - target_agent_id: "product_specialist"
        instructions: "Get detailed product information"

  - id: "product_specialist"
    name: "Product Specialist"
    is_orchestrator: false
    instructions: |
      You are a Product Specialist with deep knowledge of:
      - Product features and specifications
      - Technical details
      - Pricing and availability
    knowledge:
      - "product_catalog"
    traits:
      - "professional"
```

---

## CLI Commands

### `gnosari run`

Run a team or specific agent.

```bash
# Run entire team (orchestrator handles routing)
gnosari run teams/my_team.yaml -m "Hello team!"

# Run specific agent
gnosari run teams/my_team.yaml -m "Hello agent!" -a ceo

# With session persistence
gnosari run teams/my_team.yaml -m "Continue discussion" -s session-001

# Options
--stream/--no-stream            # Streaming output (default: enabled)
--debug/--no-debug              # Debug mode
--provider [openai|claude]      # LLM provider (default: openai)
--database-url URL              # Database for sessions
--tool-streaming/--no-tool-streaming  # Tool streaming (default: enabled)
```

### `gnosari view`

View team configuration details.

```bash
# Tree format (default)
gnosari view teams/my_team.yaml

# JSON format
gnosari view teams/my_team.yaml --format json

# Table format
gnosari view teams/my_team.yaml --format table

# Flow chart
gnosari view teams/my_team.yaml --format chart
```

### `gnosari push`

Push team configuration to Gnosari API.

```bash
gnosari push teams/my_team.yaml --api-url https://api.gnosari.com
```

### `gnosari knowledge` (via gnosisllm-knowledge library)

The knowledge CLI is provided by the `gnosisllm-knowledge` library.

```bash
# Show all available commands
gnosari knowledge --help

# Setup OpenSearch with ML model for neural search
gnosari knowledge setup

# Load and index content from URLs or sitemaps
gnosari knowledge load <url>

# Search indexed content
gnosari knowledge search "query" --mode hybrid

# Show configuration and environment info
gnosari knowledge info

# Agentic search commands
gnosari knowledge agentic setup   # Setup agentic search agents
gnosari knowledge agentic chat    # Interactive agentic chat
gnosari knowledge agentic status  # Show agent status
```

### `gnosari task run`

Execute a task by ID from the database.

```bash
gnosari task run teams/my_team.yaml --task-id 123
gnosari task run teams/my_team.yaml -t 123 --async  # Async via queue
```

### `gnosari start`

Start the queue worker (for async task execution).

```bash
gnosari start
gnosari start --concurrency 8
gnosari start --queue priority_queue
```

### `gnosari learn`

Learning system commands (currently in development).

### `gnosari status`

Check system status.

### `gnosari version`

Display version information.

---

## Tools System

### Built-in Tools

| Tool | Description | Auto-Injected |
|------|-------------|---------------|
| `KnowledgeQueryTool` | Query knowledge bases (multi-KB, search modes) | Yes, when agent has knowledge |
| `MemoryTool` | Store and recall agent memories | No |
| `EmitEventTool` | Emit events to UI via tool streaming | No |
| `GnosariTasksTool` | Task management operations | No |
| `CodingAgentTool` | Code execution | No |

### Tool Factory

The `AutoDiscoveryToolFactory` automatically discovers tools:

1. Looks up tool by `module` + `class_name`
2. Creates provider-specific wrapper (OpenAI, Claude)
3. Initializes with `args` from configuration
4. Passes `agent_run` for context access

### MCP Integration

MCP (Model Context Protocol) is the preferred way to add custom tools:

```yaml
tools:
  - id: "external_api"
    url: "http://localhost:8000/mcp"
    connection_type: "streamable_http"  # Recommended
    headers:
      Authorization: "Bearer ${TOKEN}"
    timeout: 30
```

**Connection Types:**
- `sse`: Server-Sent Events (legacy)
- `streamable_http`: HTTP with streaming (recommended)
- `stdio`: Local subprocess

---

## Knowledge System (RAG)

### Architecture

The knowledge system uses the **gnosisllm-knowledge** library as a facade for all knowledge operations:

- **Unified API**: Single `Knowledge` class handles all search and indexing operations
- **Multi-Knowledge Query**: Query multiple knowledge bases in a single call
- **Multiple Search Modes**: hybrid, semantic, keyword, and agentic search
- **Multi-Tenancy**: Per-account index isolation via `index_name` field

### OpenSearch Integration

Knowledge bases use OpenSearch with hybrid search:

- **Keyword search**: BM25 algorithm
- **Semantic search**: OpenAI embeddings (1536 dimensions)
- **Hybrid scoring**: Combination of both (default mode)
- **Agentic search**: AI-powered reasoning with citations

### Data Loaders

| Type | Description | Data Format |
|------|-------------|-------------|
| `website` | Scrape web pages | URLs |
| `sitemap` | Parse sitemap and scrape | Sitemap URL |
| `discovery` | Crawl and discover URLs | Starting URL |
| `youtube` | Extract transcripts | YouTube URLs |
| `pdf` | Parse PDF documents | File paths or URLs |
| `text` | Plain text files | File paths |
| `csv` | CSV data | File paths |
| `json` | JSON data | File paths |
| `directory` | All files in directory | Directory path |

### Auto-Injection

When an agent has `knowledge` configured, the engine automatically:

1. Adds `knowledge_query` tool to the agent
2. Includes knowledge sources in the system prompt
3. Provides query instructions to the agent

### Multi-Knowledge Query

The `KnowledgeQueryTool` supports querying multiple knowledge bases in a single call:

```python
# Query multiple KBs
knowledge_names=["docs", "faq", "support"]
search_mode="hybrid"  # or "semantic", "keyword", "agentic"
limit=10
```

Results include `collection_id` to identify the source knowledge base for each result.

---

## Sessions

### GnosariSession

Sessions persist conversation history:

- **Provider**: `openai_database` (SQL-based)
- **Storage**: PostgreSQL, MySQL, or SQLite
- **Tracking**: session_id, account_id, team_id, agent_id

### Session Configuration

```bash
# Environment variables
SESSION_PROVIDER=file|database|gnosari_api
SESSION_DATABASE_URL=postgresql+asyncpg://user:pass@host:port/db

# Usage
gnosari run team.yaml -m "Hello" -s session-001
gnosari run team.yaml -m "What did I say?" -s session-001  # Remembers context
```

### Session Events (Redis)

Sessions can publish events to Redis for real-time updates:

- Located in `sessions/events/`
- `RedisPublisher` for event publishing
- Event models for structured event data

---

## Structured Output

Structured output enables agents to return responses in a **defined schema format** rather than free-form text.

### Configuration Modes

| Mode | Fields | Description |
|------|--------|-------------|
| **Example Only** | `example` | Schema auto-inferred from example types |
| **Schema Only** | `schema` | Explicit JSON Schema definition |
| **Both** | `schema` + `example` | Full control with LLM guidance (recommended) |

### Type Inference (Example-Only Mode)

| YAML Value | Inferred Type |
|------------|---------------|
| `"string"` | `string` |
| `123` | `integer` |
| `12.5` | `number` |
| `true/false` | `boolean` |
| `["a", "b"]` | `array` |
| `{key: val}` | `object` (recursive) |

### Example Configuration

```yaml
agents:
  - id: "task_analyzer"
    instructions: "Analyze tasks and return structured data"
    is_orchestrator: true
    structured_output:
      example:
        task_name: "Implement feature X"
        priority: "high"
        estimated_hours: 8
        tags: ["backend", "api"]
        subtasks:
          - name: "Design"
            hours: 2
      strict: true
```

### Implementation Details

- **OpenAI Provider**: Uses `output_type` parameter with dynamically generated Pydantic models
- **Result Handling**: Structured outputs are automatically converted to Python dicts
- **Strict Mode**: When `strict: true` (default), OpenAI enforces exact schema compliance

---

## Events System

The engine supports emitting events to the UI via the `EmitEventTool`.

### EmitEventTool

A passthrough tool that emits events to the UI via existing tool streaming:

```python
# Tool receives event data and returns it unchanged
# UI detects emit_event tool calls and handles them as events

event_id: str          # Event identifier (e.g., "conversation.completed")
metadata_json: str     # JSON string containing event payload
```

### Usage in Agent Instructions

```yaml
agents:
  - id: "event_emitter"
    instructions: |
      When you complete a task, emit an event using the emit_event tool:
      - event_id: "task.completed"
      - metadata_json: '{"task_name": "...", "result": "success"}'
    tools:
      - id: "emit_event"
        module: "gnosari_engine.tools.builtin.emit_event"
        class_name: "EmitEventTool"
```

### How It Works

1. Agent calls `emit_event` tool with event_id and metadata
2. Tool returns event data unchanged
3. UI receives tool_call/tool_result via streaming
4. UI detects `emit_event` calls and processes as events

---

## Non-Active Fields Reference

The following fields are defined in the schema but **not actively used** in execution:

### Agent Fields

| Field | Status | Notes |
|-------|--------|-------|
| `temperature` | **Loaded but NOT passed to OpenAI** | Bug/oversight - should be passed |
| `reasoning_effort` | Not used | Defined but not implemented |
| `role` | Display + learning only | Not used in execution |
| `listen` | Not implemented | Event system planned |
| `trigger` | Not implemented | Event system planned |
| `learning_objectives` | Learning system only | System is being rethought |

### Delegation Fields

| Field | Status | Notes |
|-------|--------|-------|
| `mode` | Display only | Always uses sync via `.as_tool()` |
| `timeout` | Not used | Delegation timeout not implemented |
| `retry_attempts` | Not used | Retry logic not implemented |

### Trait Fields

| Field | Status | Notes |
|-------|--------|-------|
| `weight` | Display only | Not used for actual weighting in prompts |
| `category` | Display only | For organization, not execution |
| `tags` | Display only | For organization, not execution |

### Tool Fields

| Field | Status | Notes |
|-------|--------|-------|
| `rate_limit` | Not implemented | Rate limiting not implemented |
| `enable_caching` | Not implemented | Response caching not implemented |
| `cache_timeout` | Not implemented | Cache timeout not implemented |
| `retry_attempts` | Not implemented | Retry logic for builtin tools not implemented |
| `retry_delay` | Not implemented | Retry delay not implemented |

### Team Fields

| Field | Status | Notes |
|-------|--------|-------|
| `config.log_level` | Not used | Logging configured via CLI |
| `config.enable_memory` | Not used | Memory always available |
| `overrides` | Loaded, not applied | Override system not implemented |
| `components` | Not used | Component filtering not implemented |
| `account_id` | Display/push only | Not used in execution |

---

## Development

### Environment Setup

Required environment variables (see `.env.example`):

```bash
OPENAI_API_KEY=your-key
ANTHROPIC_API_KEY=your-key      # If using Claude
GNOSARI_API_KEY=your-key        # For pushing teams
OPENSEARCH_HOST=localhost       # For knowledge system
OPENSEARCH_PORT=9200
```

### Key Files

| File | Purpose |
|------|---------|
| `runners/gnosari_runner.py` | Main entry point, provider autodiscovery |
| `runners/provider/openai.py` | OpenAI provider implementation |
| `runners/provider/claude.py` | Claude provider implementation |
| `config/services.py` | YAML → Domain Objects pipeline |
| `prompts/agent_prompt_builder.py` | System prompt construction |
| `schemas/domain/*.py` | Team, Agent, Tool, Knowledge models |
| `tools/builtin/*.py` | Built-in tool implementations |
| `tools/factories/` | Tool factory |

---

## License

Creative Commons Attribution 4.0 International License

---

**Maintenance:** Update this file when architecture, CLI, configuration options, or significant patterns change.