Catalog PyPI
Back to packageRELEASE DETAILS

0.8.1

PyPI

agentsystems-notary

Cryptographic notarization SDK for LLM interactions

Published21 May 2026
Direct dependencies20
Transitive dependenciesNot calculated

README

Version 0.8.1 documentation

AgentSystems Notary

PyPI version

Audit logging infrastructure for AI systems

AgentSystems Notary provides tamper-evident audit trails for AI systems. It creates cryptographically verifiable logs of all LLM interactions with dual-write architecture: your storage bucket (raw logs) + hash storage (verification receipts).

Features

  • Multi-Framework Support: LangChain and CrewAI adapters
  • Dual-Write Architecture: Your bucket (raw logs) + hash storage (receipts)
  • Flexible Hash Storage: Arweave (decentralized) and/or Custodied (AgentSystems API)
  • Cryptographic Verification: SHA-256 hashes with JCS canonicalization (RFC 8785)
  • Multi-Tenant Support: Isolated audit trails for SaaS applications

Installation

pip install agentsystems-notary

Quick Start

Copy .env.example to .env and fill in your credentials.

LangChain

pip install langchain-anthropic
import os
from dotenv import load_dotenv
from agentsystems_notary import (
    LangChainNotary,
    RawPayloadStorage,
    ArweaveHashStorage,
    LocalKeySignerConfig,
    AwsS3StorageConfig,
)
from langchain_anthropic import ChatAnthropic

load_dotenv()

# Where full audit payloads are stored (your S3 bucket)
raw_payload_storage = RawPayloadStorage(
    storage=AwsS3StorageConfig(
        bucket_name=os.environ["ORG_AWS_S3_BUCKET_NAME"],
        aws_access_key_id=os.environ["ORG_AWS_S3_ACCESS_KEY_ID"],
        aws_secret_access_key=os.environ["ORG_AWS_S3_SECRET_ACCESS_KEY"],
        aws_region=os.environ["ORG_AWS_S3_REGION"],
    ),
)

# Where hashes are stored — Arweave for independent verification
hash_storage = [
    ArweaveHashStorage(
        namespace="my_namespace",
        signer=LocalKeySignerConfig(
            private_key_path=os.environ["ARWEAVE_PRIVATE_KEY_PATH"],
        ),
        bundler_url=os.environ["ARWEAVE_BUNDLER_URL"],
    ),
]

# Initialize notary
notary = LangChainNotary(
    raw_payload_storage=raw_payload_storage,
    hash_storage=hash_storage,
    debug=True,
)

model = ChatAnthropic(
    model="claude-sonnet-4-5-20250929",
    api_key=os.environ["ANTHROPIC_API_KEY"],
    callbacks=[notary],
)

response = model.invoke("What is 2 + 2?")

CrewAI

pip install crewai
import os
from dotenv import load_dotenv
from agentsystems_notary import (
    CrewAINotary,
    RawPayloadStorage,
    ArweaveHashStorage,
    LocalKeySignerConfig,
    AwsS3StorageConfig,
)
from crewai import Agent, Task, Crew, LLM

load_dotenv()

# Where full audit payloads are stored (your S3 bucket)
raw_payload_storage = RawPayloadStorage(
    storage=AwsS3StorageConfig(
        bucket_name=os.environ["ORG_AWS_S3_BUCKET_NAME"],
        aws_access_key_id=os.environ["ORG_AWS_S3_ACCESS_KEY_ID"],
        aws_secret_access_key=os.environ["ORG_AWS_S3_SECRET_ACCESS_KEY"],
        aws_region=os.environ["ORG_AWS_S3_REGION"],
    ),
)

# Where hashes are stored — Arweave for independent verification
hash_storage = [
    ArweaveHashStorage(
        namespace="my_namespace",
        signer=LocalKeySignerConfig(
            private_key_path=os.environ["ARWEAVE_PRIVATE_KEY_PATH"],
        ),
        bundler_url=os.environ["ARWEAVE_BUNDLER_URL"],
    ),
]

# Initialize notary (hooks register automatically)
notary = CrewAINotary(
    raw_payload_storage=raw_payload_storage,
    hash_storage=hash_storage,
    debug=True,
)

llm = LLM(
    model="anthropic/claude-sonnet-4-5-20250929",
    api_key=os.environ["ANTHROPIC_API_KEY"],
)
agent = Agent(role="Analyst", goal="Answer questions", backstory="Expert analyst", llm=llm)
task = Task(description="What is 2 + 2?", expected_output="The answer", agent=agent)
crew = Crew(agents=[agent], tasks=[task])

result = crew.kickoff()

How It Works

  1. Capture: Intercepts LLM requests/responses via framework hooks
  2. Canonicalize: Deterministic JSON serialization (JCS/RFC 8785)
  3. Hash: SHA-256 of canonical bytes
  4. Dual-Write:
    • Your bucket: Full canonical JSON payload
    • Hash storage: Hash receipt for verification

Configuration

Raw Payload Storage

Where full audit payloads are stored (your bucket):

from agentsystems_notary import RawPayloadStorage, AwsS3StorageConfig

raw_payload_storage = RawPayloadStorage(
    storage=AwsS3StorageConfig(
        bucket_name="my-audit-logs",
        aws_access_key_id="...",
        aws_secret_access_key="...",
        aws_region="us-east-1",
    ),
)

Hash Storage

Where hashes are stored for verification. You can use one or both.

Arweave (Decentralized) — Public blockchain, permanent storage, no vendor dependency. Verify independently with open-source CLI.

from agentsystems_notary import ArweaveHashStorage, LocalKeySignerConfig

ArweaveHashStorage(
    namespace="my_namespace",
    signer=LocalKeySignerConfig(
        private_key_path="path/to/rsa-4096-private.pem",
    ),
    bundler_url="https://node2.bundlr.network",
)

Custodied (AgentSystems API) — Managed service if you prefer AgentSystems to handle the complexity.

from agentsystems_notary import CustodiedHashStorage

CustodiedHashStorage(
    api_key="sk_asn_prod_...",  # From agentsystems.ai
    slug="my_tenant",
)

Using both:

hash_storage=[
    ArweaveHashStorage(namespace="my_namespace", signer=..., bundler_url="..."),
    CustodiedHashStorage(api_key="...", slug="my_tenant"),
]

Debug Mode

notary = LangChainNotary(
    raw_payload_storage=...,
    hash_storage=[...],
    debug=True,  # Prints canonical JSON and hashes
)

S3 Bucket Structure

{env}/{namespace}/{YYYY}/{MM}/{DD}/{hash}.json
  • env: arweave, prod, or test
  • namespace: Your namespace (Arweave) or tenant ID from API response (custodied)
  • hash: SHA-256 hash of the canonical payload

Verification

For Arweave-notarized logs, use the open-source CLI — no account required:

npm install -g agentsystems-verify
agentsystems-verify --logs logs.zip

Manual verification:

import hashlib

# 1. Download payload from your bucket
with open("payload.json", "rb") as f:
    canonical_bytes = f.read()

# 2. Compute hash
computed_hash = hashlib.sha256(canonical_bytes).hexdigest()

# 3. Compare with stored hash (from Arweave or custodied receipt)
assert computed_hash == stored_hash

Support

License

Licensed under the Apache-2.0 license.

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Declared dependencies 25

Native requirements
20 direct targetsNot calculated transitive count
Package / targetRequirementRelationship
boto3
Environment
{
  "extras": "",
  "marker": null,
  "requires_python": ">=3.11",
  "evaluation": "NOT_EVALUATED"
}
boto3>=1.34.0runtime
httpx
Environment
{
  "extras": "",
  "marker": null,
  "requires_python": ">=3.11",
  "evaluation": "NOT_EVALUATED"
}
httpx>=0.25.0runtime
jcs
Environment
{
  "extras": "",
  "marker": null,
  "requires_python": ">=3.11",
  "evaluation": "NOT_EVALUATED"
}
jcs>=0.2.1runtime
cryptography
Environment
{
  "extras": "",
  "marker": null,
  "requires_python": ">=3.11",
  "evaluation": "NOT_EVALUATED"
}
cryptography>=41.0.0runtime
requests
Environment
{
  "extras": "",
  "marker": null,
  "requires_python": ">=3.11",
  "evaluation": "NOT_EVALUATED"
}
requests>=2.28.0runtime
langchain-core
Environment
{
  "extras": "",
  "marker": "extra == \"langchain\"",
  "requires_python": ">=3.11",
  "evaluation": "NOT_EVALUATED"
}
langchain-core>=0.1.0; extra == "langchain"runtime
crewai
Environment
{
  "extras": "",
  "marker": "extra == \"crewai\"",
  "requires_python": ">=3.11",
  "evaluation": "NOT_EVALUATED"
}
crewai>=0.1.0; extra == "crewai"runtime
llama-index-core
Environment
{
  "extras": "",
  "marker": "extra == \"llamaindex\"",
  "requires_python": ">=3.11",
  "evaluation": "NOT_EVALUATED"
}
llama-index-core>=0.10.0; extra == "llamaindex"runtime
agno
Environment
{
  "extras": "",
  "marker": "extra == \"agno\"",
  "requires_python": ">=3.11",
  "evaluation": "NOT_EVALUATED"
}
agno>=0.1.0; extra == "agno"runtime
agent-control-sdk
Environment
{
  "extras": "",
  "marker": "extra == \"agent-control\"",
  "requires_python": ">=3.11",
  "evaluation": "NOT_EVALUATED"
}
agent-control-sdk>=7.0.0; extra == "agent-control"runtime
langchain-core
Environment
{
  "extras": "",
  "marker": "extra == \"all\"",
  "requires_python": ">=3.11",
  "evaluation": "NOT_EVALUATED"
}
langchain-core>=0.1.0; extra == "all"runtime
crewai
Environment
{
  "extras": "",
  "marker": "extra == \"all\"",
  "requires_python": ">=3.11",
  "evaluation": "NOT_EVALUATED"
}
crewai>=0.1.0; extra == "all"runtime
llama-index-core
Environment
{
  "extras": "",
  "marker": "extra == \"all\"",
  "requires_python": ">=3.11",
  "evaluation": "NOT_EVALUATED"
}
llama-index-core>=0.10.0; extra == "all"runtime
agno
Environment
{
  "extras": "",
  "marker": "extra == \"all\"",
  "requires_python": ">=3.11",
  "evaluation": "NOT_EVALUATED"
}
agno>=0.1.0; extra == "all"runtime
agent-control-sdk
Environment
{
  "extras": "",
  "marker": "python_version >= \"3.12\" and extra == \"all\"",
  "requires_python": ">=3.11",
  "evaluation": "NOT_EVALUATED"
}
agent-control-sdk>=7.0.0; python_version >= "3.12" and extra == "all"runtime
pytest
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.11",
  "evaluation": "NOT_EVALUATED"
}
pytest>=7.0; extra == "dev"runtime
pytest-cov
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.11",
  "evaluation": "NOT_EVALUATED"
}
pytest-cov>=4.0; extra == "dev"runtime
black
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.11",
  "evaluation": "NOT_EVALUATED"
}
black>=23.0; extra == "dev"runtime
ruff
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.11",
  "evaluation": "NOT_EVALUATED"
}
ruff>=0.1.0; extra == "dev"runtime
mypy
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.11",
  "evaluation": "NOT_EVALUATED"
}
mypy>=1.5; extra == "dev"runtime
types-requests
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.11",
  "evaluation": "NOT_EVALUATED"
}
types-requests>=2.28.0; extra == "dev"runtime
build
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.11",
  "evaluation": "NOT_EVALUATED"
}
build; extra == "dev"runtime
twine
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.11",
  "evaluation": "NOT_EVALUATED"
}
twine; extra == "dev"runtime
pip-licenses
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.11",
  "evaluation": "NOT_EVALUATED"
}
pip-licenses>=4.0.0; extra == "dev"runtime
LICENSE
Environment
{
  "extras": "",
  "marker": "extra == \"license-files\"",
  "requires_python": ">=3.11",
  "evaluation": "NOT_EVALUATED"
}
LICENSE; extra == "license-files"runtime

Distribution files

2 collected
agentsystems_notary-0.8.1-py3-none-any.whl

bdist_wheel · 32.83 KB · Python py3

Source file
agentsystems_notary-0.8.1.tar.gz

sdist · 33.06 KB · Python source

Source file

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 23:32 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package_version:f0de354b3df821190e942b85fbc00f9ecd06ddacbf97d7698005d7dff6fd7fd0

Other collected versions

View all collected versions →