agentos-ledger-client
Canonical AgentOS State Ledger client, hash-chain verification, and content-addressed blob storage.
Features
- Advisory-Locked Journal Appends: Uses canonical
GLOBAL_CHAIN_LOCK_ID = 0x4C454447to serialize concurrent writers and eliminate silent chain forks. - SHA-256 Hash Chaining: Verifiable hash chain where
integrity_hash = sha256(previous_hash + payload_json). - Envelope Digest: Secondary actor-bound digest
sha256(event_type + actor_id + actor_type + on_behalf_of + payload_json)ensuring tamper-evident provenance. - Content-Addressed Blob Storage: Tiered binary blob storage with deduplication:
- Payloads $\le$ 1MB stored inline (
BYTEA). - Payloads $>$ 1MB stored in Google Cloud Storage (
gs://...).
- Payloads $\le$ 1MB stored inline (
- Complete Schema Definitions: Canonical event namespace constants for tasks, goals, iam, approval, and rlagt events.
- Lightweight Dependencies: Standard library +
asyncpg. Optional GCS client support.
Installation
pip install agentos-ledger-client
That is the whole thing. It is on PyPI, so there is no index to configure, no credential to obtain, and nothing to do differently on a laptop, in CI, or inside an AgentOS execution sandbox — PyPI is already reachable from all three.
Blobs over 1MB need Google Cloud Storage; at or under 1MB they are stored inline as BYTEA and nothing external is required:
pip install "agentos-ledger-client[gcs]"
As a dependency, declare it the ordinary way and pin the series:
dependencies = [ "agentos-ledger-client>=0.1,<0.2" ]
Versions
Releases are cut automatically and only when the code changes. The
build asks PyPI for the highest 0.1.x, compares that release's
contents with the tree, and publishes 0.1.<n+1> only if they differ —
so a version number always means the same bytes, and a run of builds
that did not touch this package produces no releases at all.
>=0.1,<0.2 therefore resolves to the newest build of the current
series. The series moves to 0.2 only for a breaking change, which is
the one judgement nobody automates.
Published from agent_os_refactor_dev alone. Other branches never
publish, so a version cannot mean two different things depending on
where it was built.
If you are changing this package — person or agent — change the
code and stop there. Do not set __version__: scripts/ci/publish_ledger_client.py
writes it, after reading what PyPI already has, and a hand-set number
either collides with one that is taken or is overwritten. A PyPI
version is burned forever, so a collision is not recoverable.
Raise it explicitly if you break the public API, since moving the
series is the one decision here that is not automatic. The full rules
are in CONTRIBUTING.md under Releasing agentos-ledger-client.
Quick Start
import asyncpg
from agentos_ledger_client import (
chain_hash,
GLOBAL_CHAIN_LOCK_ID,
append_event,
store_blob,
read_blob,
)
async def example(conn: asyncpg.Connection):
# Store blob
ref = await store_blob(conn, b"example payload", content_type="text/plain")
print(ref.sha256, ref.storage_backend)
# Append ledger event
res = await append_event(
conn,
event_type="task.created",
payload={"title": "Test task", "blob_sha256": ref.sha256},
actor_id=my_actor_id,
actor_type="independent_agent", # see the table below
)
print(res["event_id"], res["integrity_hash"])
actor_type
The CHECK constraint admits seven values. Every event says who caused
it, and "who" is the question the chain exists to answer — an event
attributed to the wrong kind of actor is not a cosmetic error.
| value | the actor |
|---|---|
human |
a person, acting directly |
shca |
a person's assistant, acting for them |
goal_orchestrator |
the orchestrator that plans and drives a goal |
executor |
a sandboxed run doing the work |
verifier |
the checker that judges a run's criteria |
independent_agent |
an agent acting on its own account |
system |
no actor — scheduled work, reapers, migrations |
Reach for system last. It is the value that means nobody is
accountable for this, and it is easy to default to when the real actor
is simply inconvenient to thread through. On a live deployment the
distribution is roughly goal_orchestrator 28%, system 28%, human
23%, shca 16%, the rest a long tail — and some of that system share
is events whose real actor was known and dropped.
This README previously listed only the first two and the last two,
which was the state of the constraint when the package was extracted
and has been wrong since. goal_orchestrator, the most common value of
all, was missing from the documentation while being the most written to
the table.
actor_id is UUID NOT NULL and actor_type is constrained to the four
values above — a consumer whose actors are strings ("ecommerce-sim")
needs a stable UUID per actor and must pick one of the four types.
Creating the tables
from agentos_ledger_client import init_schema
await init_schema(conn) # idempotent; safe in a test fixture
Checking it against your own database
The suite that verifies this client ships inside it, so you can run it
where it matters — against the Postgres you intend to use, on your
Python, without cloning pwt_agent_os.
pip install "agentos-ledger-client[test]"
pytest --pyargs agentos_ledger_client
No database setup is required. The [test] extra brings pgserver,
a real PostgreSQL shipped as a wheel, and the fixtures start one and
tear it down. To point the suite at a server you already have, set
DATABASE_URL instead — it is used when reachable and ignored when not,
so a stale value degrades to a skip rather than a confusing error.
Why bother. What you share with AgentOS is a hash-chained table. A
schema disagreement does not announce itself as "the schema differs" —
it surfaces later as a chain that will not verify, by which point the
rows exist. This suite builds the schema from the shipped schema.sql
on an empty database, appends a chained event, and verifies it.
It is not a hypothetical check. schema.sql shipped a CHECK on
actor_type that refused goal_orchestrator, executor and
verifier — 29% of the events on a live deployment — because it was
copied from the first migration and two later ones widened it. AgentOS
never noticed: its own tables come from migrations/, not from this
file. The first person to execute it would have been a consumer.
Requires Python 3.12: pgserver publishes cp312 wheels and no sdist.
The library itself has no such constraint at runtime, but the project
declares 3.12 because that is the only version it is tested on.
Metadata
Release files for agentos-ledger-client 0.1.1
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 | |
|---|---|---|---|---|
| agentos_ledger_client-0.1.1.tar.gz | 49.2 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| agentos_ledger_client-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 98.7 kB
Release files / agentos_ledger_client-0.1.1.tar.gz
| Download URL | agentos_ledger_client-0.1.1.tar.gz |
|---|---|
| Size | 49.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1ad1487598d15a479534d4d791a585814f026b707617f8d888aeaafaa4bb88a3
|
|
BLAKE2b-256 checksum How to use checksums |
f9fc036922a1e34ec32c9c2f6a67d8e34470bebe67b0e9cdcf2adbf7f6bbbbb4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.15
|
Release files / agentos_ledger_client-0.1.1-py3-none-any.whl
| Download URL | agentos_ledger_client-0.1.1-py3-none-any.whl |
|---|---|
| Size | 49.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8c409c302a33453f632b779711ebd367a87d022e6f3a3b929ca86d731e40b84d
|
|
BLAKE2b-256 checksum How to use checksums |
679ecc6a23df098a94db6963843b13362e1ee823bb1bdafdc44192a6924bc967
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.15
|
Security for agentos-ledger-client 0.1.1
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A 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.