Skip to content

Architecture

Brian Weisberg edited this page Feb 17, 2026 · 3 revisions

Architecture

Tooli uses a three-layer architecture with a dual pipeline for parameter resolution.

Three-Layer Architecture

┌─────────────────────────────────────┐
│         Provider Layer              │
│  LocalProvider · FileSystemProvider │
└──────────────┬──────────────────────┘
               │ list[ToolDef]
┌──────────────▼──────────────────────┐
│      Transform Pipeline Layer       │
│  Namespace · Visibility · Version   │
└──────────────┬──────────────────────┘
               │ list[ToolDef]
┌──────────────▼──────────────────────┐
│         Interface Layer             │
│   CLI · MCP · HTTP · Schema Export  │
└─────────────────────────────────────┘

Provider Layer

Sources tool definitions from decorated functions (LocalProvider) or external modules (FileSystemProvider). Extensible via the Provider abstract base class.

Transform Pipeline Layer

Modifies the tool surface before exposure: adds namespace prefixes, filters by visibility tags, selects tool versions. Transforms are composable via app.with_transforms().

Interface Layer

Exposes tools through multiple interfaces, all generated from the same source of truth:

  • CLI: Typer/Click command line interface with Rich output
  • MCP: Model Context Protocol server over stdio or HTTP
  • HTTP: OpenAPI-described REST API (optional)
  • Schema Export: JSON Schema for agent discoverability

Dual Pipeline

Python type annotations
        │
        ├──→ Click/Typer pipeline → CLI params, help text, validation
        │
        └──→ Pydantic pipeline → JSON Schema, MCP inputSchema, OpenAPI

Type annotations drive both pipelines simultaneously. Annotated[str, Argument(help="Name")] produces a CLI argument with help text AND a JSON Schema property with a description.

Key Classes

Class Module Role
Tooli tooli/app.py Main app class, extends typer.Typer
TooliCommand tooli/command.py Custom Click command that captures return values
ToolError tooli/errors.py Base exception with structured error output
OutputMode tooli/output.py Enum for output format selection
Envelope tooli/envelope.py Pydantic model for JSON output wrapper
ToolContext tooli/command.py Dataclass carrying global flag values
ExecutionContext tooli/detect.py Frozen dataclass with caller detection results
CallerCategory tooli/detect.py Enum: human, ai_agent, ci_cd, container, unknown_automation
TooliResult tooli/python_api.py Frozen generic dataclass for Python API call/stream results
TooliError tooli/python_api.py Frozen dataclass for structured error results in Python API

Output Flow

Command function returns value
        │
        ▼
TooliCommand.invoke() captures return value
        │
        ▼
Resolve OutputMode (flag > env > TTY detection > default)
        │
        ├── AUTO/TTY → rich.print(value)
        ├── JSON → Envelope(ok=True, result=value, meta=...) → json.dumps → stdout
        ├── JSONL → One envelope per item for lists → stdout
        └── TEXT/PLAIN → str(value) → stdout

Error Flow

Command raises exception
        │
        ├── ToolError → structured error envelope → mapped exit code
        ├── click.UsageError → exit code 2
        └── Other → wrap as InternalError → exit code 70

Configuration Precedence

Highest priority
    │
    ├── CLI flags (--output json, --quiet, etc.)
    ├── Environment variables (TOOLI_OUTPUT, TOOLI_VERBOSE)
    ├── .env file (project root)
    ├── pyproject.toml [tool.tooli] section
    ├── User config (~/.config/tooli/config.yaml)
    ├── System config
    └── Defaults

Clone this wiki locally