> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tai42.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Author a tool

> Build a tool plugin.

Author a tool plugin — a package of tools that registers through the contract handle and loads from a manifest.

A tool plugin is a package whose modules register tools through the `tai42_app` handle. It depends only on `tai42-contract` (and `tai42-kit` for shared helpers) — never on the skeleton — so it stays a pure, contract-facing package the host loads from the manifest. The reference implementation is [`tai42-toolbox`](https://github.com/tai42ai/tai-toolbox), the ecosystem's contrib tool set.

## Register through the handle

Decorate each function with `@tai42_app.tools.tool`. The function's signature becomes the input schema and its docstring the description. Keep one tool per module so a manifest can enable them one at a time.

```python examples/tool/forecast_tool.py theme={null}
"""A minimal fictional tool: a weather forecast lookup.

Registers one tool through the ``tai42_app`` handle. The function signature becomes
the input schema and the docstring becomes the description.
"""

from tai42_contract.app import tai42_app


@tai42_app.tools.tool
def get_forecast(city: str, days: int = 1) -> dict[str, object]:
    """Return a short weather forecast for a city.

    ``city`` names the place to look up; ``days`` is how many days ahead to
    report. The return value's shape becomes the tool's output schema.
    """
    return {
        "city": city,
        "days": days,
        "summary": "clear",
        "high_c": 21,
    }
```

An async tool works the same way — the runtime awaits it. A tool that returns a structured object returns a `dict` (or a pydantic model), and its return annotation becomes the output schema.

## Gate heavy dependencies

Keep the base install light. Gate a module that needs a heavy dependency behind an optional extra, and fail loudly at import if the extra is missing — never a silent skip. Gate an HTTP tool behind an `[http]` extra, for example, and have the module raise an `install <package>[http]` hint at import when the extra is absent.

## Package layout

* Ship each tool in its own module under your package (`your_package.tools.<name>`).
* Depend on `tai42-contract` only (plus `tai42-kit` for shared clients or helpers).
* Never import the skeleton — a tool plugin is contract-facing.
* Type the package (`py.typed`) and keep the type-checker clean.

## Load it

The host enables a tool module by naming it under `tools[].module`:

```yaml manifest.yml theme={null}
tools:
  - title: weather
    module: your_package.tools.forecast
```

See [Build a tool](/guides/build-a-tool) for the loading and run flow end to end.

## Shipped implementations

* [`tai42-toolbox`](https://github.com/tai42ai/tai-toolbox) — the reference tool set (utility, HTTP, and embedding tools).

## See also

* [Tools and extensions](/concepts/tools-and-extensions) — the tool model.
* [The standard toolbox](/guides/standard-toolbox) — using the shipped tool set.
* [Python SDK reference](/reference/python-sdk) — the `tai42_app.tools` surface.
* [Ecosystem catalog](/reference/catalog) — every shipped tool.
