Skip to main content
The assembled TaiApp facade. One Protocol per feature (see tai42_contract.app.facets), composed into a single TaiApp protocol that exposes them as namespaces (app.tools, app.agents, …). The app members are partitioned across the sub-protocols — each lives in exactly one, save the shared leaf names store (versioning + presets) and register/get (webhook_verifiers + channels). The runtime forwarding handle is tai42_app (see tai42_contract.app.handle).

AppAdmin

tai42_contract.app.facets.AppAdmin
Attributes

Members

reload_mcp

tai42_contract.app.facets.AppAdmin.reload_mcp
Parameters

deregister_mcp

tai42_contract.app.facets.AppAdmin.deregister_mcp
Parameters

reload_config

tai42_contract.app.facets.AppAdmin.reload_config

tool_reloader

tai42_contract.app.facets.AppAdmin.tool_reloader
Register an async (action, name) -> dict reloader for kind. Parameters

run_tool_reload

tai42_contract.app.facets.AppAdmin.run_tool_reload
Parameters

reload_failed_mcps

tai42_contract.app.facets.AppAdmin.reload_failed_mcps

list_failed_mcps

tai42_contract.app.facets.AppAdmin.list_failed_mcps

live_mcp_status

tai42_contract.app.facets.AppAdmin.live_mcp_status
Snapshot the in-process MCP-binding state.

AppAgents

tai42_contract.app.facets.AppAgents

Members

agent

tai42_contract.app.facets.AppAgents.agent
Register an Agent subclass under name and auto-register its JSON run tool. tags are the run tool’s native tags, set on its constructed tool object. The decorator returns the class unchanged, so the decorated symbol keeps its concrete subclass type. Parameters

get_agent

tai42_contract.app.facets.AppAgents.get_agent
Fetch a registered agent instance by name; raise if missing. Parameters

all_agents

tai42_contract.app.facets.AppAgents.all_agents
Every registered agent keyed by registration name (a shallow copy, so a caller iterating it cannot mutate the live registry). The preset bind kernel reads the keys to detect an agent base (the run tool binds under the registration name).

AppBackends

tai42_contract.app.facets.AppBackends
Attributes

Members

register_backend

tai42_contract.app.facets.AppBackends.register_backend

AppBackup

tai42_contract.app.facets.AppBackup
Registry for named backup sections and the run of one section’s export/import. A plugin (or the host itself, the first consumer) registers a section under name by supplying an exporter() that returns a JSON-safe payload and an importer(payload) that applies it and returns a section report. sections() lists the registered sections for the UI. export_section / import_section run one section’s exporter/importer by name and raise loudly on an unknown name — never a silent no-op.

Members

register_section

tai42_contract.app.facets.AppBackup.register_section
Parameters

sections

tai42_contract.app.facets.AppBackup.sections

export_section

tai42_contract.app.facets.AppBackup.export_section
Parameters

import_section

tai42_contract.app.facets.AppBackup.import_section
Parameters

AppChannels

tai42_contract.app.facets.AppChannels

Members

register

tai42_contract.app.facets.AppChannels.register
Register a Channel under name. A channel plugin calls this through the tai42_app handle when its import-only channel_modules entry loads. Registering a name already taken raises loudly — a silent overwrite could swap the medium a live ask is delivered on. Parameters

get

tai42_contract.app.facets.AppChannels.get
Fetch a registered channel by name; raise loudly on an unknown name. Resolution happens when ask_user is called with channel=name, BEFORE any interaction state is written, so an unknown name surfaces as a loud failure, never a question silently delivered nowhere. Parameters

names

tai42_contract.app.facets.AppChannels.names
Every registered channel name, for the channels catalog route.

AppClients

tai42_contract.app.facets.AppClients

Members

client_ctx

tai42_contract.app.facets.AppClients.client_ctx
Async context manager yielding a connected client, pooled per loop + connection params (or one-shot when fresh=True). settings is a kit ClientSettings whose client_kwargs() supplies the connection key. Parameters

shutdown_clients

tai42_contract.app.facets.AppClients.shutdown_clients
Close every live client pool for the running loop.

AppConfig

tai42_contract.app.facets.AppConfig
Attributes

AppConnectors

tai42_contract.app.facets.AppConnectors

Members

register_connector

tai42_contract.app.facets.AppConnectors.register_connector
Register an OAuth connector provider from its pure descriptor data. A provider plugin calls this through the tai42_app handle when the manifest loads it (a connector is pure data, so this is a plain call, not a decorator). Parameters

token_store

tai42_contract.app.facets.AppConnectors.token_store
The connector token store (single-namespace, keyed by connection_id).

AppConversations

tai42_contract.app.facets.AppConversations
The conversation bridge’s entry surface for medium adapters: inbound messages via accept, out-of-band delivery receipts via record_delivery_status. Routing-row CRUD, the turn engine and the API door are not part of this facet.

Members

accept

tai42_contract.app.facets.AppConversations.accept
Accept one inbound channel message, persist it, and return its message_id (a uuid4). Routed to the door=channel route matching (channel, our_identity); the turn runs as that route’s execution key and answers back over the same channel. Idempotent on (channel, provider_message_id) — a redelivery returns the existing message_id and starts no second turn. Raises when no route matches. Parameters

record_delivery_status

tai42_contract.app.facets.AppConversations.record_delivery_status
Ingest a channel’s out-of-band delivery receipt for an outbound message. provider_message_id is one of the ids a prior notify returned, resolved to the answer record through the outbound-id reverse index. FAILED marks the record failed; DELIVERED confirms a provisional record. Raises when the id resolves to no record. Parameters

AppExtensions

tai42_contract.app.facets.AppExtensions

Members

extension

tai42_contract.app.facets.AppExtensions.extension
Register a tool-extension factory under name (default: the function’s own name); usable bare or with arguments. requires_body_locality marks an extension whose wrapper only works in the process running the tool body it wraps — e.g. a proxy layer that routes the body’s egress through a task-scoped contextvar, visible only where the body executes. The flag is stored as registration metadata the apply site reads to order a stacked combo: a locality-requiring extension must bind INSIDE any execution-relocating extension (ExtensionKind.relocates_execution), so its wrapper travels with the body to the worker. Bound outside a relocating layer, the wrapper stays behind in the submitting process and silently does not apply. Parameters

available_extensions

tai42_contract.app.facets.AppExtensions.available_extensions
List registered extension modules as [{"name", "kind"}].

AppHttp

tai42_contract.app.facets.AppHttp

Members

middleware

tai42_contract.app.facets.AppHttp.middleware
Parameters

custom_route

tai42_contract.app.facets.AppHttp.custom_route
Register a Starlette handler AND its self-describing route metadata. The metadata is the single source of truth the OpenAPI 3.1 emitter and its coverage gate consume, so every registration MUST describe itself:
  • summary — a one-line operation summary (required, non-empty).
  • tags — at least one OpenAPI tag grouping the route (required).
  • response_model — the pydantic model wrapped in the {"data": ...} success envelope, or None as the explicit opaque marker for a route with no structured response. Required — there is no default, so a route cannot silently omit it.
  • request_model — the pydantic model of the request body; required for any route that reads a body, omitted (None) otherwise.
  • authed — whether the route requires the api key (default True); emitted as the security requirement.
  • destructive — whether the route mutates in a way flagged as destructive (default False); emitted as x-destructive.
  • action — the route’s authorization character (a RouteAction); None (the default) lets the surface derive the grantable class from the HTTP methods.
  • declared — the route’s behavioral OpenAPI properties (a DeclaredRouteMetadata): its reload_gated / reads_body / error statuses / success status. A route in the /api/* spec surface declares these (the operations adapter passes its operation’s metadata, a native handler passes its own); None (the default) records trivial defaults for a route outside the spec surface, whose behavioral metadata is never emitted.
The handler’s narrative docstring becomes the operation description, and the reload-gate 503 response is derived from the handler body. Parameters

AppLifecycle

tai42_contract.app.facets.AppLifecycle

Members

on_startup

tai42_contract.app.facets.AppLifecycle.on_startup
Parameters

on_shutdown

tai42_contract.app.facets.AppLifecycle.on_shutdown
Parameters

on_reload

tai42_contract.app.facets.AppLifecycle.on_reload
Register a handler re-run after every in-place re-init (reload_config) — e.g. dynamic tool loaders that on_startup ran once. Parameters

on_fleet_op_applied

tai42_contract.app.facets.AppLifecycle.on_fleet_op_applied
Register a handler fired after any worker-bus op applies in this process, and after the reconnect self-resync reload. Unlike its zero-arg siblings, the handler takes ONE argument — the op name — so it can act on some ops and skip others (a query op carries no state change to react to). Parameters

wait_until_ready

tai42_contract.app.facets.AppLifecycle.wait_until_ready
Block until this process’s first boot self-resync has completed — the point at which the tool registry is fully built and stable for the run. A backend runtime that forks a child (or otherwise consumes queued work) per job awaits this before its work loop accepts anything: the boot self-resync rebuilds the tool registry non-atomically, so a worker that dequeued and forked mid-rebuild would run the job against a half-built registry. The latch is one-way — it resolves once and stays resolved, so a later bus reconnect (which re-runs the self-resync while the app is already live) never un-readies the process.

AppMonitoring

tai42_contract.app.facets.AppMonitoring

Members

register_monitoring

tai42_contract.app.facets.AppMonitoring.register_monitoring
Parameters

active

tai42_contract.app.facets.AppMonitoring.active
The active monitoring backend (impl type behind the contract protocol).

AppPresets

tai42_contract.app.facets.AppPresets
The presets namespace (app.presets) — the typed view + the bind kernel. store is the PresetStore-typed view over app.versioning.store (kind="preset"). bind is the kernel BOTH tiers (ephemeral and versioned) build their live tool through, so its typed-schema behavior reaches both. Attributes

Members

bind

tai42_contract.app.facets.AppPresets.bind
Return a FastMCP tool transform of base_tool as a new named tool. Built in ONE Tool.from_tool call: each fixed_kwargs key is baked as a HIDDEN, FIXED constant (removed from the exposed schema; a caller that passes it is rejected — it cannot be overridden at runtime) while the REMAINING arguments keep the base tool’s real typed schema (names, types, descriptions). tags sets the transformed tool’s native tags. An output_schema (an object JSON Schema) is baked into an agent base’s response_format (forcing structured output) or advertised + validated on a plain tool base. bind is async because it must resolve the base Tool object (via app.tools.get_tool(base_tool)) to feed the transform. Parameters

AppStorage

tai42_contract.app.facets.AppStorage

Members

register_storage

tai42_contract.app.facets.AppStorage.register_storage

resource_manager

tai42_contract.app.facets.AppStorage.resource_manager
The active resource manager (impl type; loads/renders content over storage).

AppSubApp

tai42_contract.app.facets.AppSubApp
Attributes

AppTools

tai42_contract.tools.AppTools
Tool + toolkit registration / lookup surface.

Members

tool_title

tai42_contract.tools.AppTools.tool_title
Parameters

get_tool

tai42_contract.tools.AppTools.get_tool
Parameters

get_tools

tai42_contract.tools.AppTools.get_tools

get_client_tools

tai42_contract.tools.AppTools.get_client_tools
Parameters

run_tool

tai42_contract.tools.AppTools.run_tool
Parameters

remove_tool

tai42_contract.tools.AppTools.remove_tool
Parameters

register_tool_info

tai42_contract.tools.AppTools.register_tool_info
Parameters

unregister_tool_info

tai42_contract.tools.AppTools.unregister_tool_info
Parameters

unregister_tool_base

tai42_contract.tools.AppTools.unregister_tool_base
Parameters

AppVersioning

tai42_contract.app.facets.AppVersioning
The generic versioned-document store namespace (app.versioning). This is the platform persistence primitive — append-only versions + an active pointer + rollback over an opaque JSONB body, discriminated by kind. Direct consumers (e.g. AC policies under kind="ac_policy") reach it here; presets reach it through AppPresets, never as a new kind. Attributes

AppWebhookVerifiers

tai42_contract.app.facets.AppWebhookVerifiers

Members

register

tai42_contract.app.facets.AppWebhookVerifiers.register
Register a WebhookVerifier under name. A provider plugin calls this through the tai42_app handle when its import-only webhook_verifier_modules entry loads. Registering a name already taken raises loudly — a silent overwrite could swap a topic’s verifier out from under a live binding. Parameters

get

tai42_contract.app.facets.AppWebhookVerifiers.get
Fetch a registered verifier by name; raise loudly on an unknown name. Resolution happens when a verifier is bound to a public webhook door, so an unknown name surfaces at bind time as a loud failure, never a silently-unverified door. Parameters

DeclaredRouteMetadata

tai42_contract.app.facets.DeclaredRouteMetadata
The behavioral OpenAPI properties a route DECLARES. A route registered through the operations adapter supplies this from its operation’s metadata + declared error classes; a native /api/* handler passes it explicitly at its custom_route registration. Its reload_gated / reads_body / error statuses / success status feed the emitted spec and the coverage/parity gates. additional_success_statuses names further 2xx codes one method may answer besides success_status; each is emitted as its own success response. Attributes

RouteAction

tai42_contract.app.facets.RouteAction

TaiApp

tai42_contract.app.TaiApp
The assembled facade — per-feature sub-protocols exposed as namespaces. Attributes

tai42_app

tai42_contract.app.tai42_app

RouteAction

tai42_contract.app.facets.RouteAction

DeclaredRouteMetadata

tai42_contract.app.facets.DeclaredRouteMetadata
The behavioral OpenAPI properties a route DECLARES. A route registered through the operations adapter supplies this from its operation’s metadata + declared error classes; a native /api/* handler passes it explicitly at its custom_route registration. Its reload_gated / reads_body / error statuses / success status feed the emitted spec and the coverage/parity gates. additional_success_statuses names further 2xx codes one method may answer besides success_status; each is emitted as its own success response. Attributes

AppAgents

tai42_contract.app.facets.AppAgents

Members

agent

tai42_contract.app.facets.AppAgents.agent
Register an Agent subclass under name and auto-register its JSON run tool. tags are the run tool’s native tags, set on its constructed tool object. The decorator returns the class unchanged, so the decorated symbol keeps its concrete subclass type. Parameters

get_agent

tai42_contract.app.facets.AppAgents.get_agent
Fetch a registered agent instance by name; raise if missing. Parameters

all_agents

tai42_contract.app.facets.AppAgents.all_agents
Every registered agent keyed by registration name (a shallow copy, so a caller iterating it cannot mutate the live registry). The preset bind kernel reads the keys to detect an agent base (the run tool binds under the registration name).

AppBackends

tai42_contract.app.facets.AppBackends
Attributes

Members

register_backend

tai42_contract.app.facets.AppBackends.register_backend

AppStorage

tai42_contract.app.facets.AppStorage

Members

register_storage

tai42_contract.app.facets.AppStorage.register_storage

resource_manager

tai42_contract.app.facets.AppStorage.resource_manager
The active resource manager (impl type; loads/renders content over storage).

AppMonitoring

tai42_contract.app.facets.AppMonitoring

Members

register_monitoring

tai42_contract.app.facets.AppMonitoring.register_monitoring
Parameters

active

tai42_contract.app.facets.AppMonitoring.active
The active monitoring backend (impl type behind the contract protocol).

AppExtensions

tai42_contract.app.facets.AppExtensions

Members

extension

tai42_contract.app.facets.AppExtensions.extension
Register a tool-extension factory under name (default: the function’s own name); usable bare or with arguments. requires_body_locality marks an extension whose wrapper only works in the process running the tool body it wraps — e.g. a proxy layer that routes the body’s egress through a task-scoped contextvar, visible only where the body executes. The flag is stored as registration metadata the apply site reads to order a stacked combo: a locality-requiring extension must bind INSIDE any execution-relocating extension (ExtensionKind.relocates_execution), so its wrapper travels with the body to the worker. Bound outside a relocating layer, the wrapper stays behind in the submitting process and silently does not apply. Parameters

available_extensions

tai42_contract.app.facets.AppExtensions.available_extensions
List registered extension modules as [{"name", "kind"}].

AppWebhookVerifiers

tai42_contract.app.facets.AppWebhookVerifiers

Members

register

tai42_contract.app.facets.AppWebhookVerifiers.register
Register a WebhookVerifier under name. A provider plugin calls this through the tai42_app handle when its import-only webhook_verifier_modules entry loads. Registering a name already taken raises loudly — a silent overwrite could swap a topic’s verifier out from under a live binding. Parameters

get

tai42_contract.app.facets.AppWebhookVerifiers.get
Fetch a registered verifier by name; raise loudly on an unknown name. Resolution happens when a verifier is bound to a public webhook door, so an unknown name surfaces at bind time as a loud failure, never a silently-unverified door. Parameters

AppChannels

tai42_contract.app.facets.AppChannels

Members

register

tai42_contract.app.facets.AppChannels.register
Register a Channel under name. A channel plugin calls this through the tai42_app handle when its import-only channel_modules entry loads. Registering a name already taken raises loudly — a silent overwrite could swap the medium a live ask is delivered on. Parameters

get

tai42_contract.app.facets.AppChannels.get
Fetch a registered channel by name; raise loudly on an unknown name. Resolution happens when ask_user is called with channel=name, BEFORE any interaction state is written, so an unknown name surfaces as a loud failure, never a question silently delivered nowhere. Parameters

names

tai42_contract.app.facets.AppChannels.names
Every registered channel name, for the channels catalog route.

AppConversations

tai42_contract.app.facets.AppConversations
The conversation bridge’s entry surface for medium adapters: inbound messages via accept, out-of-band delivery receipts via record_delivery_status. Routing-row CRUD, the turn engine and the API door are not part of this facet.

Members

accept

tai42_contract.app.facets.AppConversations.accept
Accept one inbound channel message, persist it, and return its message_id (a uuid4). Routed to the door=channel route matching (channel, our_identity); the turn runs as that route’s execution key and answers back over the same channel. Idempotent on (channel, provider_message_id) — a redelivery returns the existing message_id and starts no second turn. Raises when no route matches. Parameters

record_delivery_status

tai42_contract.app.facets.AppConversations.record_delivery_status
Ingest a channel’s out-of-band delivery receipt for an outbound message. provider_message_id is one of the ids a prior notify returned, resolved to the answer record through the outbound-id reverse index. FAILED marks the record failed; DELIVERED confirms a provisional record. Raises when the id resolves to no record. Parameters

AppConnectors

tai42_contract.app.facets.AppConnectors

Members

register_connector

tai42_contract.app.facets.AppConnectors.register_connector
Register an OAuth connector provider from its pure descriptor data. A provider plugin calls this through the tai42_app handle when the manifest loads it (a connector is pure data, so this is a plain call, not a decorator). Parameters

token_store

tai42_contract.app.facets.AppConnectors.token_store
The connector token store (single-namespace, keyed by connection_id).

AppHttp

tai42_contract.app.facets.AppHttp

Members

middleware

tai42_contract.app.facets.AppHttp.middleware
Parameters

custom_route

tai42_contract.app.facets.AppHttp.custom_route
Register a Starlette handler AND its self-describing route metadata. The metadata is the single source of truth the OpenAPI 3.1 emitter and its coverage gate consume, so every registration MUST describe itself:
  • summary — a one-line operation summary (required, non-empty).
  • tags — at least one OpenAPI tag grouping the route (required).
  • response_model — the pydantic model wrapped in the {"data": ...} success envelope, or None as the explicit opaque marker for a route with no structured response. Required — there is no default, so a route cannot silently omit it.
  • request_model — the pydantic model of the request body; required for any route that reads a body, omitted (None) otherwise.
  • authed — whether the route requires the api key (default True); emitted as the security requirement.
  • destructive — whether the route mutates in a way flagged as destructive (default False); emitted as x-destructive.
  • action — the route’s authorization character (a RouteAction); None (the default) lets the surface derive the grantable class from the HTTP methods.
  • declared — the route’s behavioral OpenAPI properties (a DeclaredRouteMetadata): its reload_gated / reads_body / error statuses / success status. A route in the /api/* spec surface declares these (the operations adapter passes its operation’s metadata, a native handler passes its own); None (the default) records trivial defaults for a route outside the spec surface, whose behavioral metadata is never emitted.
The handler’s narrative docstring becomes the operation description, and the reload-gate 503 response is derived from the handler body. Parameters

AppClients

tai42_contract.app.facets.AppClients

Members

client_ctx

tai42_contract.app.facets.AppClients.client_ctx
Async context manager yielding a connected client, pooled per loop + connection params (or one-shot when fresh=True). settings is a kit ClientSettings whose client_kwargs() supplies the connection key. Parameters

shutdown_clients

tai42_contract.app.facets.AppClients.shutdown_clients
Close every live client pool for the running loop.

AppLifecycle

tai42_contract.app.facets.AppLifecycle

Members

on_startup

tai42_contract.app.facets.AppLifecycle.on_startup
Parameters

on_shutdown

tai42_contract.app.facets.AppLifecycle.on_shutdown
Parameters

on_reload

tai42_contract.app.facets.AppLifecycle.on_reload
Register a handler re-run after every in-place re-init (reload_config) — e.g. dynamic tool loaders that on_startup ran once. Parameters

on_fleet_op_applied

tai42_contract.app.facets.AppLifecycle.on_fleet_op_applied
Register a handler fired after any worker-bus op applies in this process, and after the reconnect self-resync reload. Unlike its zero-arg siblings, the handler takes ONE argument — the op name — so it can act on some ops and skip others (a query op carries no state change to react to). Parameters

wait_until_ready

tai42_contract.app.facets.AppLifecycle.wait_until_ready
Block until this process’s first boot self-resync has completed — the point at which the tool registry is fully built and stable for the run. A backend runtime that forks a child (or otherwise consumes queued work) per job awaits this before its work loop accepts anything: the boot self-resync rebuilds the tool registry non-atomically, so a worker that dequeued and forked mid-rebuild would run the job against a half-built registry. The latch is one-way — it resolves once and stays resolved, so a later bus reconnect (which re-runs the self-resync while the app is already live) never un-readies the process.

AppAdmin

tai42_contract.app.facets.AppAdmin
Attributes

Members

reload_mcp

tai42_contract.app.facets.AppAdmin.reload_mcp
Parameters

deregister_mcp

tai42_contract.app.facets.AppAdmin.deregister_mcp
Parameters

reload_config

tai42_contract.app.facets.AppAdmin.reload_config

tool_reloader

tai42_contract.app.facets.AppAdmin.tool_reloader
Register an async (action, name) -> dict reloader for kind. Parameters

run_tool_reload

tai42_contract.app.facets.AppAdmin.run_tool_reload
Parameters

reload_failed_mcps

tai42_contract.app.facets.AppAdmin.reload_failed_mcps

list_failed_mcps

tai42_contract.app.facets.AppAdmin.list_failed_mcps

live_mcp_status

tai42_contract.app.facets.AppAdmin.live_mcp_status
Snapshot the in-process MCP-binding state.

AppConfig

tai42_contract.app.facets.AppConfig
Attributes

AppBackup

tai42_contract.app.facets.AppBackup
Registry for named backup sections and the run of one section’s export/import. A plugin (or the host itself, the first consumer) registers a section under name by supplying an exporter() that returns a JSON-safe payload and an importer(payload) that applies it and returns a section report. sections() lists the registered sections for the UI. export_section / import_section run one section’s exporter/importer by name and raise loudly on an unknown name — never a silent no-op.

Members

register_section

tai42_contract.app.facets.AppBackup.register_section
Parameters

sections

tai42_contract.app.facets.AppBackup.sections

export_section

tai42_contract.app.facets.AppBackup.export_section
Parameters

import_section

tai42_contract.app.facets.AppBackup.import_section
Parameters

AppSubApp

tai42_contract.app.facets.AppSubApp
Attributes

AppVersioning

tai42_contract.app.facets.AppVersioning
The generic versioned-document store namespace (app.versioning). This is the platform persistence primitive — append-only versions + an active pointer + rollback over an opaque JSONB body, discriminated by kind. Direct consumers (e.g. AC policies under kind="ac_policy") reach it here; presets reach it through AppPresets, never as a new kind. Attributes

AppPresets

tai42_contract.app.facets.AppPresets
The presets namespace (app.presets) — the typed view + the bind kernel. store is the PresetStore-typed view over app.versioning.store (kind="preset"). bind is the kernel BOTH tiers (ephemeral and versioned) build their live tool through, so its typed-schema behavior reaches both. Attributes

Members

bind

tai42_contract.app.facets.AppPresets.bind
Return a FastMCP tool transform of base_tool as a new named tool. Built in ONE Tool.from_tool call: each fixed_kwargs key is baked as a HIDDEN, FIXED constant (removed from the exposed schema; a caller that passes it is rejected — it cannot be overridden at runtime) while the REMAINING arguments keep the base tool’s real typed schema (names, types, descriptions). tags sets the transformed tool’s native tags. An output_schema (an object JSON Schema) is baked into an agent base’s response_format (forcing structured output) or advertised + validated on a plain tool base. bind is async because it must resolve the base Tool object (via app.tools.get_tool(base_tool)) to feed the transform. Parameters