Psych Runtime
A Python library for running AI agents inside your application. It runs an agent's tool calls, saves a Run's progress as it goes, pauses for approval before the calls you choose, and records everything a Run did so you can read it back. You supply the model, the tools and the database.
psychruntime.com · Documentation · Browser demo · Changelog
Status: pre-alpha. The public API changes between minor releases, and
every breaking change is in CHANGELOG.md before it ships. Names scheduled
for removal warn for at least one minor release first. The PyPI badge above
shows the current release.
What it looks like
One agent, one tool, offline. The test suite runs this file on every commit.
import asyncio
import psych_runtime
from psych_runtime.testing.fake_model import FakeModel
async def lookup_order(order_id: str) -> dict[str, str]:
"""Look up an order by its id."""
return {"order_id": order_id, "status": "shipped"}
spec = psych_runtime.AgentSpec(
name="support",
instructions="Help the customer with their order.",
model=psych_runtime.ModelRef(model="fake-standard"),
tools=(psych_runtime.CodeTool(name="lookup_order"),),
)
async def main() -> None:
model = (
FakeModel()
.turn(text="Checking.", tool_calls=[("lookup_order", {"order_id": "A1"})])
.turn(text="A1 has shipped.")
)
async with psych_runtime.session(model, tools=[lookup_order]) as s:
view = await s.ask(spec, "where is order A1?")
print(view.text) # A1 has shipped.
report = await psych_runtime.report(s.store, view.run_id)
print(report.totals.usage, report.totals.cost)
asyncio.run(main())
A1 has shipped.
input=0 output=0 cache_read=0 cache_write=0 cache_write_1h=0 reasoning=0 None
The tool ran: report.tool_calls says so, from the log. Cost is None
because no price table was passed; it is never rounded to zero.
Run it
Python 3.12 or newer. The package depends on pydantic and httpx.
pip install psych-runtime
psych new demo && cd demo && python main.py
Expected:
No OPENAI_API_KEY set, so this run uses the fake model.
Order A1 has shipped with DHL.
completed | 1 turn, 1 tool call | 0 tokens | cost None
Set OPENAI_API_KEY and the same file calls a real provider. psych new
writes a main.py you own; the command line never runs an agent for you.
- The distribution is
psych-runtime, the import ispsych_runtime, the command ispsych. session()defaults to an in-memory store that dies with the process. Pass aPostgresStore,MySQLStoreorDynamoDBStorefor anything that must survive a restart.- Get started walks through the file above, then a real model, a second tool, and reading a Run back.
What it handles
| Guide | |
|---|---|
Recover a run after a worker stops. Another worker claims the expired lease, replays the log and carries on. A call the dead worker left open is settled unknown, not re-run, unless the tool is registered safe_to_retry=True. Needs a durable store. |
Persist and recover runs |
| Require approval for selected tool calls. By name or by annotation. A matching call suspends the Run with its exact arguments and waits for a decision from any process. | Approvals |
| Connect Python functions, HTTP endpoints, MCP servers and A2A agents as tools, resolved fresh every turn. | Code tools, MCP |
Inspect a run: status for a screen, the answer with its work, a report with tool calls, usage and cost, or the raw log. Every read takes a scope=. |
Reading a Run |
| Track token usage and cost per model call, split by cache state, with provider-versus-estimated provenance. | Pricing |
Serve multiple tenants from one process: a Scope on every record and every outbound call. |
Multi-tenancy |
Where it runs
Psych is a dependency you import, not a service you deploy. Your request
handler admits a Run and returns; a Worker in a process of yours claims it
and executes it; the two share your database and nothing else.
Psych brings no HTTP server, auth, user model, scheduler, UI, prompt library,
eval framework, vector store, budget enforcement or model router. Your
application already has those, and a library that brought its own would
argue with them. psych new api --template fastapi shows the split.
Limitations worth knowing before you build on it:
- Only what you register is safe to retry. After a crash, a tool call
recorded as started is settled
unknownunless it was registeredsafe_to_retry=True. Psych does not make an external side effect repeatable; it refuses to guess. - A sandbox says what it proved, not what it hopes. Every backend grades ten guarantees per execution and reports the isolation level it actually reached; output produced under weaker terms than were requested is withheld rather than returned. A plain subprocess limits a program and does not isolate it, and it says so. Namespaces and containers reach a kernel boundary; no local backend reaches one on macOS or Windows, where a request for full isolation is refused instead of approximated.
- Cost is only as good as its source.
Cost.sourcedistinguishes an amount returned by the provider from one estimated using the bundled, dated price snapshot or your override. A model with no known price recordscost=None. Token totals carry their ownusage_source; missing provider usage is never presented as a measured zero. - Provider support is the OpenAI-compatible chat API. One client reaches
OpenAI and any gateway that speaks the same protocol; anything else is a
ModelClientyou implement.
The example console
git clone https://github.com/psych-systems/psych-runtime && cd psych-runtime
docker compose up --build # then http://localhost:3000
examples/playground/ is an application
built on the library: publish an agent, talk to it, watch the log, read the
report. It supplies the HTTP server and the UI Psych does not. It is an
example, not a hardened service; do not put it on the public internet.
For coding agents
The repository ships 26 skills, one per feature, in
.agents/skills/. Give your coding agent this instruction:
Read https://raw.githubusercontent.com/psych-systems/psych-runtime/main/.agents/skills/psych/SKILL.md
and follow it to add Psych to this project.
psych skills install copies them into a project.
Documentation
psychruntime.com/docs is generated from
this repository: the API reference from psych_runtime.__all__, the guides
from the skills above, the changelog and design notes copied verbatim. The
build fails when any page disagrees with its source.
DESIGN.md, the settled design.docs/design-notes/, why each area is shaped the way it is.docs/api.md, the public API with a worked example the test suite runs.docs/deployment.md, what a deployment is responsible for: scope, secrets, sandboxes, retention.
Contributing, support and security
CONTRIBUTING.md: what is welcome, how to set up, and what a change has to pass.- Issues for bugs and questions. Most bugs reproduce against the fake model with no provider and no network; a failing test beats a description.
SECURITY.md: report vulnerabilities privately through the advisory form, never as a public issue.
Development
uv sync --all-extras --group dev
scripts/dev-services.sh start # real Postgres, MySQL and DynamoDB Local
scripts/check.sh # ruff, mypy --strict, import-linter, generated docs, three test layers
Licence
Apache-2.0. See LICENSE, and NOTICE for the one third-party attribution the package carries.
Metadata
Release files for psych-runtime 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| psych_runtime-0.1.2.tar.gz | 3.1 MB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| psych_runtime-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 4.0 MB
Release files / psych_runtime-0.1.2.tar.gz
| Download URL | psych_runtime-0.1.2.tar.gz |
|---|---|
| Size | 3.1 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c69cc16c3721c07eb371b38e00a4b90a55ae2056cd1d58b35f28d9aee9ee053c
|
|
BLAKE2b-256 checksum How to use checksums |
e20599d9b853ad4ea05721fb515c5c72bc36d4be49f439111d512cc3d1e80dd6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 13, 2026.
Transparency logRelease files / psych_runtime-0.1.2-py3-none-any.whl
| Download URL | psych_runtime-0.1.2-py3-none-any.whl |
|---|---|
| Size | 871.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d087e78938520ea656d47b793eeed0cbc25589a051fd9c1a0e0e2f6d667318a9
|
|
BLAKE2b-256 checksum How to use checksums |
2898c934ef694270a2f1d9246c7203a5a492fbeba47629f64586d8ab7018af5c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 13, 2026.
Transparency logSecurity for psych-runtime 0.1.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for psych_runtime-0.1.2.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 13, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.