Host-owned mapping from manifest provider names to trusted builders.
A manifest can select a bounded provider name and JSON configuration; it
cannot register a module, function, callback, command, or code URL. Builders
receive a path-free application identity, requested workflow or mission
destination, building owner, and installed limits. Acquisition returns a
normalized provider build with one or more capabilities, an optional safe
snapshot, and an optional idempotent
close function. A close function must return exactly :ok; any other return,
exception, or exit is a provider-cleanup failure. The Kernel still attempts
every registered close function and may replace the run outcome with
:provider_cleanup_error.
Trusted staged builders enforce a global preparation barrier. Every selected provider first performs pure selection checks, then every provider completes non-secret local preflight, and no provider is acquired before the union of declared credentials has been resolved exactly once.
When that resolution happens differs by caller, and the difference is the
authority each one has. An active command resolves at phase-8 step 5 from its
sealed declarations, before any provider callback runs, and supplies the map;
resolve_credentials/2 is not called again below that point. Direct embedding
has no sealed declarations to derive a union from before preparation, so it
keeps resolving here, from what preparation reported, with the synchronous
semantics its caller selected. Active command assembly bounds preparation,
preflight, and acquisition by its shared run deadline; preflight releases
share the provider-cleanup budget.
Preparation also freezes
the provider's data_class and accepts_data policy so run assembly can
reject an incompatible information flow before preflight or credentials.
A builder bound to the data policy declared by its sealed
PtcRunner.Kernel.ProviderDescriptor cannot contradict it: preparation
returning a different data_class or set of accepted classes than phase 5
admitted, and than sink authorization used, fails with
:provider_declaration_mismatch before preflight, credentials, or
acquisition. Explicit embedding builders registered without a declared policy
have no such declaration, so their preparation remains authoritative for
them.
A staged provider may additionally require or provide a bounded, code-owned
acquisition service. Services pass opaque values only between selected
trusted providers after the barrier; they never enter Lisp environments,
connector snapshots, traces, or result artifacts.
There are no implicit built-ins. CLI applications receive exactly the
aliases in their host installation, while trusted Elixir embedding can pass
any explicit builder map. The registry also freezes the installed limit
ceilings used when manifests are loaded, so every frontend applies the same
host authority rather than reconstructing it in CLI-specific options.
Builder exceptions are contained at their current lifecycle phase.
A staged acquisition context's owner is the private signal owner for that
provider's resource scope. Any process or port root started by an acquisition
must monitor that owner and synchronously call
PtcRunner.Kernel.ResourceRegistrar.register_root/1 from the root's init
callback before its start operation returns. The registrar's private
controller forwards registration into the scope's authoritative cleanup
owner. Ports must be owned by a registered process. Registration after start
returns is unsupported. A root
retaining an unsettled OAuth release or persistence fence may call
PtcRunner.Kernel.ResourceRegistrar.handoff_root/2 only after it has stopped
accepting work and the terminal operation has a bounded self-owner or
adopter.
provides is not a general marker. It names an acquisition service, and
normalize_build/2 requires the acquired build to export exactly the
services declared here, so a provider that declares one without exporting it
fails with :invalid_provider_build. Use a dedicated field for
provider-kind facts, as workflow_llm? does.
Summary
Types
A zero-arity cleanup function returned by a provider builder.
Functions
Builds one entry through all three lifecycle phases.
Idempotently releases private host authority retained by this registry.
Creates a registry from explicit staged builders keyed by provider name.
Marks a trusted builder as staged, optionally bound to its declared policy.
Checks the complete inert registry shape accepted by the constructor.
Types
@type acquire() :: (credential_values() -> {:ok, built_provider()} | {:error, term()}) | (credential_values(), acquisition_services() -> {:ok, built_provider()} | {:error, term()})
@opaque authority_owner()
@type build_context() :: %{ optional(:deadline) => PtcRunner.Kernel.Deadline.t(), optional(:deadline_ms) => integer(), optional(:resource_registrar) => PtcRunner.Kernel.ResourceRegistrar.t(), application_content_digest: binary(), destination: :workflow | :mission, owner: pid(), limits: PtcRunner.Kernel.Limits.t(), installed_limits: PtcRunner.Kernel.Limits.t() }
@type built_provider() :: %{ capabilities: [PtcRunner.Kernel.Capability.t()], snapshot: map() | nil, close: close() | nil, data_class: :normal | :private_inspection, accepts_data: [:normal | :private_inspection], exports: %{optional(atom()) => term()} }
@type close() :: (-> term())
A zero-arity cleanup function returned by a provider builder.
Declared here rather than borrowed from the internal cleanup module, so the public contract does not depend on an implementation detail's documentation.
@type context() :: %{ optional(:deadline) => PtcRunner.Kernel.Deadline.t(), optional(:deadline_ms) => integer(), optional(:resource_registrar) => PtcRunner.Kernel.ResourceRegistrar.t(), application_content_digest: binary(), destination: :workflow | :mission, owner: pid(), limits: PtcRunner.Kernel.Limits.t(), installed_limits: PtcRunner.Kernel.Limits.t(), provider: binary() }
@type credential_resolver() :: ([binary()] -> {:ok, credential_values()} | {:error, term()})
@type prepared() :: %{ credential_names: [binary()], data_class: :normal | :private_inspection, accepts_data: [:normal | :private_inspection], requires: [atom()], provides: [atom()], workflow_llm?: boolean(), workflow_llm_route: nil | %{source: binary(), installation_revision: binary(), default: boolean()} | %{ source: binary(), installation_revision: binary(), default: boolean(), max_calls: pos_integer() | nil }, preflight: (-> {:ok, acquire()} | {:ok, acquire(), (-> :ok | {:error, term()})} | {:error, term()}) }
@type registry_builder() :: staged_builder()
@type staged_builder() :: {:staged, (map(), context() -> {:ok, prepared()} | {:error, term()}), PtcRunner.Kernel.ProviderDescriptor.data_policy() | nil}
@type t() :: %PtcRunner.Kernel.ProviderRegistry{ authority_owner: authority_owner() | nil, builders: %{required(binary()) => registry_builder()}, credential_resolver: credential_resolver(), installed_limits: PtcRunner.Kernel.Limits.t() }
Functions
@spec build(t(), binary(), map(), build_context()) :: {:ok, built_provider()} | {:error, term()}
Builds one entry through all three lifecycle phases.
Run assembly uses the individual phase functions so the barrier spans every
selected provider. This convenience path remains useful for embedding and
focused provider tests. It rejects registrar-backed contexts because scoped
acquisition requires PtcRunner.Kernel.ProviderAcquisition's complete
multi-provider lifecycle.
@spec close(t()) :: :ok
Idempotently releases private host authority retained by this registry.
Creates a registry from explicit staged builders keyed by provider name.
@spec staged( (map(), context() -> {:ok, prepared()} | {:error, term()}), PtcRunner.Kernel.ProviderDescriptor.data_policy() | nil ) :: staged_builder()
Marks a trusted builder as staged, optionally bound to its declared policy.
The preparation callback must be side-effect free. Its returned preflight
callback may perform only non-secret local checks; the acquire callback is
the first phase allowed to use resolved credentials or open a provider.
Optional :data_class and :accepts_data fields default to normal-only and
must exactly match the acquired build. A builder bound to a declared policy
must also prepare exactly that policy; an installed catalog projects one from
the sealed descriptor of every builder it selects.
Checks the complete inert registry shape accepted by the constructor.