Observed since 20 Oct, 23:32 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
agentsystems-notary
Cryptographic notarization SDK for LLM interactions
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).
pip install agentsystems-notary
Copy .env.example to .env and fill in your credentials.
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?")
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()
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",
),
)
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"),
]
notary = LangChainNotary(
raw_payload_storage=...,
hash_storage=[...],
debug=True, # Prints canonical JSON and hashes
)
{env}/{namespace}/{YYYY}/{MM}/{DD}/{hash}.json
env: arweave, prod, or testnamespace: Your namespace (Arweave) or tenant ID from API response (custodied)hash: SHA-256 hash of the canonical payloadFor 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
Licensed under the Apache-2.0 license.
Download counts and popularity will appear here as the collector receives them.
| Package / target | Requirement | Relationship |
|---|---|---|
boto3Environment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | boto3>=1.34.0 | runtime |
httpxEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | httpx>=0.25.0 | runtime |
jcsEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | jcs>=0.2.1 | runtime |
cryptographyEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | cryptography>=41.0.0 | runtime |
requestsEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | requests>=2.28.0 | runtime |
langchain-coreEnvironment{
"extras": "",
"marker": "extra == \"langchain\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | langchain-core>=0.1.0; extra == "langchain" | runtime |
crewaiEnvironment{
"extras": "",
"marker": "extra == \"crewai\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | crewai>=0.1.0; extra == "crewai" | runtime |
llama-index-coreEnvironment{
"extras": "",
"marker": "extra == \"llamaindex\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | llama-index-core>=0.10.0; extra == "llamaindex" | runtime |
agnoEnvironment{
"extras": "",
"marker": "extra == \"agno\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | agno>=0.1.0; extra == "agno" | runtime |
agent-control-sdkEnvironment{
"extras": "",
"marker": "extra == \"agent-control\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | agent-control-sdk>=7.0.0; extra == "agent-control" | runtime |
langchain-coreEnvironment{
"extras": "",
"marker": "extra == \"all\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | langchain-core>=0.1.0; extra == "all" | runtime |
crewaiEnvironment{
"extras": "",
"marker": "extra == \"all\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | crewai>=0.1.0; extra == "all" | runtime |
llama-index-coreEnvironment{
"extras": "",
"marker": "extra == \"all\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | llama-index-core>=0.10.0; extra == "all" | runtime |
agnoEnvironment{
"extras": "",
"marker": "extra == \"all\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | agno>=0.1.0; extra == "all" | runtime |
agent-control-sdkEnvironment{
"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 |
pytestEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | pytest>=7.0; extra == "dev" | runtime |
pytest-covEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | pytest-cov>=4.0; extra == "dev" | runtime |
blackEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | black>=23.0; extra == "dev" | runtime |
ruffEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | ruff>=0.1.0; extra == "dev" | runtime |
mypyEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | mypy>=1.5; extra == "dev" | runtime |
types-requestsEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | types-requests>=2.28.0; extra == "dev" | runtime |
buildEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | build; extra == "dev" | runtime |
twineEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | twine; extra == "dev" | runtime |
pip-licensesEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | pip-licenses>=4.0.0; extra == "dev" | runtime |
LICENSEEnvironment{
"extras": "",
"marker": "extra == \"license-files\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | LICENSE; extra == "license-files" | runtime |
bdist_wheel · 32.83 KB · Python py3
sdist · 33.06 KB · Python source
Observed since 20 Oct, 23:32 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package_version:f0de354b3df821190e942b85fbc00f9ecd06ddacbf97d7698005d7dff6fd7fd0