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 + tool_meta) and register/get
(webhook_verifiers + channels). The runtime forwarding handle is
tai42_app (see tai42_contract.app.handle).
AppAccounts
tai42_contract.app.facets.integrations.AppAccounts
Members
active_provider
tai42_contract.app.facets.integrations.AppAccounts.active_provider
name, or None when none is active.
An AccountsProvider is an IdentityProvider. None means no provider is
active under that name — the name is not configured, or a build is mid-flight.
Parameters
AppAdmin
tai42_contract.app.facets.runtime.AppAdmin
Members
reload_mcp
tai42_contract.app.facets.runtime.AppAdmin.reload_mcp
title and return its status.
Parameters
deregister_mcp
tai42_contract.app.facets.runtime.AppAdmin.deregister_mcp
title and return its status.
Parameters
reload_config
tai42_contract.app.facets.runtime.AppAdmin.reload_config
tool_reloader
tai42_contract.app.facets.runtime.AppAdmin.tool_reloader
(action, name) -> dict reloader for kind.
Parameters
run_tool_reload
tai42_contract.app.facets.runtime.AppAdmin.run_tool_reload
kind reloader for action on name.
Parameters
reload_failed_mcps
tai42_contract.app.facets.runtime.AppAdmin.reload_failed_mcps
list_failed_mcps
tai42_contract.app.facets.runtime.AppAdmin.list_failed_mcps
live_mcp_status
tai42_contract.app.facets.runtime.AppAdmin.live_mcp_status
live_manifest
tai42_contract.app.facets.runtime.AppAdmin.live_manifest
AppAgents
tai42_contract.app.facets.execution.AppAgents
app.agents).
Members
agent
tai42_contract.app.facets.execution.AppAgents.agent
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.
meta is generic registration metadata threaded onto the same constructed
run-tool object (naming no consumer concept — a registrant attaches any generic
tai42/* key, e.g. a crash-resume flag the run-dispatch seam reads). The
decorator returns the class unchanged, so the decorated symbol keeps its
concrete subclass type.
Parameters
get_agent
tai42_contract.app.facets.execution.AppAgents.get_agent
all_agents
tai42_contract.app.facets.execution.AppAgents.all_agents
AppBackends
tai42_contract.app.facets.execution.AppBackends
app.backends).
Members
register_backend
tai42_contract.app.facets.execution.AppBackends.register_backend
Backend provider; usable bare or as a decorator factory.
backend
tai42_contract.app.facets.execution.AppBackends.backend
None when none is registered.
AppBackup
tai42_contract.app.facets.runtime.AppBackup
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.runtime.AppBackup.register_section
name.
Parameters
sections
tai42_contract.app.facets.runtime.AppBackup.sections
export_section
tai42_contract.app.facets.runtime.AppBackup.export_section
name and return its payload.
Parameters
import_section
tai42_contract.app.facets.runtime.AppBackup.import_section
payload via one section’s importer by name and return its report.
Parameters
AppChannels
tai42_contract.app.facets.messaging.AppChannels
app.channels) and inbound-answer ladder.
Members
register
tai42_contract.app.facets.messaging.AppChannels.register
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.messaging.AppChannels.get
ask 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.messaging.AppChannels.names
handle_inbound_answer
tai42_contract.app.facets.messaging.AppChannels.handle_inbound_answer
InboundAnswerResult: the outcome the channel maps to its
transport ack, plus the door’s retry_reason/retry_field when it rejected
the answer’s content, so a channel that owns its correction surface can render the
door’s specific message.
A channel computes its own opaque correlation_key for the participant’s address,
provides the answer value to forward to the door, its
CorrelationStore, and an InboundBridge of the
fields a bridged turn needs.
SEAM SYMMETRY (bridge.params ↔ answer params): the InboundBridge may carry opaque
channel enrichment in params — the answer-path counterpart of a conversation entry’s
params. The ladder threads it BOTH ways so enrichment is never dropped on either arm:
the answer is forwarded to the ask’s callback door as {"answer": answer, "params": params} (params present only when set), landing on
params for the asking flow
to read beside answer; and on the BRIDGE arm the same params are passed to
accept as its entry params. The ladder:
- No pending ask on the key ->
InboundAnswerOutcome.NO_CORRELATIONwith NO side effect: the CALLER bridges the reply as a normal turn (the ladder never bridges on a miss, exactly as each channel did by hand). - The door accepts (2xx) -> release the correlation, return
InboundAnswerOutcome.FORWARDED. - The door returns 404 (the ask was withdrawn/expired/cancelled) -> release,
bridge the reply as a fresh turn, return
InboundAnswerOutcome.BRIDGED. - The door returns 400 on a LIVE ask -> read the door’s
retry_in_place(default True): True keeps the correlation, notifies the participant what’s expected, fires ONE operator event, returnsInboundAnswerOutcome.RETRY_KEPT; False (a hard mismatch) releases, notifies the participant the question is closed, fires the event, bridges the reply, returnsInboundAnswerOutcome.BRIDGED. - Anything else (401/413/5xx, or a transport fault) -> do NOT release; raise
AnswerForwardErrorso the channel’s webhook redelivery re-runs the ladder. The answer is never silently lost.
InboundAnswerOutcome.NO_CORRELATION.
Parameters
record_send_receipt
tai42_contract.app.facets.messaging.AppChannels.record_send_receipt
notify_user send back onto its originating trace.
The send is a notify_user channel send with no conversation record. The tier-2
counterpart to the conversation bridge’s record_delivery_status: a
channel’s delivery-status webhook calls this when the bridge does not own the
outbound id (record_delivery_status raised LookupError). It resolves the id
through the TTL’d send-receipt index and, on a hit, emits a delivery_receipt event
into the recorded trace (a FAILED receipt at ERROR level), so the originating trace
shows delivered-vs-accepted for its sends. errors carries any provider error
detail for the event input.
Returns True when the id was a known send (event emitted), False when it
is not — so the webhook keeps its genuinely-unknown-id log only on a False. A
no-op returning False where the send-receipt store is unconfigured.
Parameters
AppClients
tai42_contract.app.facets.runtime.AppClients
Members
client_ctx
tai42_contract.app.facets.runtime.AppClients.client_ctx
fresh=True.
settings is a kit ClientSettings whose client_kwargs() supplies
the connection key.
Parameters
shutdown_clients
tai42_contract.app.facets.runtime.AppClients.shutdown_clients
AppConfig
tai42_contract.app.facets.runtime.AppConfig
Members
config_manager
tai42_contract.app.facets.runtime.AppConfig.config_manager
AppConnectors
tai42_contract.app.facets.integrations.AppConnectors
Members
register_connector
tai42_contract.app.facets.integrations.AppConnectors.register_connector
connectors entry at boot/reload, and by any
code holding the handle (a connector is pure data, so this is a plain call,
not a decorator).
Parameters
token_store
tai42_contract.app.facets.integrations.AppConnectors.token_store
connection_id).
resolve_connection_auth
tai42_contract.app.facets.integrations.AppConnectors.resolve_connection_auth
await it. Returns None when the connection injects nothing.
GUARANTEE (enforced by the skeleton implementation): (1) it RAISES a loud
constant-message error when NO execution identity is bound — the fail-close
raise fires as the awaited coroutine runs, BEFORE resolving, so an
identity-less door never gets creds injected; and
(2) connection_id is a REFERENCE supplied by operator settings, NEVER
session-supplied, so a session can neither reach an identity-less door’s
creds nor name another connection. The contract carries no logic — the
skeleton owns the fail-close enforcement.
Parameters
AppConversations
tai42_contract.app.facets.messaging.AppConversations
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.messaging.AppConversations.accept
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.
client_address is the conversation identity (its thread and transcript).
cap_key is the party the per-address turn cap holds accountable, which the
door composes: a provider channel passes its attested address (the two match),
a door that mints its own visitor id passes a key the platform does NOT mint —
its network client bucket — so the cap bounds spend the visitor cannot reset.
Required and non-blank; a door that omits it is refused, never defaulted.
params are optional entry parameters the door captured with the conversation
entry, delivered verbatim to a tool target’s payload under params;
None/empty leaves the payload unchanged. The door validates them with
validate_entry_params before accept.
params is ALSO the opaque-enrichment seam for the channel-specific inbound
context that has no shared shape — a tapped reply/list id, a template button
payload, a referral, the reply-to context of the message the participant quoted, a
contact card or a reaction — which a channel adapter encodes as string entries a
route reads deliberately; the platform adds no typed field for those.
form is an optional structured participant submission (an ask-less form’s answers)
riding WITH the required rendered text — the text stays the whole turn every
consumer sees, while a tool target’s start_expr may map the structured copy
from the payload’s form key (present only when the inbound carried one). The
platform bounds it as pure transport
(validate_inbound_form) and attaches no
meaning and NO TRUST to the contents: participant-shaped data, never schema-conformant.
attachments is the STRUCTURED media the participant sent WITH the message — the
inbound counterpart of an outbound answer’s media — as MediaItem
(image/document/video/audio; a channel resolves a sticker to image/video, a voice
note to audio). location is a LocationElement the participant shared. Both
are machine-consumable content with a shared cross-channel shape, so they are typed
fields (not params): they land in a tool target’s payload under the stable
attachments / location keys, present only when the inbound carried them, so
a form-/media-unaware target still sees the whole turn as text. None leaves
the payload unchanged.
locale is the participant’s BCP 47 language tag the channel resolved from its native
inbound (a per-message language hint), captured onto the turn’s subject so the
rendering layer resolves every text template and list format against it — flows and
state templates never select a language. It seeds a first-contact person’s stored
locale and, absent a stored operator override, is the turn’s resolved locale;
None means the channel supplied none (no silent default to any language).
Parameters
record_delivery_status
tai42_contract.app.facets.messaging.AppConversations.record_delivery_status
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
pending_messages
tai42_contract.app.facets.messaging.AppConversations.pending_messages
after and not yet carried into a turn.
The accepted records with origin="client" and inbound_kind="message" on
thread_id whose acceptance follows the after message, in acceptance order, each a
PendingMessage. Read-only and in-process (it reads the same thread index the turn
engine batches over), bounded by the thread’s FIFO depth.
A body running inside a turn asks this — with after the turn’s own lead message_id —
to learn whether a newer message is waiting, so it can yield (raise
TurnSupersededError) before an expensive or
irreversible step. Outside a turn there is nothing pending by definition. An unknown
thread_id reads as an empty list; a record already left accepted is not pending.
Parameters
register_target_validator
tai42_contract.app.facets.messaging.AppConversations.register_target_validator
target_kind.
A plugin calls this through the tai42_app handle when its module loads.
Route creation consults every registered validator for the route’s target kind
AFTER the target exists but BEFORE the route is written; a validator returning
any message lines refuses the creation with them (a 422), so a defect the target
carries — a flow reading a state no binding supplies — is caught at bind, never
deferred to run time. Registering two validators for one kind raises loudly.
Parameters
AppExtensions
tai42_contract.app.facets.execution.AppExtensions
app.extensions).
Members
extension
tai42_contract.app.facets.execution.AppExtensions.extension
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.execution.AppExtensions.available_extensions
[{"name", "kind"}].
AppHttp
tai42_contract.app.facets.routing.AppHttp
Members
middleware
tai42_contract.app.facets.routing.AppHttp.middleware
custom_route
tai42_contract.app.facets.routing.AppHttp.custom_route
summary— a one-line operation summary (required, non-empty).tags— at least one OpenAPI tag grouping the route (required).response_model— the pydantic model (anyBaseModel,RootModelincluded) describing the success body. Required — there is no default, so a route cannot silently omit it. By default the model is wrapped in the{"data": ...}success envelope; a route that answers a RAW top-level body passesenveloped=False(see below).Noneis legal ONLY together with a non-blankno_body_reason: the two states are mutually exclusive — a route declares a typed body OR a reasoned no-body, never both and never neither.enveloped— whether the JSON success body is wrapped in the{"data": <response_model>}envelope (the default,True) or is the model’s schema DIRECTLY at the top level (False, a raw non-enveloped body).enveloped=FalseREQUIRES aresponse_model: an unwrapped body still needs a real model, so a bareNoneunder it is a registration error.no_body_reason— the required-when-response_modelisNonejustification for a route that serves no{"data": <model>}JSON body (a redirect, a raw/streaming/asset response, a vendor webhook 200, or a raw non-enveloped body the envelope emitter cannot describe). Passing it alongside aresponse_model, or omitting it whenresponse_modelisNone, is a registration error.request_model— the pydantic model of the request body; required for any route that reads a body, omitted (None) otherwise.query_model— the pydantic model whose fields are published asin: queryparameters for ANY method, additive torequest_model. A read door’srequest_modelalready emits as query, so this is the only way a WRITE-method door documents the query it reads at the edge;None(the default) publishes no query model.authed— whether the route requires the api key; emitted as thesecurityrequirement.None(the default) defers to the runtime: a core route resolves toTrue, a declared plugin route to the negation of itstai-plugin.ymlpublicflag. Passing an explicit bool from a declared plugin route module is a registration error — the declaration is the single source of that decision.destructive— whether the route mutates in a way flagged as destructive (defaultFalse); emitted asx-destructive.action— the route’s authorization character (aRouteAction);None(the default) lets the surface derive the grantable class from the HTTP methods.declared— the route’s behavioral OpenAPI properties (aDeclaredRouteMetadata): itsreload_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.
503 response is derived from the handler body.
Parameters
use_raw_path_key
tai42_contract.app.facets.routing.AppHttp.use_raw_path_key
path_prefix against the raw (undecoded) request path.
A path parameter whose values carry / (a state record’s {key}, addressed as one
percent-encoded segment) stays ONE segment instead of splitting once the ASGI server has
decoded %2F; the matched parameters are decoded once after the match. Called AFTER the
routes are registered, over their shared prefix, so it covers a family of doors at one seam. A
no-op where no route table is served (the offline spec harness).
Parameters
mount_base
tai42_contract.app.facets.routing.AppHttp.mount_base
/api/ + the item’s mount base, no trailing slash (e.g. /api/channels/telegram).
Callable ONLY while a declared plugin route module imports — the mount
binding is present then. A module captures this value at import for later
use (a startup hook building an external webhook URL, a login descriptor’s
self-referential path) so a remapped base is followed instead of a
hardcoded default. Called with no binding present — a core or
operator-authored module — it raises: those modules own no declared mount.
AppInteractions
tai42_contract.app.facets.messaging.AppInteractions
app.interactions) — the ask facade and answer check.
Members
check_answer
tai42_contract.app.facets.messaging.AppInteractions.check_answer
answer against question — the ONE answer check every door reaches.
question is a QuestionFormat (the answer
format plus its payload — no stored request needed). Returns None when the answer
conforms; raises AnswerMismatchError (carrying the
failing field’s dotted path when the fault locates to one) otherwise. The answer door,
the callback door, a resumed run’s visit and plugins all validate through this one
callable so every surface applies identical rules per format.
Parameters
assert_resume_authorized
tai42_contract.app.facets.messaging.AppInteractions.assert_resume_authorized
interaction_id — or raise.
A driver’s continuation face and cross-driver chain-delivery tool call this with the id
they are about to resume/deliver-to, BEFORE producing any outcome, because those tools are
dispatchable by name at the run-tool door and the MCP edge. Authorised only inside the
platform’s own resume of that run: it passes iff the ambient run-authorization context
names interaction_id directly (the resume origin) OR the interaction’s stored run
delivery identity matches the ambient one (a cross-driver chain re-entry of the same run).
Raises ParkResumeUnauthorizedError for an external
caller (no origin) or an id belonging to another run — never a mere presence test.
Parameters
assert_delivery_authorized
tai42_contract.app.facets.messaging.AppInteractions.assert_delivery_authorized
completion_id — or raise.
A door’s out-of-band delivery address is a registered tool the platform’s delivery ladder
fires; the tool calls this at entry with the payload’s completion_id before delivering
anything. It passes iff the ambient delivery-fire context is set AND equals
completion_id — a None id and a call outside any fire never pass. Raises
ParkDeliveryUnauthorizedError otherwise, so a caller
naming the address tool directly at the run-tool door or the MCP edge delivers nothing.
Parameters
redelivery_horizon_seconds
tai42_contract.app.facets.messaging.AppInteractions.redelivery_horizon_seconds
visit
tai42_contract.app.facets.messaging.AppInteractions.visit
Visit-typed shared-visit callable.
The ONE seam every door drives a parkable run through: it runs the cancel / resume / take /
start order once for every caller (checks everything before doing anything, cancels,
resumes or takes at most one action besides cancel, starts the target when nothing was
resumed, normalises what came back), and returns a
VisitOutcome. A door resolves its own jqs to plain
values and hands them in; the generic list_parked / resume_parked / cancel_parked
below are thin wrappers over this same seam.
park_answer
tai42_contract.app.facets.messaging.AppInteractions.park_answer
VisitOutcome.
A plain result is the tool’s own value; an asks outcome is the caller ask entries
the run parked ({"asks": [entry, ...]}); a parked outcome is the suspended
sentinel; none is None. Both the synchronous run-tool door and the background
submit’s terminal record shape a park through this ONE callable, so a poller of either
door reads identical bytes and can tell a caller-ask park (answerable through
resume_parked) from a user-ask park. It never reveals a wrapped secret — the sync door
reveals those on the result kind itself and every recorder masks its own copy.
Parameters
normalise_started
tai42_contract.app.facets.messaging.AppInteractions.normalise_started
started VisitOutcome over the ambient subject.
The same normalisation visit applies to what its start returned — caller asks,
a re-park, or a final result — exposed for a door that already ran its start INSIDE its own
visit (a hook fire whose visit owns the run) and only needs the return classified,
so its record carries the same park answer both direct doors return.
Parameters
list_parked
tai42_contract.app.facets.messaging.AppInteractions.list_parked
ParkedEntry with its id, status
(asking/running/finished/failed) and the question/answer fields a
state-backed entry carries. The same rows a door-contract jq reads as $parked.
list_parked_for
tai42_contract.app.facets.messaging.AppInteractions.list_parked_for
context’s subject — the same entries as list_parked.
A parkable-driving door fetches this over its OWN
StateContext once and feeds the list to the door-contract
evaluator as $parked, keeping the contract evaluation a pure function of an injected
list rather than an ambient read. A None context has no subject and returns an empty
list.
Parameters
current_fire_identity
tai42_contract.app.facets.messaging.AppInteractions.current_fire_identity
(user_id, fingerprint) pair a fire forwards, or None.
A background task tool dispatched from within a door fire forwards this pair onto its worker
job so the deferred fire re-binds the SAME authority; None when no identity (or no
per-mint fingerprint) is bound, so nothing is forwarded and the deferred fire fails closed on
any credential seam rather than under a substituted principal.
bound_execution_identity_for_fire
tai42_contract.app.facets.messaging.AppInteractions.bound_execution_identity_for_fire
async with binding execution_key’s live-grant identity for a receiver-less door fire.
A scheduled fire has no live caller, so the door stores the firing identity (the execution
key’s user_id and its per-mint fingerprint) at create and binds it here at fire, so a
run that async-parks can rebind its continuation and a to="caller" resume acts under the
same authority. Homed beside the door’s other kit-reachable seams so a backend plugin binds a
scheduled fire’s identity without importing the skeleton. Raises when the key no longer
carries authority — the fire fails closed, never under a substituted principal.
Parameters
resume_parked
tai42_contract.app.facets.messaging.AppInteractions.resume_parked
payload, or TAKE its waiting outcome when omitted.
With payload given it resumes the asking caller ask interaction_id and returns
the resumed run’s normalised outcome; with payload omitted it TAKES a finished
entry’s waiting outcome (kind="result") or re-raises a failed one as
ParkableRunFailedError. A live inline receiver, so the
resumed run’s terminal is returned inline rather than delivered out of band.
Parameters
cancel_parked
tai42_contract.app.facets.messaging.AppInteractions.cancel_parked
ids on the current run’s subject.
Each id is torn down through the one teardown seam (its run and every run it linked above it
close for good, delivering FAILED once to a door that started it); returns a
VisitOutcome naming the ids cancelled. An id outside
the run’s own parked list raises ParkedEntryGoneError
with nothing cancelled.
Parameters
ask
tai42_contract.app.facets.messaging.AppInteractions.ask
Ask-typed ask callable.
An in-process plugin asks a human without importing the skeleton:
await tai42_app.interactions.ask(question, ..., mode="async", expiry_at=...). The return shape is the Ask contract’s:
mode="sync" returns the typed answer, mode="async" returns a
SuspendedInteraction. Its full call signature is the Ask
Protocol’s, including the per-ask on_mismatch digression policy and
mismatch_notice retry text a channel-delivered ask carries. A facade
EXPOSURE of the skeleton helper through the already-typed Protocol — no new
ask semantics.
AppLifecycle
tai42_contract.app.facets.runtime.AppLifecycle
Members
on_startup
tai42_contract.app.facets.runtime.AppLifecycle.on_startup
func to run at process startup (usable as a decorator).
Parameters
on_shutdown
tai42_contract.app.facets.runtime.AppLifecycle.on_shutdown
func to run at process shutdown (usable as a decorator).
Parameters
on_reload
tai42_contract.app.facets.runtime.AppLifecycle.on_reload
reload_config).
For example, dynamic tool loaders that on_startup ran once.
Parameters
on_post_swap
tai42_contract.app.facets.runtime.AppLifecycle.on_post_swap
on_fleet_op_applied
tai42_contract.app.facets.runtime.AppLifecycle.on_fleet_op_applied
wait_until_ready
tai42_contract.app.facets.runtime.AppLifecycle.wait_until_ready
AppMonitoring
tai42_contract.app.facets.runtime.AppMonitoring
Members
register_monitoring
tai42_contract.app.facets.runtime.AppMonitoring.register_monitoring
builder is omitted.
Parameters
active
tai42_contract.app.facets.runtime.AppMonitoring.active
AppPresets
tai42_contract.app.facets.authoring.AppPresets
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.
Members
bind
tai42_contract.app.facets.authoring.AppPresets.bind
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
create
tai42_contract.app.facets.authoring.AppPresets.create
input_schema over
a base tool with no registered support is a loud error that persists nothing. The
caller-authorization tier fence is OFF — the registration-tier fence authorizes a
request principal at the HTTP doors; an in-process caller authorizes its own callers
and passes only the base tools it is entitled to author — while every content check
stays on.
Parameters
save_version
tai42_contract.app.facets.authoring.AppPresets.save_version
input_schema via the CARRY_FORWARD sentinel;
output_schema only when output_schema_provided is True). A body that
cannot bind is a loud error that commits nothing; the tier fence is OFF for the
reason create states.
Parameters
register_write_validator
tai42_contract.app.facets.authoring.AppPresets.register_write_validator
base_tool (one per base tool; duplicate registration raises).
A base-tool plugin calls this through the tai42_app handle when its tool
module loads. The validator runs on every write that persists a body —
create / save-version / rollback — and in the dry-run validate verdict,
so a body its base tool cannot accept is a loud 400 that never persists. A
base tool with no registered validator gets no extra check.
Parameters
register_input_schema_support
tai42_contract.app.facets.authoring.AppPresets.register_input_schema_support
base_tool ACCEPTS a per-preset input schema (one per base tool; duplicate raises).
A base-tool plugin calls this through the tai42_app handle when its tool
module loads. A preset that sets an input_schema over a base tool with no
registered support is a loud authoring error at the shared preset-authoring
chokepoint, never a silently-ignored schema.
Parameters
input_schema_support
tai42_contract.app.facets.authoring.AppPresets.input_schema_support
base_tool declared, or None if it declared none.
When None, the base tool’s typed schema is fixed.
Parameters
register_registration_tier
tai42_contract.app.facets.authoring.AppPresets.register_registration_tier
base_tool (one per base tool).
Governs create/save/rollback/rename; duplicate registration raises.
Default authoring is the presets’ own write action; a base tool with no
declaration keeps that default. A base tool declaring fenced requires the
admin fence to author a preset over it. The shared preset-authoring chokepoint
reads this and enforces it BEFORE any store write on every authoring door.
Parameters
registration_tier
tai42_contract.app.facets.authoring.AppPresets.registration_tier
base_tool declared, or None if it declared none.
When None, authoring keeps the presets’ default write action.
Parameters
get_active_versioned_body
tai42_contract.app.facets.authoring.AppPresets.get_active_versioned_body
(version, body) read TOGETHER in one query.
The version-aware sibling of store.get_active_body: it captures the active version
pointer and the body it points at atomically, so a consumer that needs the version beside
the body never risks a skewed second read across a concurrent activation. Raises
PresetNotFoundError for an unknown preset.
Parameters
used_by
tai42_contract.app.facets.authoring.AppPresets.used_by
name as a tool, sorted.
Computed over the active preset population (a body’s composed tool names intersected with
the population, self excluded), so it answers “which saved presets depend on this one” for a
rename/delete dependents pass. Raises
PresetNotFoundError for a name that is not a known
preset.
Parameters
register_seed
tai42_contract.app.facets.authoring.AppPresets.register_seed
tai42_app handle when its module loads.
The declared seeds are applied by the startup/reload seed applier — created
when absent, a preset already present left untouched. Declaring two seeds
under the same name raises loudly — a silent overwrite could drop one
plugin’s default under another’s.
Parameters
store
tai42_contract.app.facets.authoring.AppPresets.store
app.versioning.store (kind="preset").
AppSandboxes
tai42_contract.app.facets.execution.AppSandboxes
app.sandboxes).
Members
register_sandbox
tai42_contract.app.facets.execution.AppSandboxes.register_sandbox
Sandbox provider (decorator form, returning the class unchanged).
One provider backs the slot; a second registration is a conflict the runtime rejects loudly.
sandbox
tai42_contract.app.facets.execution.AppSandboxes.sandbox
None — status/introspection ONLY.
Never gate execution on this nullable read; acquire through require_sandbox, the every-door
guarantee (a None property is how per-consumer checks drift).
require_sandbox
tai42_contract.app.facets.execution.AppSandboxes.require_sandbox
SandboxUnavailableError (naming TAI_MCP_SANDBOX and
sandbox_module) when none is registered. EVERY consumer acquires through here.
sandbox_policy
tai42_contract.app.facets.execution.AppSandboxes.sandbox_policy
SandboxPolicy.
This is the plugin-reachable READ of the SAME policy the skeleton binds to the kit at the
session-create chokepoint.
Available REGARDLESS of whether a provider is registered (it reads operator
config, not a provider). Mirrors the ask / resolve_connection_auth
facade accessors that let an in-process plugin read a skeleton-resolved value
without importing the skeleton; a consumer building a policied spec reads the
network default and scrub_transcript here. Implemented in the skeleton,
which resolves the policy once and returns the SAME value it binds to the kit.
AppStates
tai42_contract.app.facets.states.AppStates
app.states).
The door-agnostic contract every door and tool reads and writes a subject’s document through.
The store takes a full StateSubject and refuses
anything less; subject resolution happens once per door, never here. Every write
door supplies a WriteOrigin carrying only what a
consumer knows — the platform completes it (door/actor/turn_id) at this
chokepoint, so the audit ledger is never optional or forgeable. While the states
component’s database is unbound every method raises
StatesNotConfiguredError (501), never an empty read.
Members
list_declarations
tai42_contract.app.facets.states.AppStates.list_declarations
get_declaration
tai42_contract.app.facets.states.AppStates.get_declaration
name, or None when none is declared.
Parameters
put_declaration
tai42_contract.app.facets.states.AppStates.put_declaration
NonAdditiveRedeclareError (erase the records
first), and removing a subject kind still present in records raises
DeclarationInUseError. Never a silent overwrite.
Parameters
delete_declaration
tai42_contract.app.facets.states.AppStates.delete_declaration
DeclarationInUseError when a consumer still binds it.
Parameters
stats
tai42_contract.app.facets.states.AppStates.stats
list_templates
tai42_contract.app.facets.states.AppStates.list_templates
get_template
tai42_contract.app.facets.states.AppStates.get_template
name, or None when none is stored.
The read a consumer’s own sibling document validates against.
Parameters
put_template
tai42_contract.app.facets.states.AppStates.put_template
replace required to overwrite an existing name).
Runs every registered attach validator over each live attachment before the write,
so a consumer’s data-dependent check still fires here; a raise leaves the stored
document untouched. Overwriting an existing name without replace raises
TemplateExistsError.
Parameters
delete_template
tai42_contract.app.facets.states.AppStates.delete_template
TemplateInUseError while it is still attached.
Parameters
list_attachments
tai42_contract.app.facets.states.AppStates.list_attachments
state, by template, or every attachment when both are None.
What the attachments listing and the Consumers tab read. Each row carries state,
template, path, parameters and declarations.
Parameters
attach
tai42_contract.app.facets.states.AppStates.attach
template on state at body.path, recomposing the effective schema in one transaction.
Stores the resolved parameters and declarations. Runs every registered attach validator before the write; a
raise refuses the door with the validator’s message. Overlapping fragments raise
AttachConflictError.
Parameters
update_attachment_declarations
tai42_contract.app.facets.states.AppStates.update_attachment_declarations
options is a per-operation directive bag passed to the reconcilers for THIS
operation only, never stored or served back (None is an empty bag).
Parameters
detach
tai42_contract.app.facets.states.AppStates.detach
read
tai42_contract.app.facets.states.AppStates.read
subject (resolving a fold to its canonical subject), or None when none exists.
An unknown person or a target mismatch is a refusal, never an empty document.
Parameters
replace
tai42_contract.app.facets.states.AppStates.replace
subject’s whole document with data and return the new record.
Parameters
merge
tai42_contract.app.facets.states.AppStates.merge
patch into subject’s document and return the new record.
Parameters
apply
tai42_contract.app.facets.states.AppStates.apply
subject’s document under the effective schema.
Refuses a whole-path write over a composing path
(RegimeViolationError) before the ledger insert,
stamps _trace under a traced attachment, and records one state_writes row with
the touched paths and the completed origin. A replayed op_id returns
applied=False without re-writing; guarded ops land in skipped.
Parameters
eval_template_jq
tai42_contract.app.facets.states.AppStates.eval_template_jq
input-purpose template_jq program name for subject and return its value.
The program’s jq runs over the subject’s record, params supplying
its declared parameters. name resolves across the state’s attached templates
(unqualified → the declaring template; <attachment>.<name> → that attachment’s
template). An unknown name is a StateNotFoundError; an
ambiguous unqualified name, an update-purpose name, an undeclared param or an
evaluation failure is a ValueValidationError. A read;
no write is recorded.
Parameters
apply_template_jq
tai42_contract.app.facets.states.AppStates.apply_template_jq
update-purpose template_jq program name to subject.
Its jq maps the record subtree (its .) with $input bound to a template-relative op
batch, rebased under the attachment path and applied through the same chokepoint as
apply — so regimes, the
composing-shape guard, trace stamping and op_id idempotency all hold. name
resolves as for eval_template_jq. An unknown name is a
StateNotFoundError; an ambiguous unqualified name, an
input-purpose name, an evaluation failure or a wrong-shaped return is a
ValueValidationError.
Parameters
erase
tai42_contract.app.facets.states.AppStates.erase
subject’s record, recording the write.
Parameters
fold
tai42_contract.app.facets.states.AppStates.fold
subject into into and return the resulting canonical document.
mode decides how the documents combine. A self-fold, a cycle, a conflicting re-fold,
or a merge whose result fails the schema raises
SubjectFoldError; a retried fold to the same target is a quiet no-op.
Parameters
list_subjects
tai42_contract.app.facets.states.AppStates.list_subjects
state (optionally one kind).
{"subjects": [...], "next_cursor": <cursor|None>}.
Parameters
search
tai42_contract.app.facets.states.AppStates.search
filters.
{"matches": [...], "next_cursor": <cursor|None>}.
Parameters
writes
tai42_contract.app.facets.states.AppStates.writes
subject, newest first.
The items (each a write with its completed origin and touched paths) plus the
next_cursor that pages the trail like list_subjects/search page
theirs (the last row’s id when the page is full, else None).
Parameters
prune_expired
tai42_contract.app.facets.states.AppStates.prune_expired
retention_days and return the per-state deletion counts.
context
tai42_contract.app.facets.states.AppStates.context
StateContext the current door deposited.
None outside a door (an api write completes from the request principal instead).
register_consumer_lister
tai42_contract.app.facets.states.AppStates.register_consumer_lister
kind (flow / hook / schedule / agent).
A plugin calls this through the tai42_app handle when its module loads;
consumers unions every registered lister. Registering two listers for one
kind raises loudly.
Parameters
consumers
tai42_contract.app.facets.states.AppStates.consumers
state — the union of every registered consumer lister — for the Consumers tab.
Parameters
register_template_seed
tai42_contract.app.facets.states.AppStates.register_template_seed
tai42_app handle when its module loads. The
startup/reload seed applier creates it when absent and leaves a template already
present untouched. Declaring two seeds under one name raises loudly.
Parameters
register_attach_validator
tai42_contract.app.facets.states.AppStates.register_attach_validator
tai42_app handle when its module loads. The
validator receives the template document, an attachment’s declaration values, and the
state’s effective schema, and RAISES to refuse; it runs before every attach,
update_attachment_declarations and put_template(replace=True) write, so a
consumer’s checks fire at the platform’s declarations doors, the States page
included.
Parameters
register_attach_reconciler
tai42_contract.app.facets.states.AppStates.register_attach_reconciler
tai42_app handle when its module loads. The
reconciler receives a AttachReconcileContext — the
template, the operation, the previous and new declarations, the attach options, and a
record door bound to the state — inside every attach and
update_attachment_declarations write, after the validators and before the write. It
RAISES to refuse the attach (naming the records the new declarations orphan) or
writes resolutions through the context’s record door and returns, letting the attach
commit with those writes.
Parameters
AppStorage
tai42_contract.app.facets.execution.AppStorage
app.storage).
Members
register_storage
tai42_contract.app.facets.execution.AppStorage.register_storage
Storage provider; usable bare or as a decorator factory.
resource_manager
tai42_contract.app.facets.execution.AppStorage.resource_manager
AppSubApp
tai42_contract.app.facets.runtime.AppSubApp
Members
mcp_sub_app_router
tai42_contract.app.facets.runtime.AppSubApp.mcp_sub_app_router
AppToolMeta
tai42_contract.app.facets.authoring.AppToolMeta
app.tool_meta) — the organizational overlay over any live tool.
The overlay is a folder tree plus a per-tool row (display name, folder
placement, tags, badges, a hidden override).
store is the ToolMetaStore view the routes
and the preset lifecycle cascade read and write. patch is the in-process edit
seam beside the HTTP PATCH door.
Members
store
tai42_contract.app.facets.authoring.AppToolMeta.store
patch
tai42_contract.app.facets.authoring.AppToolMeta.patch
folder_id is a loud error). Only the
arguments given are written: folder_id places the tool, and a tags list
REPLACES the whole tag set (array values are set replacements, not merges).
tags=None leaves the tag set untouched; folder_id=None leaves the
placement untouched.
Parameters
AppTools
tai42_contract.tools.AppTools
Members
tool_title
tai42_contract.tools.AppTools.tool_title
func.
Parameters
get_tool
tai42_contract.tools.AppTools.get_tool
key.
Parameters
get_tools
tai42_contract.tools.AppTools.get_tools
get_client_tools
tai42_contract.tools.AppTools.get_client_tools
names when given.
Parameters
run_tool
tai42_contract.tools.AppTools.run_tool
key with arguments and return its result.
offload_sync runs a synchronous tool body off the event loop in a worker thread.
continues_chain is an in-process seam keyword ONLY (no request model, MCP
argument, or tool argument sets it): when given, the dispatch’s call frame SETS
the ambient call chain to it rather than pushing key, so a continuation
runner restores a parked run’s chain on the one dispatch that resumes it.
extras is likewise an in-process seam keyword ONLY (no request model, MCP
argument, or tool argument sets it): the mapping a door carries into the run it
starts. It is set on the dispatch’s call frame — ambient and read-only for THAT
frame, so the started tool reads it through extras and every nested frame
starts empty. A visit checks the keys against the target’s declaration before the
run; None binds an empty mapping.
Parameters
extras
tai42_contract.tools.AppTools.extras
extras mapping the current run was started with (empty when none).
A door carries author-configured extras into a run; a tool reads the keys it declared
(@app.tools.tool(extras_keys=...)) here. The mapping is read-only and scoped to the
started target’s own frame — every nested dispatch reads an empty mapping, so nothing leaks
down. No request model, MCP argument, or tool argument can set it.
declared_extras
tai42_contract.tools.AppTools.declared_extras
extras keys tool name is declared to read (empty when it declares none).
A preset inherits its base tool’s declared keys. The visit checks a door’s extras against
this set before starting the target and refuses an undeclared key.
Parameters
remove_tool
tai42_contract.tools.AppTools.remove_tool
name.
Parameters
register_tool_info
tai42_contract.tools.AppTools.register_tool_info
name’s extension combos, attaching each combo stack to the base.
Parameters
unregister_tool_info
tai42_contract.tools.AppTools.unregister_tool_info
name.
Parameters
unregister_tool_base
tai42_contract.tools.AppTools.unregister_tool_base
tool_name and return the names removed.
Parameters
tool_refs_extractor
tai42_contract.tools.AppTools.tool_refs_extractor
name registered, or None when it declared none.
Parameters
register_rename_referee
tai42_contract.tools.AppTools.register_rename_referee
ToolRenameReferee consulted before a tool rename.
A plugin holding tool-name references calls this through the tai42_app
handle when its module loads. Every registered referee is asked for the
old name on a rename; any non-empty answer blocks the rename and its
descriptions name the holders. Registering the same provider object twice
raises loudly — a double registration is a plugin bug, never a silent
duplicate consult.
Parameters
register_delete_referee
tai42_contract.tools.AppTools.register_delete_referee
ToolDeleteReferee consulted before a preset delete.
A plugin holding resources keyed on a preset/tool name (e.g. per-node state
bindings that reference a preset) calls this through the tai42_app handle when
its module loads. Every registered referee is asked for the name on a delete; a
referee cascades its own cleanup and returns empty to allow, or returns non-empty
descriptions to VETO — any non-empty answer blocks the delete and names the
holders. Registering the same provider object twice raises loudly — a double
registration is a plugin bug, never a silent duplicate consult.
Parameters
register_detach_referee
tai42_contract.tools.AppTools.register_detach_referee
StateTemplateDetachReferee consulted before a state-template detach.
A holder of door bindings that name templates (e.g. per-node state bindings, or the
platform’s own preset/route/hook/schedule bindings) calls this through the
tai42_app handle when its module loads. Every registered referee is asked for the
(state, template) on a detach; any non-empty answer blocks the detach and its
descriptions name the referencing bindings. Registering the same provider object
twice raises loudly — a double registration is a bug, never a silent duplicate
consult.
Parameters
register_tier
tai42_contract.tools.AppTools.register_tier
base_tool’s registration tier (a RouteAction).
The authorization character enforced everywhere the tier is consulted.
A fenced or secret tier gates BOTH authoring a preset over the base tool
(admin-only) AND running the tool: a fenced/secret tool runs only for an
administrator, at every execution door, and a preset authored over it inherits
that fence at run time. read/write carry no execution gate. This is the
programmatic form of @app.tools.tool(tier=...); both write the one shared
registry (also read on the authoring side as app.presets.registration_tier).
One declaration per base tool; a duplicate raises loudly.
Parameters
tier
tai42_contract.tools.AppTools.tier
base_tool declared, or None when it declared none.
None means no execution fence; authoring keeps the presets’ default write action.
Parameters
AppVersioning
tai42_contract.app.facets.authoring.AppVersioning
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.
Members
store
tai42_contract.app.facets.authoring.AppVersioning.store
AppWebhookVerifiers
tai42_contract.app.facets.messaging.AppWebhookVerifiers
app.webhook_verifiers).
Members
register
tai42_contract.app.facets.messaging.AppWebhookVerifiers.register
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.messaging.AppWebhookVerifiers.get
DeclaredRouteMetadata
tai42_contract.app.facets.routing.DeclaredRouteMetadata
/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
PendingMessage
tai42_contract.app.facets.messaging.PendingMessage
AppConversations.pending_messages returns, so a body running inside a
turn can learn a newer message is waiting and stop before an irreversible step. message_id
is the accepted record’s id, text its verbatim inbound text, accepted_at the epoch
seconds it was accepted at (the thread index’s own score). Frozen.
Attributes
RouteAction
tai42_contract.app.facets.routing.RouteAction
TaiApp
tai42_contract.app.TaiApp
Members
tools
tai42_contract.app.TaiApp.tools
agents
tai42_contract.app.TaiApp.agents
backends
tai42_contract.app.TaiApp.backends
sandboxes
tai42_contract.app.TaiApp.sandboxes
storage
tai42_contract.app.TaiApp.storage
connectors
tai42_contract.app.TaiApp.connectors
accounts
tai42_contract.app.TaiApp.accounts
webhook_verifiers
tai42_contract.app.TaiApp.webhook_verifiers
channels
tai42_contract.app.TaiApp.channels
conversations
tai42_contract.app.TaiApp.conversations
monitoring
tai42_contract.app.TaiApp.monitoring
extensions
tai42_contract.app.TaiApp.extensions
interactions
tai42_contract.app.TaiApp.interactions
ask interactions facade.
http
tai42_contract.app.TaiApp.http
clients
tai42_contract.app.TaiApp.clients
lifecycle
tai42_contract.app.TaiApp.lifecycle
admin
tai42_contract.app.TaiApp.admin
config
tai42_contract.app.TaiApp.config
backup
tai42_contract.app.TaiApp.backup
sub_app
tai42_contract.app.TaiApp.sub_app
versioning
tai42_contract.app.TaiApp.versioning
presets
tai42_contract.app.TaiApp.presets
tool_meta
tai42_contract.app.TaiApp.tool_meta
states
tai42_contract.app.TaiApp.states
tai42_app
tai42_contract.app.tai42_app
AppAccounts
tai42_contract.app.facets.integrations.AppAccounts
Members
active_provider
tai42_contract.app.facets.integrations.AppAccounts.active_provider
name, or None when none is active.
An AccountsProvider is an IdentityProvider. None means no provider is
active under that name — the name is not configured, or a build is mid-flight.
Parameters
AppAdmin
tai42_contract.app.facets.runtime.AppAdmin
Members
reload_mcp
tai42_contract.app.facets.runtime.AppAdmin.reload_mcp
title and return its status.
Parameters
deregister_mcp
tai42_contract.app.facets.runtime.AppAdmin.deregister_mcp
title and return its status.
Parameters
reload_config
tai42_contract.app.facets.runtime.AppAdmin.reload_config
tool_reloader
tai42_contract.app.facets.runtime.AppAdmin.tool_reloader
(action, name) -> dict reloader for kind.
Parameters
run_tool_reload
tai42_contract.app.facets.runtime.AppAdmin.run_tool_reload
kind reloader for action on name.
Parameters
reload_failed_mcps
tai42_contract.app.facets.runtime.AppAdmin.reload_failed_mcps
list_failed_mcps
tai42_contract.app.facets.runtime.AppAdmin.list_failed_mcps
live_mcp_status
tai42_contract.app.facets.runtime.AppAdmin.live_mcp_status
live_manifest
tai42_contract.app.facets.runtime.AppAdmin.live_manifest
AppAgents
tai42_contract.app.facets.execution.AppAgents
app.agents).
Members
agent
tai42_contract.app.facets.execution.AppAgents.agent
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.
meta is generic registration metadata threaded onto the same constructed
run-tool object (naming no consumer concept — a registrant attaches any generic
tai42/* key, e.g. a crash-resume flag the run-dispatch seam reads). The
decorator returns the class unchanged, so the decorated symbol keeps its
concrete subclass type.
Parameters
get_agent
tai42_contract.app.facets.execution.AppAgents.get_agent
all_agents
tai42_contract.app.facets.execution.AppAgents.all_agents
AppBackends
tai42_contract.app.facets.execution.AppBackends
app.backends).
Members
register_backend
tai42_contract.app.facets.execution.AppBackends.register_backend
Backend provider; usable bare or as a decorator factory.
backend
tai42_contract.app.facets.execution.AppBackends.backend
None when none is registered.
AppBackup
tai42_contract.app.facets.runtime.AppBackup
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.runtime.AppBackup.register_section
name.
Parameters
sections
tai42_contract.app.facets.runtime.AppBackup.sections
export_section
tai42_contract.app.facets.runtime.AppBackup.export_section
name and return its payload.
Parameters
import_section
tai42_contract.app.facets.runtime.AppBackup.import_section
payload via one section’s importer by name and return its report.
Parameters
AppChannels
tai42_contract.app.facets.messaging.AppChannels
app.channels) and inbound-answer ladder.
Members
register
tai42_contract.app.facets.messaging.AppChannels.register
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.messaging.AppChannels.get
ask 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.messaging.AppChannels.names
handle_inbound_answer
tai42_contract.app.facets.messaging.AppChannels.handle_inbound_answer
InboundAnswerResult: the outcome the channel maps to its
transport ack, plus the door’s retry_reason/retry_field when it rejected
the answer’s content, so a channel that owns its correction surface can render the
door’s specific message.
A channel computes its own opaque correlation_key for the participant’s address,
provides the answer value to forward to the door, its
CorrelationStore, and an InboundBridge of the
fields a bridged turn needs.
SEAM SYMMETRY (bridge.params ↔ answer params): the InboundBridge may carry opaque
channel enrichment in params — the answer-path counterpart of a conversation entry’s
params. The ladder threads it BOTH ways so enrichment is never dropped on either arm:
the answer is forwarded to the ask’s callback door as {"answer": answer, "params": params} (params present only when set), landing on
params for the asking flow
to read beside answer; and on the BRIDGE arm the same params are passed to
accept as its entry params. The ladder:
- No pending ask on the key ->
InboundAnswerOutcome.NO_CORRELATIONwith NO side effect: the CALLER bridges the reply as a normal turn (the ladder never bridges on a miss, exactly as each channel did by hand). - The door accepts (2xx) -> release the correlation, return
InboundAnswerOutcome.FORWARDED. - The door returns 404 (the ask was withdrawn/expired/cancelled) -> release,
bridge the reply as a fresh turn, return
InboundAnswerOutcome.BRIDGED. - The door returns 400 on a LIVE ask -> read the door’s
retry_in_place(default True): True keeps the correlation, notifies the participant what’s expected, fires ONE operator event, returnsInboundAnswerOutcome.RETRY_KEPT; False (a hard mismatch) releases, notifies the participant the question is closed, fires the event, bridges the reply, returnsInboundAnswerOutcome.BRIDGED. - Anything else (401/413/5xx, or a transport fault) -> do NOT release; raise
AnswerForwardErrorso the channel’s webhook redelivery re-runs the ladder. The answer is never silently lost.
InboundAnswerOutcome.NO_CORRELATION.
Parameters
record_send_receipt
tai42_contract.app.facets.messaging.AppChannels.record_send_receipt
notify_user send back onto its originating trace.
The send is a notify_user channel send with no conversation record. The tier-2
counterpart to the conversation bridge’s record_delivery_status: a
channel’s delivery-status webhook calls this when the bridge does not own the
outbound id (record_delivery_status raised LookupError). It resolves the id
through the TTL’d send-receipt index and, on a hit, emits a delivery_receipt event
into the recorded trace (a FAILED receipt at ERROR level), so the originating trace
shows delivered-vs-accepted for its sends. errors carries any provider error
detail for the event input.
Returns True when the id was a known send (event emitted), False when it
is not — so the webhook keeps its genuinely-unknown-id log only on a False. A
no-op returning False where the send-receipt store is unconfigured.
Parameters
AppClients
tai42_contract.app.facets.runtime.AppClients
Members
client_ctx
tai42_contract.app.facets.runtime.AppClients.client_ctx
fresh=True.
settings is a kit ClientSettings whose client_kwargs() supplies
the connection key.
Parameters
shutdown_clients
tai42_contract.app.facets.runtime.AppClients.shutdown_clients
AppConfig
tai42_contract.app.facets.runtime.AppConfig
Members
config_manager
tai42_contract.app.facets.runtime.AppConfig.config_manager
AppConnectors
tai42_contract.app.facets.integrations.AppConnectors
Members
register_connector
tai42_contract.app.facets.integrations.AppConnectors.register_connector
connectors entry at boot/reload, and by any
code holding the handle (a connector is pure data, so this is a plain call,
not a decorator).
Parameters
token_store
tai42_contract.app.facets.integrations.AppConnectors.token_store
connection_id).
resolve_connection_auth
tai42_contract.app.facets.integrations.AppConnectors.resolve_connection_auth
await it. Returns None when the connection injects nothing.
GUARANTEE (enforced by the skeleton implementation): (1) it RAISES a loud
constant-message error when NO execution identity is bound — the fail-close
raise fires as the awaited coroutine runs, BEFORE resolving, so an
identity-less door never gets creds injected; and
(2) connection_id is a REFERENCE supplied by operator settings, NEVER
session-supplied, so a session can neither reach an identity-less door’s
creds nor name another connection. The contract carries no logic — the
skeleton owns the fail-close enforcement.
Parameters
AppConversations
tai42_contract.app.facets.messaging.AppConversations
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.messaging.AppConversations.accept
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.
client_address is the conversation identity (its thread and transcript).
cap_key is the party the per-address turn cap holds accountable, which the
door composes: a provider channel passes its attested address (the two match),
a door that mints its own visitor id passes a key the platform does NOT mint —
its network client bucket — so the cap bounds spend the visitor cannot reset.
Required and non-blank; a door that omits it is refused, never defaulted.
params are optional entry parameters the door captured with the conversation
entry, delivered verbatim to a tool target’s payload under params;
None/empty leaves the payload unchanged. The door validates them with
validate_entry_params before accept.
params is ALSO the opaque-enrichment seam for the channel-specific inbound
context that has no shared shape — a tapped reply/list id, a template button
payload, a referral, the reply-to context of the message the participant quoted, a
contact card or a reaction — which a channel adapter encodes as string entries a
route reads deliberately; the platform adds no typed field for those.
form is an optional structured participant submission (an ask-less form’s answers)
riding WITH the required rendered text — the text stays the whole turn every
consumer sees, while a tool target’s start_expr may map the structured copy
from the payload’s form key (present only when the inbound carried one). The
platform bounds it as pure transport
(validate_inbound_form) and attaches no
meaning and NO TRUST to the contents: participant-shaped data, never schema-conformant.
attachments is the STRUCTURED media the participant sent WITH the message — the
inbound counterpart of an outbound answer’s media — as MediaItem
(image/document/video/audio; a channel resolves a sticker to image/video, a voice
note to audio). location is a LocationElement the participant shared. Both
are machine-consumable content with a shared cross-channel shape, so they are typed
fields (not params): they land in a tool target’s payload under the stable
attachments / location keys, present only when the inbound carried them, so
a form-/media-unaware target still sees the whole turn as text. None leaves
the payload unchanged.
locale is the participant’s BCP 47 language tag the channel resolved from its native
inbound (a per-message language hint), captured onto the turn’s subject so the
rendering layer resolves every text template and list format against it — flows and
state templates never select a language. It seeds a first-contact person’s stored
locale and, absent a stored operator override, is the turn’s resolved locale;
None means the channel supplied none (no silent default to any language).
Parameters
record_delivery_status
tai42_contract.app.facets.messaging.AppConversations.record_delivery_status
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
pending_messages
tai42_contract.app.facets.messaging.AppConversations.pending_messages
after and not yet carried into a turn.
The accepted records with origin="client" and inbound_kind="message" on
thread_id whose acceptance follows the after message, in acceptance order, each a
PendingMessage. Read-only and in-process (it reads the same thread index the turn
engine batches over), bounded by the thread’s FIFO depth.
A body running inside a turn asks this — with after the turn’s own lead message_id —
to learn whether a newer message is waiting, so it can yield (raise
TurnSupersededError) before an expensive or
irreversible step. Outside a turn there is nothing pending by definition. An unknown
thread_id reads as an empty list; a record already left accepted is not pending.
Parameters
register_target_validator
tai42_contract.app.facets.messaging.AppConversations.register_target_validator
target_kind.
A plugin calls this through the tai42_app handle when its module loads.
Route creation consults every registered validator for the route’s target kind
AFTER the target exists but BEFORE the route is written; a validator returning
any message lines refuses the creation with them (a 422), so a defect the target
carries — a flow reading a state no binding supplies — is caught at bind, never
deferred to run time. Registering two validators for one kind raises loudly.
Parameters
AppExtensions
tai42_contract.app.facets.execution.AppExtensions
app.extensions).
Members
extension
tai42_contract.app.facets.execution.AppExtensions.extension
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.execution.AppExtensions.available_extensions
[{"name", "kind"}].
AppHttp
tai42_contract.app.facets.routing.AppHttp
Members
middleware
tai42_contract.app.facets.routing.AppHttp.middleware
custom_route
tai42_contract.app.facets.routing.AppHttp.custom_route
summary— a one-line operation summary (required, non-empty).tags— at least one OpenAPI tag grouping the route (required).response_model— the pydantic model (anyBaseModel,RootModelincluded) describing the success body. Required — there is no default, so a route cannot silently omit it. By default the model is wrapped in the{"data": ...}success envelope; a route that answers a RAW top-level body passesenveloped=False(see below).Noneis legal ONLY together with a non-blankno_body_reason: the two states are mutually exclusive — a route declares a typed body OR a reasoned no-body, never both and never neither.enveloped— whether the JSON success body is wrapped in the{"data": <response_model>}envelope (the default,True) or is the model’s schema DIRECTLY at the top level (False, a raw non-enveloped body).enveloped=FalseREQUIRES aresponse_model: an unwrapped body still needs a real model, so a bareNoneunder it is a registration error.no_body_reason— the required-when-response_modelisNonejustification for a route that serves no{"data": <model>}JSON body (a redirect, a raw/streaming/asset response, a vendor webhook 200, or a raw non-enveloped body the envelope emitter cannot describe). Passing it alongside aresponse_model, or omitting it whenresponse_modelisNone, is a registration error.request_model— the pydantic model of the request body; required for any route that reads a body, omitted (None) otherwise.query_model— the pydantic model whose fields are published asin: queryparameters for ANY method, additive torequest_model. A read door’srequest_modelalready emits as query, so this is the only way a WRITE-method door documents the query it reads at the edge;None(the default) publishes no query model.authed— whether the route requires the api key; emitted as thesecurityrequirement.None(the default) defers to the runtime: a core route resolves toTrue, a declared plugin route to the negation of itstai-plugin.ymlpublicflag. Passing an explicit bool from a declared plugin route module is a registration error — the declaration is the single source of that decision.destructive— whether the route mutates in a way flagged as destructive (defaultFalse); emitted asx-destructive.action— the route’s authorization character (aRouteAction);None(the default) lets the surface derive the grantable class from the HTTP methods.declared— the route’s behavioral OpenAPI properties (aDeclaredRouteMetadata): itsreload_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.
503 response is derived from the handler body.
Parameters
use_raw_path_key
tai42_contract.app.facets.routing.AppHttp.use_raw_path_key
path_prefix against the raw (undecoded) request path.
A path parameter whose values carry / (a state record’s {key}, addressed as one
percent-encoded segment) stays ONE segment instead of splitting once the ASGI server has
decoded %2F; the matched parameters are decoded once after the match. Called AFTER the
routes are registered, over their shared prefix, so it covers a family of doors at one seam. A
no-op where no route table is served (the offline spec harness).
Parameters
mount_base
tai42_contract.app.facets.routing.AppHttp.mount_base
/api/ + the item’s mount base, no trailing slash (e.g. /api/channels/telegram).
Callable ONLY while a declared plugin route module imports — the mount
binding is present then. A module captures this value at import for later
use (a startup hook building an external webhook URL, a login descriptor’s
self-referential path) so a remapped base is followed instead of a
hardcoded default. Called with no binding present — a core or
operator-authored module — it raises: those modules own no declared mount.
AppInteractions
tai42_contract.app.facets.messaging.AppInteractions
app.interactions) — the ask facade and answer check.
Members
check_answer
tai42_contract.app.facets.messaging.AppInteractions.check_answer
answer against question — the ONE answer check every door reaches.
question is a QuestionFormat (the answer
format plus its payload — no stored request needed). Returns None when the answer
conforms; raises AnswerMismatchError (carrying the
failing field’s dotted path when the fault locates to one) otherwise. The answer door,
the callback door, a resumed run’s visit and plugins all validate through this one
callable so every surface applies identical rules per format.
Parameters
assert_resume_authorized
tai42_contract.app.facets.messaging.AppInteractions.assert_resume_authorized
interaction_id — or raise.
A driver’s continuation face and cross-driver chain-delivery tool call this with the id
they are about to resume/deliver-to, BEFORE producing any outcome, because those tools are
dispatchable by name at the run-tool door and the MCP edge. Authorised only inside the
platform’s own resume of that run: it passes iff the ambient run-authorization context
names interaction_id directly (the resume origin) OR the interaction’s stored run
delivery identity matches the ambient one (a cross-driver chain re-entry of the same run).
Raises ParkResumeUnauthorizedError for an external
caller (no origin) or an id belonging to another run — never a mere presence test.
Parameters
assert_delivery_authorized
tai42_contract.app.facets.messaging.AppInteractions.assert_delivery_authorized
completion_id — or raise.
A door’s out-of-band delivery address is a registered tool the platform’s delivery ladder
fires; the tool calls this at entry with the payload’s completion_id before delivering
anything. It passes iff the ambient delivery-fire context is set AND equals
completion_id — a None id and a call outside any fire never pass. Raises
ParkDeliveryUnauthorizedError otherwise, so a caller
naming the address tool directly at the run-tool door or the MCP edge delivers nothing.
Parameters
redelivery_horizon_seconds
tai42_contract.app.facets.messaging.AppInteractions.redelivery_horizon_seconds
visit
tai42_contract.app.facets.messaging.AppInteractions.visit
Visit-typed shared-visit callable.
The ONE seam every door drives a parkable run through: it runs the cancel / resume / take /
start order once for every caller (checks everything before doing anything, cancels,
resumes or takes at most one action besides cancel, starts the target when nothing was
resumed, normalises what came back), and returns a
VisitOutcome. A door resolves its own jqs to plain
values and hands them in; the generic list_parked / resume_parked / cancel_parked
below are thin wrappers over this same seam.
park_answer
tai42_contract.app.facets.messaging.AppInteractions.park_answer
VisitOutcome.
A plain result is the tool’s own value; an asks outcome is the caller ask entries
the run parked ({"asks": [entry, ...]}); a parked outcome is the suspended
sentinel; none is None. Both the synchronous run-tool door and the background
submit’s terminal record shape a park through this ONE callable, so a poller of either
door reads identical bytes and can tell a caller-ask park (answerable through
resume_parked) from a user-ask park. It never reveals a wrapped secret — the sync door
reveals those on the result kind itself and every recorder masks its own copy.
Parameters
normalise_started
tai42_contract.app.facets.messaging.AppInteractions.normalise_started
started VisitOutcome over the ambient subject.
The same normalisation visit applies to what its start returned — caller asks,
a re-park, or a final result — exposed for a door that already ran its start INSIDE its own
visit (a hook fire whose visit owns the run) and only needs the return classified,
so its record carries the same park answer both direct doors return.
Parameters
list_parked
tai42_contract.app.facets.messaging.AppInteractions.list_parked
ParkedEntry with its id, status
(asking/running/finished/failed) and the question/answer fields a
state-backed entry carries. The same rows a door-contract jq reads as $parked.
list_parked_for
tai42_contract.app.facets.messaging.AppInteractions.list_parked_for
context’s subject — the same entries as list_parked.
A parkable-driving door fetches this over its OWN
StateContext once and feeds the list to the door-contract
evaluator as $parked, keeping the contract evaluation a pure function of an injected
list rather than an ambient read. A None context has no subject and returns an empty
list.
Parameters
current_fire_identity
tai42_contract.app.facets.messaging.AppInteractions.current_fire_identity
(user_id, fingerprint) pair a fire forwards, or None.
A background task tool dispatched from within a door fire forwards this pair onto its worker
job so the deferred fire re-binds the SAME authority; None when no identity (or no
per-mint fingerprint) is bound, so nothing is forwarded and the deferred fire fails closed on
any credential seam rather than under a substituted principal.
bound_execution_identity_for_fire
tai42_contract.app.facets.messaging.AppInteractions.bound_execution_identity_for_fire
async with binding execution_key’s live-grant identity for a receiver-less door fire.
A scheduled fire has no live caller, so the door stores the firing identity (the execution
key’s user_id and its per-mint fingerprint) at create and binds it here at fire, so a
run that async-parks can rebind its continuation and a to="caller" resume acts under the
same authority. Homed beside the door’s other kit-reachable seams so a backend plugin binds a
scheduled fire’s identity without importing the skeleton. Raises when the key no longer
carries authority — the fire fails closed, never under a substituted principal.
Parameters
resume_parked
tai42_contract.app.facets.messaging.AppInteractions.resume_parked
payload, or TAKE its waiting outcome when omitted.
With payload given it resumes the asking caller ask interaction_id and returns
the resumed run’s normalised outcome; with payload omitted it TAKES a finished
entry’s waiting outcome (kind="result") or re-raises a failed one as
ParkableRunFailedError. A live inline receiver, so the
resumed run’s terminal is returned inline rather than delivered out of band.
Parameters
cancel_parked
tai42_contract.app.facets.messaging.AppInteractions.cancel_parked
ids on the current run’s subject.
Each id is torn down through the one teardown seam (its run and every run it linked above it
close for good, delivering FAILED once to a door that started it); returns a
VisitOutcome naming the ids cancelled. An id outside
the run’s own parked list raises ParkedEntryGoneError
with nothing cancelled.
Parameters
ask
tai42_contract.app.facets.messaging.AppInteractions.ask
Ask-typed ask callable.
An in-process plugin asks a human without importing the skeleton:
await tai42_app.interactions.ask(question, ..., mode="async", expiry_at=...). The return shape is the Ask contract’s:
mode="sync" returns the typed answer, mode="async" returns a
SuspendedInteraction. Its full call signature is the Ask
Protocol’s, including the per-ask on_mismatch digression policy and
mismatch_notice retry text a channel-delivered ask carries. A facade
EXPOSURE of the skeleton helper through the already-typed Protocol — no new
ask semantics.
AppLifecycle
tai42_contract.app.facets.runtime.AppLifecycle
Members
on_startup
tai42_contract.app.facets.runtime.AppLifecycle.on_startup
func to run at process startup (usable as a decorator).
Parameters
on_shutdown
tai42_contract.app.facets.runtime.AppLifecycle.on_shutdown
func to run at process shutdown (usable as a decorator).
Parameters
on_reload
tai42_contract.app.facets.runtime.AppLifecycle.on_reload
reload_config).
For example, dynamic tool loaders that on_startup ran once.
Parameters
on_post_swap
tai42_contract.app.facets.runtime.AppLifecycle.on_post_swap
on_fleet_op_applied
tai42_contract.app.facets.runtime.AppLifecycle.on_fleet_op_applied
wait_until_ready
tai42_contract.app.facets.runtime.AppLifecycle.wait_until_ready
AppMonitoring
tai42_contract.app.facets.runtime.AppMonitoring
Members
register_monitoring
tai42_contract.app.facets.runtime.AppMonitoring.register_monitoring
builder is omitted.
Parameters
active
tai42_contract.app.facets.runtime.AppMonitoring.active
AppPresets
tai42_contract.app.facets.authoring.AppPresets
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.
Members
bind
tai42_contract.app.facets.authoring.AppPresets.bind
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
create
tai42_contract.app.facets.authoring.AppPresets.create
input_schema over
a base tool with no registered support is a loud error that persists nothing. The
caller-authorization tier fence is OFF — the registration-tier fence authorizes a
request principal at the HTTP doors; an in-process caller authorizes its own callers
and passes only the base tools it is entitled to author — while every content check
stays on.
Parameters
save_version
tai42_contract.app.facets.authoring.AppPresets.save_version
input_schema via the CARRY_FORWARD sentinel;
output_schema only when output_schema_provided is True). A body that
cannot bind is a loud error that commits nothing; the tier fence is OFF for the
reason create states.
Parameters
register_write_validator
tai42_contract.app.facets.authoring.AppPresets.register_write_validator
base_tool (one per base tool; duplicate registration raises).
A base-tool plugin calls this through the tai42_app handle when its tool
module loads. The validator runs on every write that persists a body —
create / save-version / rollback — and in the dry-run validate verdict,
so a body its base tool cannot accept is a loud 400 that never persists. A
base tool with no registered validator gets no extra check.
Parameters
register_input_schema_support
tai42_contract.app.facets.authoring.AppPresets.register_input_schema_support
base_tool ACCEPTS a per-preset input schema (one per base tool; duplicate raises).
A base-tool plugin calls this through the tai42_app handle when its tool
module loads. A preset that sets an input_schema over a base tool with no
registered support is a loud authoring error at the shared preset-authoring
chokepoint, never a silently-ignored schema.
Parameters
input_schema_support
tai42_contract.app.facets.authoring.AppPresets.input_schema_support
base_tool declared, or None if it declared none.
When None, the base tool’s typed schema is fixed.
Parameters
register_registration_tier
tai42_contract.app.facets.authoring.AppPresets.register_registration_tier
base_tool (one per base tool).
Governs create/save/rollback/rename; duplicate registration raises.
Default authoring is the presets’ own write action; a base tool with no
declaration keeps that default. A base tool declaring fenced requires the
admin fence to author a preset over it. The shared preset-authoring chokepoint
reads this and enforces it BEFORE any store write on every authoring door.
Parameters
registration_tier
tai42_contract.app.facets.authoring.AppPresets.registration_tier
base_tool declared, or None if it declared none.
When None, authoring keeps the presets’ default write action.
Parameters
get_active_versioned_body
tai42_contract.app.facets.authoring.AppPresets.get_active_versioned_body
(version, body) read TOGETHER in one query.
The version-aware sibling of store.get_active_body: it captures the active version
pointer and the body it points at atomically, so a consumer that needs the version beside
the body never risks a skewed second read across a concurrent activation. Raises
PresetNotFoundError for an unknown preset.
Parameters
used_by
tai42_contract.app.facets.authoring.AppPresets.used_by
name as a tool, sorted.
Computed over the active preset population (a body’s composed tool names intersected with
the population, self excluded), so it answers “which saved presets depend on this one” for a
rename/delete dependents pass. Raises
PresetNotFoundError for a name that is not a known
preset.
Parameters
register_seed
tai42_contract.app.facets.authoring.AppPresets.register_seed
tai42_app handle when its module loads.
The declared seeds are applied by the startup/reload seed applier — created
when absent, a preset already present left untouched. Declaring two seeds
under the same name raises loudly — a silent overwrite could drop one
plugin’s default under another’s.
Parameters
store
tai42_contract.app.facets.authoring.AppPresets.store
app.versioning.store (kind="preset").
AppSandboxes
tai42_contract.app.facets.execution.AppSandboxes
app.sandboxes).
Members
register_sandbox
tai42_contract.app.facets.execution.AppSandboxes.register_sandbox
Sandbox provider (decorator form, returning the class unchanged).
One provider backs the slot; a second registration is a conflict the runtime rejects loudly.
sandbox
tai42_contract.app.facets.execution.AppSandboxes.sandbox
None — status/introspection ONLY.
Never gate execution on this nullable read; acquire through require_sandbox, the every-door
guarantee (a None property is how per-consumer checks drift).
require_sandbox
tai42_contract.app.facets.execution.AppSandboxes.require_sandbox
SandboxUnavailableError (naming TAI_MCP_SANDBOX and
sandbox_module) when none is registered. EVERY consumer acquires through here.
sandbox_policy
tai42_contract.app.facets.execution.AppSandboxes.sandbox_policy
SandboxPolicy.
This is the plugin-reachable READ of the SAME policy the skeleton binds to the kit at the
session-create chokepoint.
Available REGARDLESS of whether a provider is registered (it reads operator
config, not a provider). Mirrors the ask / resolve_connection_auth
facade accessors that let an in-process plugin read a skeleton-resolved value
without importing the skeleton; a consumer building a policied spec reads the
network default and scrub_transcript here. Implemented in the skeleton,
which resolves the policy once and returns the SAME value it binds to the kit.
AppStates
tai42_contract.app.facets.states.AppStates
app.states).
The door-agnostic contract every door and tool reads and writes a subject’s document through.
The store takes a full StateSubject and refuses
anything less; subject resolution happens once per door, never here. Every write
door supplies a WriteOrigin carrying only what a
consumer knows — the platform completes it (door/actor/turn_id) at this
chokepoint, so the audit ledger is never optional or forgeable. While the states
component’s database is unbound every method raises
StatesNotConfiguredError (501), never an empty read.
Members
list_declarations
tai42_contract.app.facets.states.AppStates.list_declarations
get_declaration
tai42_contract.app.facets.states.AppStates.get_declaration
name, or None when none is declared.
Parameters
put_declaration
tai42_contract.app.facets.states.AppStates.put_declaration
NonAdditiveRedeclareError (erase the records
first), and removing a subject kind still present in records raises
DeclarationInUseError. Never a silent overwrite.
Parameters
delete_declaration
tai42_contract.app.facets.states.AppStates.delete_declaration
DeclarationInUseError when a consumer still binds it.
Parameters
stats
tai42_contract.app.facets.states.AppStates.stats
list_templates
tai42_contract.app.facets.states.AppStates.list_templates
get_template
tai42_contract.app.facets.states.AppStates.get_template
name, or None when none is stored.
The read a consumer’s own sibling document validates against.
Parameters
put_template
tai42_contract.app.facets.states.AppStates.put_template
replace required to overwrite an existing name).
Runs every registered attach validator over each live attachment before the write,
so a consumer’s data-dependent check still fires here; a raise leaves the stored
document untouched. Overwriting an existing name without replace raises
TemplateExistsError.
Parameters
delete_template
tai42_contract.app.facets.states.AppStates.delete_template
TemplateInUseError while it is still attached.
Parameters
list_attachments
tai42_contract.app.facets.states.AppStates.list_attachments
state, by template, or every attachment when both are None.
What the attachments listing and the Consumers tab read. Each row carries state,
template, path, parameters and declarations.
Parameters
attach
tai42_contract.app.facets.states.AppStates.attach
template on state at body.path, recomposing the effective schema in one transaction.
Stores the resolved parameters and declarations. Runs every registered attach validator before the write; a
raise refuses the door with the validator’s message. Overlapping fragments raise
AttachConflictError.
Parameters
update_attachment_declarations
tai42_contract.app.facets.states.AppStates.update_attachment_declarations
options is a per-operation directive bag passed to the reconcilers for THIS
operation only, never stored or served back (None is an empty bag).
Parameters
detach
tai42_contract.app.facets.states.AppStates.detach
read
tai42_contract.app.facets.states.AppStates.read
subject (resolving a fold to its canonical subject), or None when none exists.
An unknown person or a target mismatch is a refusal, never an empty document.
Parameters
replace
tai42_contract.app.facets.states.AppStates.replace
subject’s whole document with data and return the new record.
Parameters
merge
tai42_contract.app.facets.states.AppStates.merge
patch into subject’s document and return the new record.
Parameters
apply
tai42_contract.app.facets.states.AppStates.apply
subject’s document under the effective schema.
Refuses a whole-path write over a composing path
(RegimeViolationError) before the ledger insert,
stamps _trace under a traced attachment, and records one state_writes row with
the touched paths and the completed origin. A replayed op_id returns
applied=False without re-writing; guarded ops land in skipped.
Parameters
eval_template_jq
tai42_contract.app.facets.states.AppStates.eval_template_jq
input-purpose template_jq program name for subject and return its value.
The program’s jq runs over the subject’s record, params supplying
its declared parameters. name resolves across the state’s attached templates
(unqualified → the declaring template; <attachment>.<name> → that attachment’s
template). An unknown name is a StateNotFoundError; an
ambiguous unqualified name, an update-purpose name, an undeclared param or an
evaluation failure is a ValueValidationError. A read;
no write is recorded.
Parameters
apply_template_jq
tai42_contract.app.facets.states.AppStates.apply_template_jq
update-purpose template_jq program name to subject.
Its jq maps the record subtree (its .) with $input bound to a template-relative op
batch, rebased under the attachment path and applied through the same chokepoint as
apply — so regimes, the
composing-shape guard, trace stamping and op_id idempotency all hold. name
resolves as for eval_template_jq. An unknown name is a
StateNotFoundError; an ambiguous unqualified name, an
input-purpose name, an evaluation failure or a wrong-shaped return is a
ValueValidationError.
Parameters
erase
tai42_contract.app.facets.states.AppStates.erase
subject’s record, recording the write.
Parameters
fold
tai42_contract.app.facets.states.AppStates.fold
subject into into and return the resulting canonical document.
mode decides how the documents combine. A self-fold, a cycle, a conflicting re-fold,
or a merge whose result fails the schema raises
SubjectFoldError; a retried fold to the same target is a quiet no-op.
Parameters
list_subjects
tai42_contract.app.facets.states.AppStates.list_subjects
state (optionally one kind).
{"subjects": [...], "next_cursor": <cursor|None>}.
Parameters
search
tai42_contract.app.facets.states.AppStates.search
filters.
{"matches": [...], "next_cursor": <cursor|None>}.
Parameters
writes
tai42_contract.app.facets.states.AppStates.writes
subject, newest first.
The items (each a write with its completed origin and touched paths) plus the
next_cursor that pages the trail like list_subjects/search page
theirs (the last row’s id when the page is full, else None).
Parameters
prune_expired
tai42_contract.app.facets.states.AppStates.prune_expired
retention_days and return the per-state deletion counts.
context
tai42_contract.app.facets.states.AppStates.context
StateContext the current door deposited.
None outside a door (an api write completes from the request principal instead).
register_consumer_lister
tai42_contract.app.facets.states.AppStates.register_consumer_lister
kind (flow / hook / schedule / agent).
A plugin calls this through the tai42_app handle when its module loads;
consumers unions every registered lister. Registering two listers for one
kind raises loudly.
Parameters
consumers
tai42_contract.app.facets.states.AppStates.consumers
state — the union of every registered consumer lister — for the Consumers tab.
Parameters
register_template_seed
tai42_contract.app.facets.states.AppStates.register_template_seed
tai42_app handle when its module loads. The
startup/reload seed applier creates it when absent and leaves a template already
present untouched. Declaring two seeds under one name raises loudly.
Parameters
register_attach_validator
tai42_contract.app.facets.states.AppStates.register_attach_validator
tai42_app handle when its module loads. The
validator receives the template document, an attachment’s declaration values, and the
state’s effective schema, and RAISES to refuse; it runs before every attach,
update_attachment_declarations and put_template(replace=True) write, so a
consumer’s checks fire at the platform’s declarations doors, the States page
included.
Parameters
register_attach_reconciler
tai42_contract.app.facets.states.AppStates.register_attach_reconciler
tai42_app handle when its module loads. The
reconciler receives a AttachReconcileContext — the
template, the operation, the previous and new declarations, the attach options, and a
record door bound to the state — inside every attach and
update_attachment_declarations write, after the validators and before the write. It
RAISES to refuse the attach (naming the records the new declarations orphan) or
writes resolutions through the context’s record door and returns, letting the attach
commit with those writes.
Parameters
AppStorage
tai42_contract.app.facets.execution.AppStorage
app.storage).
Members
register_storage
tai42_contract.app.facets.execution.AppStorage.register_storage
Storage provider; usable bare or as a decorator factory.
resource_manager
tai42_contract.app.facets.execution.AppStorage.resource_manager
AppSubApp
tai42_contract.app.facets.runtime.AppSubApp
Members
mcp_sub_app_router
tai42_contract.app.facets.runtime.AppSubApp.mcp_sub_app_router
AppToolMeta
tai42_contract.app.facets.authoring.AppToolMeta
app.tool_meta) — the organizational overlay over any live tool.
The overlay is a folder tree plus a per-tool row (display name, folder
placement, tags, badges, a hidden override).
store is the ToolMetaStore view the routes
and the preset lifecycle cascade read and write. patch is the in-process edit
seam beside the HTTP PATCH door.
Members
store
tai42_contract.app.facets.authoring.AppToolMeta.store
patch
tai42_contract.app.facets.authoring.AppToolMeta.patch
folder_id is a loud error). Only the
arguments given are written: folder_id places the tool, and a tags list
REPLACES the whole tag set (array values are set replacements, not merges).
tags=None leaves the tag set untouched; folder_id=None leaves the
placement untouched.
Parameters
AppVersioning
tai42_contract.app.facets.authoring.AppVersioning
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.
Members
store
tai42_contract.app.facets.authoring.AppVersioning.store
AppWebhookVerifiers
tai42_contract.app.facets.messaging.AppWebhookVerifiers
app.webhook_verifiers).
Members
register
tai42_contract.app.facets.messaging.AppWebhookVerifiers.register
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.messaging.AppWebhookVerifiers.get
DeclaredRouteMetadata
tai42_contract.app.facets.routing.DeclaredRouteMetadata
/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
PendingMessage
tai42_contract.app.facets.messaging.PendingMessage
AppConversations.pending_messages returns, so a body running inside a
turn can learn a newer message is waiting and stop before an irreversible step. message_id
is the accepted record’s id, text its verbatim inbound text, accepted_at the epoch
seconds it was accepted at (the thread index’s own score). Frozen.
Attributes
RouteAction
tai42_contract.app.facets.routing.RouteAction

