> ## Documentation Index
> Fetch the complete documentation index at: https://ctrlrun.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# PostgresStateStore

> Approvals, effects and evidence in a Postgres schema (SPEC-v0.6 §4).

`ctrlrun.postgres.PostgresStateStore` — class, defined at `src/ctrlrun/postgres.py:218`

```python theme={null}
from ctrlrun.postgres import PostgresStateStore
```

Needs the `postgres` extra: `pip install "ctrlrun[postgres]"`. Importing it without that raises `MissingDependency` carrying the install command.

```python theme={null}
class PostgresStateStore
    def __init__(url: str, *, clock: Callable[[], datetime] = _utc_now, schema: str = 'public')
```

Approvals, effects and evidence in a Postgres schema (SPEC-v0.6 §4).

One connection per thread, as `SQLiteStateStore` does: `psycopg` connections are not
thread-safe, and the thread-local shape is the one `close()` is already specified against
(§2.7).

**A connection outlives the thread that opened it, and that is a real limit worth stating.**
A host running agents on a *bounded, recycled* thread pool is fine -- the same threads keep
reusing the same connections. A host that starts a fresh thread per unit of work accumulates
one connection per thread that ever touched the store, and Postgres connections are far
scarcer than SQLite file handles: `max_connections` defaults to 100. `close()` releases every
one, so the mitigation is to close a store you are done with. The conformance suite met this
for real -- ninety-six connections across twelve rounds of eight threads -- and the failure
surfaced in a case that had nothing to do with it.

No pool ships. An operator may put pgbouncer in front in **transaction** mode, and it works
because this store holds nothing session-scoped: no advisory lock, no temp table, no prepared
statement it depends on surviving, no `SET`. That is the second reason §4.2.1 rejected
advisory locks, and it is a property worth keeping deliberately rather than by luck.

## Next

* [Python API index](/reference/api/index).
* [Get started](/get-started/quickstart) · [Why](/why).


## Related topics

- [Running on Postgres](/postgres.md)
- [Move from SQLite to Postgres](/cookbook/sqlite-to-postgres.md)
- [Install](/get-started/install.md)
- [Claims](/CLAIMS.md)
- [Python API](/reference/api/index.md)
