Ports
The interfaces you implement. Psych Runtime calls back only through these.
Store
protocol
class Store(*args, **kwargs)Persistence, as narrow as an append-only log can be.
Every method here is expressible as one conditional write or one bounded read. An implementation that needs a transaction to satisfy this contract has misread it.
BlobStore
protocol
class BlobStore(*args, **kwargs)Content-addressable-by-caller storage for payloads too large for a log
record, put/get/delete by BlobKey, with range reads.
Every method is one operation against one object: no listing, no
versioning, no multipart upload management exposed to a caller. The three
adapters (psych_runtime.store.blob_memory, psych_runtime.store.blob_fs,
psych_runtime.store.blob_s3) all pass psych_runtime.store.blob_contract, the same
discipline psych_runtime.store.contract applies to Store.
MemoryStore
protocol
class MemoryStore(*args, **kwargs)Durable facts across Runs, isolated by tenant and end user.
Not conversation history (that is the log) and not semantic retrieval (that
is explicitly refused; DESIGN.md §15 and this package's README). A
MemoryStore is a flat, small collection of facts per end user, recalled
in full every time: there is no ranking, no similarity search and no
partial retrieval, because those are exactly the features that would make
this module the RAG framework Psych refuses to own.
ModelClient
protocol
class ModelClient(*args, **kwargs)What Psych needs from a model provider.
One method. Everything else Psych does with models, it does itself.
Policy
protocol
class Policy(*args, **kwargs)Authorization, implemented by the consumer against their own identity system.
Psych calls this; it never decides. An implementation that raises is treated as a denial rather than as a crash, because an authorization system being down should stop work rather than let it through, and should not take the Run's whole log with it.
SecretResolver
protocol
class SecretResolver(*args, **kwargs)Resolves a credential name to a value, for exactly the Scope asking.
An implementation should resolve fresh, or from its own short-lived cache, rather than memoising forever: DESIGN.md §10.2's "fresh at every turn boundary" rule for tools applies here too, since a credential a consumer just revoked must stop working on the next resolve rather than the next process restart.
Telemetry
protocol
class Telemetry(*args, **kwargs)The root of the tree. Every Run's telemetry starts here.
An implementation must never let a failure of its own escape into the
caller: wrap an untrusted implementation in GuardedTelemetry rather
than relying on callers to guard themselves.
Sandbox
protocol
class Sandbox(*args, **kwargs)Runs one model-written program in isolation and reports the result.
DESIGN.md §18 rejects in-process execution outright: no implementation
of this port may run the program in the calling process. Process
isolation (psych_runtime.sandbox.subprocess) is the floor; a container
(psych_runtime.sandbox.container) is available for consumers who need more.
PriceResolver
protocol
class PriceResolver(*args, **kwargs)Price resolution is a port, not a hardcoded table.
DESIGN.md §13.2: the shipped table is a convenience with a known staleness problem. A consumer reconciling against their real provider bill supplies their own, and theirs is authoritative.
An implementation returns None for a model it does not know. It must not
invent a rate, and it must not return zeros: compute_cost turns None
into a recorded cost=None, which is the honest answer.
EgressPolicy
protocol
class EgressPolicy(*args, **kwargs)Decides whether one outbound request may proceed.
Called once per request, with enough context for a real decision: which tenant is asking, and where the request is headed. The seam calls this before opening the connection, not after, so a denial never touches the network.
An implementation should be fast and free of side effects: it runs on every outbound call Psych makes, including the read side of a streamed model response, so anything slow here is a latency tax on everything.