agent execution
One request. Many steps. One durable run.
Psych turns an agent request into work a Worker can execute, pause, recover, and inspect. Your application keeps control of where it runs and what it can reach.
the path a request takes
Two processes, one database.
The handler returns as soon as the Run is admitted. The Worker does the slow part in its own process, and the two share a Store and nothing else.
Validate the request, save it, and return its ID.
The request can returnClaim the run, call the model and tools, and record each result.
Scale workers separatelyone log per run
Three ports in. One log out.
You supply a model client, tools and a store. Psych folds what they do into one append-only log per Run, and everything you read back is derived from it.
The report, the live stream, the status a screen shows and the step a crashed workflow resumes from are all computed from that log. Nothing is stored twice, so no two reads disagree.
inside the package
What is yours, and what is Psych’s.
What to implement, and what to import. Dependencies point inward, and an import linter enforces it.
your app
Routes, auth, cron, queue consumers. Turn a request into a Scope and call dispatch().
psych_runtime
The whole public surface. Every type you can hold is exported here, and a test fails when one is not.
runtime/
Worker, supervisor, Attempt, lease, agent loop, workflow engine, suspend, interrupts, subagents.
tools/ model/
Per-turn resolution, access narrowing, the four tool executors, the model client, pricing, one egress seam.
core/
Spec models, Version hashing, Record types, the pure reducer. No IO, no clock, no randomness.
your infra
Store, BlobStore, Sandbox, Telemetry, SecretResolver, Policy. Ports, with adapters in the box.
the boundary
Left to your application, on purpose.
You already have each of these. A library that brought its own would argue with yours.
| Not in Psych | What it does instead |
|---|---|
| An HTTP server or any transport | Functions you call from your own routes. |
| Auth, users, orgs, roles | A Scope on every call and a Policy port you implement. |
| A database of its own | A Store port, four adapters, one contract suite. |
| A scheduler or timer | You call dispatch(). A Run waiting on a clock suspends as external. |
| A UI | status() returns a serialisable RunStatus a screen can draw. |
| Prompt management, evals | Instructions and skills live in the Spec you version. |
| A vector store or retrieval | Nothing. You have one, and it belongs behind a tool. |
| Budgets and model routing | Metering yes, enforcement no. Fallback models yes, a router no. |