Repository navigation
Architecture
Brian Weisberg edited this page Feb 17, 2026
·
3 revisions
Tooli uses a three-layer architecture with a dual pipeline for parameter resolution.
┌─────────────────────────────────────┐
│ Provider Layer │
│ LocalProvider · FileSystemProvider │
└──────────────┬──────────────────────┘
│ list[ToolDef]
┌──────────────▼──────────────────────┐
│ Transform Pipeline Layer │
│ Namespace · Visibility · Version │
└──────────────┬──────────────────────┘
│ list[ToolDef]
┌──────────────▼──────────────────────┐
│ Interface Layer │
│ CLI · MCP · HTTP · Schema Export │
└─────────────────────────────────────┘
Sources tool definitions from decorated functions (LocalProvider) or external modules (FileSystemProvider). Extensible via the Provider abstract base class.
Modifies the tool surface before exposure: adds namespace prefixes, filters by visibility tags, selects tool versions. Transforms are composable via app.with_transforms().
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
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.
| 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 |
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
Command raises exception
│
├── ToolError → structured error envelope → mapped exit code
├── click.UsageError → exit code 2
└── Other → wrap as InternalError → exit code 70
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