Skip to main content
Plugin-spec loading: the YAML I/O for tai-plugin.yml. Every installable TAI plugin ships a tai-plugin.yml — at its repo root and as package-data inside the built wheel. The schema is tai42_contract.plugins.PluginSpec; these helpers do the YAML reading the pure contract cannot (the contract has no YAML dependency) and validate loudly. parse_plugin_spec is the shared low-level entry point — it validates spec content already in memory (bytes or str), and both loaders route through it. Because a spec may arrive as untrusted network input (an artifact fetched from a registry, a wheel of unknown provenance), parsing is hardened against resource-exhaustion and ambiguity attacks: content larger than MAX_PLUGIN_SPEC_BYTES is rejected before parsing; YAML anchors/aliases (the billion-laughs expansion vector) and duplicate mapping keys (silent last-value-wins) are rejected outright; deeply nested documents that exhaust the interpreter stack are caught. A flat tai-plugin.yml needs none of those constructs, so rejecting them costs nothing. Failure surface: content- and file-level problems (over-size input, missing file, non-UTF-8 bytes, unparseable YAML, anchors/aliases, duplicate keys, excessive nesting, a non-mapping document, a wheel with zero or several spec files, an unreadable archive) raise PluginSpecLoadError; schema violations inside a well-formed document propagate pydantic’s ValidationError, which already names every offending field. Nothing degrades silently.

MAX_DOCS_FILE_BYTES

tai42_kit.plugins.MAX_DOCS_FILE_BYTES

MAX_DOCS_TOTAL_BYTES

tai42_kit.plugins.MAX_DOCS_TOTAL_BYTES

MAX_PLUGIN_SPEC_BYTES

tai42_kit.plugins.MAX_PLUGIN_SPEC_BYTES

MDX_SAFE_COMPONENTS

tai42_kit.plugins.MDX_SAFE_COMPONENTS

PLUGIN_DOCS_DIRNAME

tai42_kit.plugins.PLUGIN_DOCS_DIRNAME

PLUGIN_DOCS_INDEX

tai42_kit.plugins.PLUGIN_DOCS_INDEX

PLUGIN_SPEC_FILENAME

tai42_kit.plugins.PLUGIN_SPEC_FILENAME

EnvRequirement

tai42_kit.plugins.EnvRequirement
One environment variable an installed plugin item requires. name is the variable name; secret marks a value the platform masks in views and profile snapshots. Secret-ness is a property of the requirement the spec DECLARES (an OAuth client secret), not of the marker grammar — a !ENV marker cannot know whether its value is sensitive, so marker-derived requirements are never secret here. Attributes

PluginDocsError

tai42_kit.plugins.PluginDocsError
Raised when a plugin’s in-wheel docs/ tree cannot be read or fails the canonical validation contract. Covers both the extraction family (missing tree, a traversing/absolute member, an over-ceiling or bomb member, an unreadable archive) and every validate_docs violation (set-shape, front matter, unresolvable reference, forbidden scheme, un-whitelisted mdx). Nothing degrades silently.

PluginSpecLoadError

tai42_kit.plugins.PluginSpecLoadError
Raised when a tai-plugin.yml cannot be located, read, or parsed. Covers the I/O and structural-safety failure family only; a well-formed YAML mapping that violates the schema raises pydantic’s ValidationError instead.

accepts_env

tai42_kit.plugins.accepts_env
Whether the installer offers an env-supply step for this spec. True iff any item carries at least one !ENV marker (required OR defaulted — an operator may override even a defaulted marker) or the spec has a non-empty required_env_for_spec. This is the installer’s env-acceptance and routing key. Parameters

load_plugin_spec

tai42_kit.plugins.load_plugin_spec
Load and validate the tai-plugin.yml at path. Raises PluginSpecLoadError for an unreadable or over-size file, non-UTF-8 bytes, invalid YAML, or a non-mapping document; pydantic ValidationError for schema violations. Never returns a partial or defaulted spec. The on-disk size is checked against MAX_PLUGIN_SPEC_BYTES via stat before any bytes are read, so a multi-gigabyte file is refused without being slurped into memory. The bytes are then handed to parse_plugin_spec, which enforces the byte cap and UTF-8 decode uniformly with the wheel and in-memory paths — so a non-UTF-8 file raises PluginSpecLoadError rather than escaping as UnicodeDecodeError. Parameters

parse_plugin_spec

tai42_kit.plugins.parse_plugin_spec
Parse and validate tai-plugin.yml content already in memory. The shared low-level entry point: load_plugin_spec and read_wheel_plugin_spec both route through it, and callers holding raw bytes (e.g. an artifact fetched over the network) validate through it directly. source names the content’s origin in error messages. Raises PluginSpecLoadError for over-size input, non-UTF-8 bytes, invalid YAML, anchors/aliases, duplicate keys, excessive nesting, or a non-mapping document; pydantic ValidationError for schema violations. Parameters

read_dir_docs

tai42_kit.plugins.read_dir_docs
Read the docs/ tree sitting beside tai-plugin.yml in a plugin dir. The on-disk counterpart of read_wheel_docs for a descriptor-only plugin (no wheel): returns {relative_path: bytes} for every file under <plugin_dir>/docs/, keyed from plugin_dir so keys begin docs/ (e.g. docs/index.mdx) exactly as the wheel reader keys them. The same ceilings apply: a member past MAX_DOCS_FILE_BYTES or a cumulative payload past MAX_DOCS_TOTAL_BYTES raises PluginDocsError. A missing docs/ directory, an empty one, or an unreadable file also raises PluginDocsError. Never returns a partial tree. Parameters

read_wheel_docs

tai42_kit.plugins.read_wheel_docs
Read the docs/ tree packaged beside tai-plugin.yml in the wheel. Returns {relative_path: bytes} for every file under the packaged docs/ directory, keyed from the spec’s package root so keys begin docs/ (e.g. docs/index.mdx). The wheel must contain exactly one tai-plugin.yml (as read_wheel_plugin_spec requires) with a docs/ directory beside it. Zero or several specs, a missing docs/ tree, a member escaping via .. or an absolute path, a member using a compression method other than stored/deflate, a member inflating past MAX_DOCS_FILE_BYTES, a cumulative payload past MAX_DOCS_TOTAL_BYTES, or an unreadable archive raise PluginDocsError. Never returns a partial tree. Decompression-bomb discipline mirrors read_wheel_plugin_spec: only ZIP_STORED/ZIP_DEFLATED members are read (CPython threads the length cap into the decompressor solely on the deflate path), the caps are enforced by BOUNDED streamed reads, and ZipInfo.file_size — attacker-controlled central-directory metadata — is never trusted. Parameters

read_wheel_plugin_spec

tai42_kit.plugins.read_wheel_plugin_spec
Read and validate the spec packaged inside the wheel at wheel_path. The wheel must contain exactly one tai-plugin.yml entry (shipped as package-data in the plugin’s import package); zero or several entries, an unreadable archive, a member using a compression method other than stored/deflate, an over-size or decompression-bomb member, invalid YAML, or a non-mapping document raise PluginSpecLoadError, and schema violations raise pydantic’s ValidationError. Only ZIP_STORED and ZIP_DEFLATED members are read: the bounded read that caps a decompression bomb relies on ZipExtFile threading the length cap into the decompressor, which CPython does only on the deflate path, so a ZIP_BZIP2/ZIP_LZMA member would inflate its whole block unbounded. The compression method is checked before any byte is read. Parameters

required_env

tai42_kit.plugins.required_env
The environment variables one item requires to install, in first-seen order. An mcp-server item requires each REQUIRED (no-default) !ENV marker var in its mcp block — deduped, secret=False (the marker cannot know). An oauth connector requires its client-credential pair (client_id_env non-secret, client_secret_env secret). A none connector requires nothing at install (its config_fields are supplied by the end user at connect time), and every other kind requires nothing. Parameters

required_env_for_spec

tai42_kit.plugins.required_env_for_spec
The ordered union of every item’s required_env, keyed by name. First-seen order across spec.provides is preserved; when the same var is required by two items with different secret-ness, secret=True wins (a value masked by any requirement stays masked). Parameters

validate_docs

tai42_kit.plugins.validate_docs
Validate a docs tree ({docs-relative-path: bytes}) against the canonical contract, raising PluginDocsError on the first violation. The one implementation every enforcement point shares (marketplace ingest, the monorepo CI gate, the docs-site generator); each caller owns the first_party policy. Enforced for EVERY namespace: the set shape (only .mdx pages under docs/ and raster images under docs/images/ — SVG and every other type refused, SVG being an XSS surface); a present docs/index.mdx; per-page front matter of exactly title + description, each a single-line plain string with no control characters or fence-breaking metacharacters; and relative link/image references that resolve within the set. When first_party is False, additionally: the mdx safe-whitelist (MDX_SAFE_COMPONENTS) and a link/image scheme of only http(s) or an in-set relative path — javascript:/data: refused. Parameters