papeete-actor
Conformance gates for the Papeete ecosystem contracts.
papeete-actor lint-card papeete-actor.yaml… papeete-actor-card/v1
papeete-actor lint-message --issue-body inter-agent-message/v0
papeete-actor lint-publication REPO… publication/v2
papeete-actor check --workspace DIR the cross-card join
papeete-actor contracts which contract versions this build enforces
pip install papeete-actor
What it enforces
An actor in this ecosystem is one repo, one human+agent pair, one mailbox, one card. The card —
papeete-actor.yaml at the repo root — declares five things, and each has exactly one owner:
| Section | Says | Owned by |
|---|---|---|
offers |
what I can be asked to do | me; the caller decides whether to ask |
releases |
the versioned artefacts I ship, and what announces each | me |
publications |
facts I emit — means (prose) and shape (payload schema) |
me |
subscriptions |
facts I pull, and what I do about them | me, about someone else's publication |
dependencies |
which actors I am interested in, at what ref — never which of their artefacts | me |
Those four downstream/consumer sections are two kinds crossed with two directions — state
(versioned, resolved at a pin, latest wins) in releases/dependencies, occurrence (a point in
time, append-only, superseded never replaced) in publications/subscriptions. Cutting a release
is emitting the fact: one act, two products, one commit.
Two rules do most of the work:
The producer supplies meaning. The consumer declares intent. Behaviour is proposed, never contracted.
A publication says what a fact is and why it might concern a reader — never what a reader should do about it. That belongs in the consumer's own card, under the consumer's own review. It is MCP's rule applied to facts instead of tools. What the consumer then runs — a handler, a poll, a judgement, a human — is its own business; the contract asks only that the edge be declared, never that it be wired a particular way.
Determinism sits at existence, never at interpretation.
"Has anything appeared after my position?" must stay deterministic — if a model decides what it
has already seen, consumption stops being idempotent. "Does this fact matter to me?" is
irreducibly judgement. A subscription declares both halves separately, and papeete-actor checks that
the deterministic half stays deterministic.
The contracts are in this repo
src/papeete_actor/schemas/ — ordinary committed source. The
package IS the contracts, not a gate that goes looking for them
(ADR-PA-0001).
That is what makes an organisation able to stand up a papeete-actor without depending on Papeete for
anything. The previous design fetched the schemas at build time from a private lab repo, which meant
a build needed a credential nobody outside the lab could have — and spec and gate could not change
in one commit, the drift generator ADR-ECO-0005 was written to prevent.
Every gate loads its schema. None hard-codes a field, an enum, or a rule.
uv build # no network, no token, no fetch step
papeete-actor also holds its own card, papeete-actor.yaml, under the
contract it ships — and CI lints it on every push. If the schemas failed to ship in the wheel, or a
gate could not read them, that check fails.
Versioning
The tool version and the contract versions are different things and move independently.
papeete-actor contracts prints the mapping for any installed build:
papeete-actor 0.1.0 — contracts from …/site-packages/papeete_actor/schemas
ok papeete-actor-card papeete-actor-card/v1
ok message inter-agent-message/v0
ok publication publication/v2
A card declares the contract version; your CI pins the tool.
Releasing
Tag-triggered, via PyPI Trusted Publishing (OIDC). No API token is stored anywhere — GitHub mints a short-lived OIDC token per run and PyPI trades it for an upload token. There is nothing to rotate and nothing to leak.
git tag v0.1.0 && git push origin v0.1.0 # .github/workflows/release.yml does the rest
One-time setup — done for this repo, both steps
Kept as a record of what is configured, and as the recipe for the next package that needs it.
1. A pending publisher on PyPI ✅ registered 2026-07-23. The project did not exist yet, so it is registered from the publisher side rather than by a first manual upload. At https://pypi.org/manage/account/publishing/, as a GitHub pending publisher:
| Field | Value |
|---|---|
| PyPI Project Name | papeete-actor |
| Owner | papeete-hub |
| Repository name | papeete-actor |
| Workflow name | release.yml |
| Environment name | pypi |
All five must match exactly — PyPI checks the OIDC claims against them and rejects the upload
otherwise. release.yml already declares permissions: id-token: write and
environment: pypi, which is what makes those claims present.
2. The pypi GitHub environment ✅ created. No secrets in it — it exists so the OIDC claim
carries an environment name for PyPI to match. Protection rules are not set and are worth
considering, because a release is irreversible: PyPI never allows re-uploading a version, even after
a delete. Required reviewers, and restricting deployments to tags matching v*, are the two that
earn their keep.
A private repo is fine. Trusted Publishing authenticates the workflow, not the source, so nothing here needs to be public for the package to be.
After the first successful release PyPI converts the pending publisher into a normal one automatically; there is no second setup step.
Nothing has been published yet. papeete-actor is unclaimed on PyPI and the release lane has
never run — git tag v0.1.0 && git push origin v0.1.0 is the whole of it.
What a release asserts
The workflow builds, installs the wheel into a clean venv, and runs papeete-actor contracts
before publishing — so a build that lost its schemas fails the release instead of shipping a gate
that enforces nothing.
What it does not do
papeete-actor check computes four conformance classes — dangling subscription, unsubscribed
publication, unschematised publication, unpinned scripted subscription. It deliberately does not
compute the fifth, undeclared consumption: the evidence for that lives in consumer source code,
not in cards, so detection is a heuristic and a heuristic finding is a prompt to declare, never a
verdict.
Licence
MIT.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file papeete_actor-0.4.0.tar.gz.
File metadata
- Download URL: papeete_actor-0.4.0.tar.gz
- Upload date:
- Size: 143.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cd17b9a6421f70d872f0e7b57ba99053e7e12a240d69b8b124bdaa6304c18b3d
|
|
| MD5 |
b4013639ab7eb800a08484a337ebed5d
|
|
| BLAKE2b-256 |
2ac731dc7c12d9682a1a65ae971209fcce6a50e6bd7a16b96d0be5f48245a6d7
|
File details
Details for the file papeete_actor-0.4.0-py3-none-any.whl.
File metadata
- Download URL: papeete_actor-0.4.0-py3-none-any.whl
- Upload date:
- Size: 46.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ab1dde00fe7014b5bcd620cff8647c4e11ce541e034432d6302e8acdf435465b
|
|
| MD5 |
8cd75f01e8eb1ec6a54b68701d44b9fe
|
|
| BLAKE2b-256 |
b5fe0f99d9db097027ea81de47b4b2c0bf463d222693e310dc8115dd19ed7859
|