> ## 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.

# Plugins (tai42_contract.plugins)

> The PluginSpec model behind tai-plugin.yml.

Plugin manifest contract: the `tai-plugin.yml` schema (`PluginSpec`).

Every installable TAI plugin ships a `tai-plugin.yml` — at its repo root and
as package-data inside the built wheel. The file names the listing
(`namespace/name`), the pip distribution that backs it, the tai42-contract
compatibility range, declared capabilities, and the item-level `provides`
index: one entry per tool/agent/extension/... the package registers, because
items are what users search for while the plugin is what gets installed.

The models here are the one schema shared by the marketplace registry's
validator, the skeleton's installer, and each plugin repo's own spec test.
The YAML I/O helpers live above the contract (`tai42_kit.plugins`) — the
contract itself has no YAML dependency.

`KIND_MANIFEST_BINDINGS` is the single source for how each provided item
kind wires into a `Manifest`: which manifest
field an installer patches and with what shape (a config row, a module-list
entry, a single-module slot, a package-name entry, or no manifest field at
all for the env-selected `config` kind).

Version strings are validated as PEP 440 (an anchored regex of the spec's
canonical pattern) and `contract` as a PEP 440 specifier set — shape-level
parseability only; evaluating whether a version satisfies a range is the
consumer's concern.

`display_name` and `icon` are the optional marketplace display metadata: a
human UI title (the UI titleizes `name` when absent) and either a packaged
image path relative to the package root or an `https` URL (the UI falls back
to a generated monogram when absent).

## KIND\_MANIFEST\_BINDINGS

`tai42_contract.plugins.KIND_MANIFEST_BINDINGS`

```python theme={null}
KIND_MANIFEST_BINDINGS: Mapping[PluginItemKind, ManifestBinding] = MappingProxyType({PluginItemKind.TOOL: ManifestBinding(field='tools', mode='config_row'), PluginItemKind.AGENT: ManifestBinding(field='agents', mode='config_row'), PluginItemKind.EXTENSION: ManifestBinding(field='extensions_modules', mode='module_list'), PluginItemKind.CONNECTOR: ManifestBinding(field='lifecycle_modules', mode='module_list'), PluginItemKind.CHANNEL: ManifestBinding(field='channel_modules', mode='module_list'), PluginItemKind.BACKEND: ManifestBinding(field='backend_module', mode='scalar_module'), PluginItemKind.STORAGE: ManifestBinding(field='storage_module', mode='scalar_module'), PluginItemKind.MONITORING: ManifestBinding(field='monitoring_module', mode='scalar_module'), PluginItemKind.WEBHOOK_VERIFIER: ManifestBinding(field='webhook_verifier_modules', mode='module_list'), PluginItemKind.CONFIG: ManifestBinding(field=None, mode='env_selected'), PluginItemKind.IDENTITY: ManifestBinding(field='lifecycle_modules', mode='module_list'), PluginItemKind.STUDIO_PLUGIN: ManifestBinding(field='studio_plugins', mode='package_list'), PluginItemKind.ROUTER: ManifestBinding(field='routers_modules', mode='module_list'), PluginItemKind.MIDDLEWARE: ManifestBinding(field='middlewares_modules', mode='module_list')})
```

## ManifestBinding

`tai42_contract.plugins.ManifestBinding`

```python theme={null}
class ManifestBinding(BaseModel)
```

How one provided item kind wires into a `Manifest`.

`field` names the manifest field an installer patches for an item of
this kind; `mode` is the patch shape:

* `config_row` — append a config row (`tools`/`agents`) whose
  `module` is the item's module.
* `module_list` — append the item's module to a plain module list.
* `scalar_module` — set a single-module slot; the slot holds ONE module,
  so a second plugin claiming an occupied slot is a conflict the caller
  must reject loudly.
* `package_list` — append the plugin's DISTRIBUTION name (not the item's
  module) to a package list (`studio_plugins`).
* `env_selected` — no manifest field: the kind is selected through the
  environment (a `config` provider is named by `TAI_CONFIG_MODE` and
  imported by the config seam), so `field` is `None`.

**Attributes**

| Attribute      | Type                                                                                    |
| -------------- | --------------------------------------------------------------------------------------- |
| `model_config` | —                                                                                       |
| `field`        | `str \| None`                                                                           |
| `mode`         | `Literal['config_row', 'module_list', 'scalar_module', 'package_list', 'env_selected']` |

## PluginItem

`tai42_contract.plugins.PluginItem`

```python theme={null}
class PluginItem(BaseModel)
```

One installable item in a plugin's `provides` index.

`module` is the import path whose import side-effect registers the item
(or, for env-selected kinds, the module the selecting seam imports); the
installer patches it into the manifest per `KIND_MANIFEST_BINDINGS`.

**Attributes**

| Attribute      | Type             |
| -------------- | ---------------- |
| `model_config` | —                |
| `kind`         | `PluginItemKind` |
| `name`         | `str`            |
| `module`       | `str`            |
| `description`  | `str`            |
| `tags`         | `list[str]`      |

## PluginItemKind

`tai42_contract.plugins.PluginItemKind`

```python theme={null}
class PluginItemKind(StrEnum)
```

Kind of one installable item a plugin provides.

The values are the ecosystem's item-kind vocabulary (the same words the
catalog and the marketplace facets use). `KIND_MANIFEST_BINDINGS` maps
every member onto its manifest wiring; an unknown kind in a spec is a
loud validation reject, never a skipped row.

**Attributes**

| Attribute          | Type |
| ------------------ | ---- |
| `TOOL`             | —    |
| `AGENT`            | —    |
| `EXTENSION`        | —    |
| `CONNECTOR`        | —    |
| `CHANNEL`          | —    |
| `BACKEND`          | —    |
| `STORAGE`          | —    |
| `MONITORING`       | —    |
| `WEBHOOK_VERIFIER` | —    |
| `CONFIG`           | —    |
| `IDENTITY`         | —    |
| `STUDIO_PLUGIN`    | —    |
| `ROUTER`           | —    |
| `MIDDLEWARE`       | —    |

## PluginPermissions

`tai42_contract.plugins.PluginPermissions`

```python theme={null}
class PluginPermissions(BaseModel)
```

Capabilities a plugin declares — informational: surfaced in listings,
not enforced by a sandbox.

Omitting the block declares none (every flag defaults to `False`); an
unknown key is rejected loudly rather than silently ignored.

**Attributes**

| Attribute      | Type   |
| -------------- | ------ |
| `model_config` | —      |
| `network`      | `bool` |
| `subprocess`   | `bool` |
| `filesystem`   | `bool` |

## PluginSpec

`tai42_contract.plugins.PluginSpec`

```python theme={null}
class PluginSpec(BaseModel)
```

The complete, validated content of one `tai-plugin.yml`.

Frozen and `extra="forbid"`: a typo'd key fails validation loudly. The
listing reference is `namespace/name` (`ref`); `package` is the
normalized pip distribution the listing points at; `version` must equal
the built wheel's version (each plugin repo's spec test and the registry's
ingest validation both pin that); `contract` is the tai42-contract
compatibility range as a PEP 440 specifier set. `display_name` and
`icon` are optional marketplace display metadata.

**Attributes**

| Attribute      | Type                |
| -------------- | ------------------- |
| `model_config` | —                   |
| `spec_version` | `Literal[1]`        |
| `namespace`    | `str`               |
| `name`         | `str`               |
| `display_name` | `str \| None`       |
| `package`      | `str`               |
| `version`      | `str`               |
| `description`  | `str`               |
| `icon`         | `str \| None`       |
| `license`      | `str`               |
| `homepage`     | `str \| None`       |
| `repository`   | `str \| None`       |
| `contract`     | `str`               |
| `categories`   | `list[str]`         |
| `tags`         | `list[str]`         |
| `permissions`  | `PluginPermissions` |
| `provides`     | `list[PluginItem]`  |

### Members

#### ref

`tai42_contract.plugins.PluginSpec.ref`

```python theme={null}
ref: str
```

The full listing reference, `namespace/name`.
