Python SDK overview
The Python SDK ships as the platools package (packages/platools-py in the monorepo). It targets Python 3.10+ and depends on Pydantic v2, docstring-parser, and websockets.
Public surface
Everything you need lives at the top level:
from platools import ( Platools, # the per-app instance (decorator + registry + client) PlatoolsClient, # advanced: manual WebSocket client ToolDef, # runtime tool descriptor (frozen dataclass) ToolSchema, # MCP-compliant schema dataclass AuthLevel, # Literal["none", "user", "admin"] SchemaError, # raised for missing type hints / bad signatures)All of these are declared in platools/__init__.py::__all__. Keep your imports at the top-level platools module so future refactors inside core/, transport/, etc. don’t break your code.
The Platools instance
from platools import Platools
platools = Platools( url="https://platform.example.com", # or $PLATOS_URL secret="platos_agent_...", # or $PLATOS_SECRET)Each Platools() owns its own ToolRegistry. Create one per backend process and import it from every module that defines tools:
from platools import Platoolsplatools = Platools()
# my_app/billing.pyfrom my_app.core import platools
@platools.tool()def list_invoices(customer_id: str) -> list[Invoice]: ...Properties you can read:
| Attribute | Type | Purpose |
|---|---|---|
platools.url | str | None | Platform base URL (constructor or $PLATOS_URL). |
platools.secret | str | None | JWT-bearing secret (constructor or $PLATOS_SECRET). |
platools.tool | decorator factory | @platools.tool(...) - see Decorator. |
platools.registry | ToolRegistry | Read-mostly. The doctor CLI walks this. |
platools.tools | dict[str, ToolDef] | Read-only snapshot keyed by tool name. |
platools.get_tool(name) | ToolDef | None | Convenience lookup. |
platools.get_mcp_schemas() | list[ToolSchema] | MCP-ready schemas for every tool. |
await platools.connect() | coroutine | Opens the outbound WebSocket. See Client. |
What happens when you decorate
The @platools.tool() decorator:
- Validates the options (
authin{none, user, admin},timeout > 0). - Builds the input schema via
platools.core.schema.build_input_schema(). A Pydantic model is created from the function’s type hints, docstring param descriptions feedField(description=...), andmodel_json_schema()produces the final dict. - Builds an output schema from the return annotation (if any).
- Creates a
ToolDefand registers it on the instance’sToolRegistry. Duplicate names raiseValueError. - Returns the original function unchanged. Decorated tools remain directly callable in user code. Unit tests don’t have to go through the registry.
See Decorator and Schemas for details.
SDK architecture
platools/├── __init__.py # Platools class + public exports├── types.py # AuthLevel, ToolDef, ToolSchema (frozen dataclasses)├── core/│ ├── decorator.py # @platools.tool() factory│ ├── registry.py # ToolRegistry (dict[str, ToolDef] wrapper)│ └── schema.py # type hints -> Pydantic model -> JSON Schema├── transport/│ ├── client.py # PlatoolsClient (WebSocket + heartbeat + backoff)│ └── protocol.py # wire messages (Pydantic models)├── serve/│ ├── dispatcher.py # JSON-RPC -> tool call dispatcher│ ├── http.py # stdlib-only HTTP/1.1 transport for platools serve│ └── stdio.py # stdio transport├── doctor/│ ├── analyzer.py # static analysis of a ToolRegistry│ ├── checks.py # individual lint rules│ └── reporter.py # human-readable / JSON output├── testing/│ ├── runner.py # ToolTestRunner + BatchResult + latency stats│ └── mock_client.py # in-process mock for unit tests└── cli/ ├── __init__.py # platools entrypoint ├── doctor.py # platools doctor ├── test.py # platools test └── serve.py # platools serve