Metadata-Version: 2.4
Name: agent-toolprint
Version: 0.1.0
Summary: Double-signed receipts for AI-agent tool invocations — DSSE + JCS + Ed25519, verifiable offline (Python port of @p-vbordei/agent-toolprint)
Project-URL: Homepage, https://github.com/p-vbordei/agent-toolprint-py
Project-URL: Reference, https://github.com/p-vbordei/agent-toolprint
Project-URL: Issues, https://github.com/p-vbordei/agent-toolprint-py/issues
Author-email: Vlad Bordei <bordeivlad@gmail.com>
License: Apache-2.0
License-File: LICENSE
Keywords: agent,ai-agent,audit,did-key,dsse,ed25519,jcs,mcp,non-repudiation,provenance,receipt,tool-call
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Requires-Python: >=3.10
Requires-Dist: base58>=2.1
Requires-Dist: cryptography>=42.0
Requires-Dist: jcs>=0.2.1
Provides-Extra: dev
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Description-Content-Type: text/markdown

# agent-toolprint (Python)

Python port of [`@p-vbordei/agent-toolprint`](https://github.com/p-vbordei/agent-toolprint).
Byte-deterministic-compatible: passes the same conformance vectors.

`agent-toolprint` is a double-signed receipt format for AI-agent tool
invocations. The agent signs. The tool counter-signs. Anyone with the public
keys can verify offline — no host, no service, no chain.

```bash
pip install agent-toolprint
```

## 30-second example

```python
import asyncio, base64, os, uuid
from datetime import datetime, timezone
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from agent_toolprint import (
    Plaintext, VerifyOptions,
    countersign_tool, did_key_from_ed25519_pubkey, did_key_resolver,
    sha256_hash, sign_agent, verify,
)

def gen():
    sk = Ed25519PrivateKey.generate()
    return (
        sk.private_bytes(serialization.Encoding.Raw, serialization.PrivateFormat.Raw, serialization.NoEncryption()),
        sk.public_key().public_bytes(serialization.Encoding.Raw, serialization.PublicFormat.Raw),
    )

async def main():
    agent_sk, agent_pk = gen()
    tool_sk, tool_pk = gen()
    args, response = {"query": "bun docs"}, {"results": ["https://bun.sh/docs"]}
    receipt = {
        "v": "tp/0.1",
        "id": str(uuid.uuid4()),
        "ts": datetime.now(timezone.utc).isoformat().replace("+00:00", "Z"),
        "agent": {"did": did_key_from_ed25519_pubkey(agent_pk), "key_id": "agent"},
        "tool":  {"did": did_key_from_ed25519_pubkey(tool_pk),  "key_id": "tool"},
        "call":   {"name": "search", "args_hash":     sha256_hash(args)},
        "result": {"status": "ok",   "response_hash": sha256_hash(response)},
        "nonce":  base64.b64encode(os.urandom(32)).decode("ascii"),
    }
    env = countersign_tool(sign_agent(receipt, agent_sk), tool_sk)
    res = await verify(env, VerifyOptions(
        resolver=did_key_resolver,
        plaintext=Plaintext(args=args, args_provided=True, response=response, response_provided=True),
    ))
    print(res.ok)  # True

asyncio.run(main())
```

## Why this exists

The TypeScript reference defines a small, stable receipt protocol (DSSE + JCS +
Ed25519, `did:key` identities). This package is the Python implementation of the
same wire format — produced bytes are byte-identical, signatures verify across
languages, and the same conformance vectors pass.

## Conformance

```bash
uv run pytest -v
```

All 15 TS vectors across SPEC §6 clauses C1–C4 pass here.

## License

Apache 2.0 — see [LICENSE](./LICENSE).
