Metadata-Version: 2.5
Name: agent-mandates
Version: 0.1.0
Summary: Who authorized an AI agent to act, whether it stayed inside those bounds, and what it cost when it did not.
Project-URL: Homepage, https://github.com/Oluwatemmy/agent-mandates
Project-URL: Repository, https://github.com/Oluwatemmy/agent-mandates
Project-URL: Issues, https://github.com/Oluwatemmy/agent-mandates/issues
Project-URL: Changelog, https://github.com/Oluwatemmy/agent-mandates/blob/main/CHANGELOG.md
Project-URL: Specification, https://github.com/Oluwatemmy/agent-mandates/blob/main/FORMAT.md
Author: Ajayi Oluwaseyi Temitope
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: agentic-commerce,ai-agents,audit-trail,delegation,ed25519,rfc8785,verifiable-credentials
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Security :: Cryptography
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: cryptography>=42.0
Requires-Dist: pydantic>=2.9
Provides-Extra: dev
Requires-Dist: hypothesis>=6.100; extra == 'dev'
Requires-Dist: mypy~=2.3; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: rfc8785>=0.1; extra == 'dev'
Requires-Dist: ruff~=0.16.7; extra == 'dev'
Description-Content-Type: text/markdown

# agent-mandates

[![PyPI](https://img.shields.io/pypi/v/agent-mandates)](https://pypi.org/project/agent-mandates/)
[![CI](https://github.com/Oluwatemmy/agent-mandates/actions/workflows/ci.yml/badge.svg)](https://github.com/Oluwatemmy/agent-mandates/actions/workflows/ci.yml)
[![Python](https://img.shields.io/pypi/pyversions/agent-mandates)](https://pypi.org/project/agent-mandates/)
[![License](https://img.shields.io/pypi/l/agent-mandates)](LICENSE)

Who authorized an AI agent to do something, whether it stayed inside those
bounds, and what it cost when it did not.

Three linked documents, each signed by the party actually making the claim:

- **Mandate** — signed by a principal, granting one named agent a scope, a
  ceiling and an expiry. An agent may pass authority on, but only narrowed: a
  delegated grant can never widen what it received.
- **Action receipt** — signed by the agent when it acts, bound by hash to the
  mandate it acted under.
- **Outcome attestation** — signed later and bound by hash to that receipt.
  What actually happened: completed, disputed, refunded, reversed, and any loss.

Because a grant is signed by whoever granted it rather than whoever used it, a
verifier checks an agent's authority against its principal instead of taking the
agent's word for it. Verification needs only the published public keys, never
access to the issuer.

## Install

```sh
pip install agent-mandates
```

Python 3.11+. Depends on `pydantic` and `cryptography`, nothing else.

## Issue a grant, act under it, attest the outcome

```python
# Alice grants her shopping agent authority to charge up to 200 USD.
mandate = Mandate(
    id=new_mandate_id(),
    issued_at=now,
    principal=alice,
    agent=shopper,
    scope=("payment.charge",),
    expires_at=now + timedelta(days=30),
    max_value=Money(amount=Decimal("200.00"), currency="USD"),
)

# The agent charges 79.99. receipt_under commits to the grant by hash, so the
# binding cannot be mistyped.
receipt = receipt_under(
    mandate,
    action=Action(
        type="payment.charge",
        target="https://shop.example.com/v1/orders",
        params_hash=...,
        value=Money(amount=Decimal("79.99"), currency="USD"),
    ),
    decision=Decision(outcome=DecisionOutcome.ALLOW),
    issued_at=now + timedelta(minutes=2),
)

# Two days later the merchant attests what happened.
outcome = outcome_for(receipt, status=OutcomeStatus.COMPLETED, issued_at=now + timedelta(days=2))

envelope = sign(mandate, "alice", alice_key)
```

[`examples/walkthrough.py`](examples/walkthrough.py) is the whole flow, runnable.
The test suite executes it, so it cannot drift from the library.

## Verify

Anyone holding the published keys can check the chain:

```console
$ mandates verify outcome.json --keys jwks.json \
      --receipt receipt.json --mandate mandate.json

document   outc_70744f1f3219436cb220f281817fee60 (outcome attestation)
status     completed
signed by  merchant
receipt    rcpt_1614b59b188b4e8b8cffe7d14be710db signed by shopper
binding    OK
mandate    mndt_5533e1521b474eb5a62f310837f472a5 granted by alice
chain      OK, answering to user:alice (human)
scope      OK
result     VERIFIED
```

Exit codes are `0` verified, `1` not verified, `2` bad input, so the three cases
can be told apart in a script. `--require KEY_ID` fails unless a particular key
signed. Repeat `--mandate`, root first, to check a delegation chain.

## What it does not do

**It verifies documents, not the world they describe.** An agent signs its own
account of what it did, and nothing here compares that account to reality. A
receipt saying an agent charged 79.99 is evidence that the agent *claimed* that,
under authority its principal *did* grant. It is not evidence the charge
happened.

Key management is deliberately out of scope: generating, storing, rotating and
revoking private keys is left to you.

## The format

The wire format is specified in [FORMAT.md](FORMAT.md) — canonicalization,
signing boundary, binding, attenuation — and pinned by golden vectors in
[`tests/vectors/`](tests/vectors), which carry fixed key seeds so an
implementation in another language can reproduce the same signature bytes.

Verified on Linux, macOS and Windows across Python 3.11, 3.12 and 3.13, which
ship different Unicode tables and must still agree on canonical bytes.

## Development

```sh
python -m pip install -e ".[dev]"
python -m pytest
```

Contributions welcome — see [CONTRIBUTING.md](CONTRIBUTING.md). Security
reports: [SECURITY.md](SECURITY.md).

## License

Copyright 2026 Ajayi Oluwaseyi Temitope.

Apache-2.0 rather than MIT for its explicit patent grant: this format is meant
to be implemented by other parties, who need assurance that no patent claim will
be asserted over it later.
