Metadata-Version: 2.4
Name: aegis-ledger-sdk
Version: 0.3.5
Summary: Tamper-evident execution ledger for AI agents. Log every tool call, decision, and error to a cryptographically verifiable audit trail.
Project-URL: Homepage, https://www.aegis-ledger.com
Project-URL: Documentation, https://www.aegis-ledger.com/docs
Project-URL: Repository, https://github.com/VladislavRoss/aegis-ledger-sdk
Author-email: Aegis Ledger <info@aegis-ledger.com>
License-Expression: MIT
License-File: LICENSE
Keywords: ai-agents,anthropic,audit-trail,autogen,compliance,crewai,icp,langchain,observability,openai,tamper-evident
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Logging
Requires-Python: >=3.10
Requires-Dist: cryptography>=42.0
Requires-Dist: ic-py>=1.0
Provides-Extra: all
Requires-Dist: autogen-agentchat>=0.4; extra == 'all'
Requires-Dist: claude-agent-sdk>=0.1; extra == 'all'
Requires-Dist: crewai>=0.28; extra == 'all'
Requires-Dist: fpdf2>=2.7.4; extra == 'all'
Requires-Dist: langchain-core>=0.1; extra == 'all'
Requires-Dist: mcp<2.0,>=1.20; extra == 'all'
Requires-Dist: openai-agents>=0.1; extra == 'all'
Requires-Dist: pqcrypto>=0.4; extra == 'all'
Provides-Extra: anthropic-agents
Requires-Dist: claude-agent-sdk>=0.1; extra == 'anthropic-agents'
Provides-Extra: autogen
Requires-Dist: autogen-agentchat>=0.4; extra == 'autogen'
Provides-Extra: crewai
Requires-Dist: crewai>=0.28; extra == 'crewai'
Provides-Extra: dev
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
Requires-Dist: pytest-timeout>=2.3; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.4; extra == 'dev'
Provides-Extra: icp
Provides-Extra: langchain
Requires-Dist: langchain-core>=0.1; extra == 'langchain'
Provides-Extra: mcp
Requires-Dist: mcp<2.0,>=1.20; extra == 'mcp'
Provides-Extra: openai-agents
Requires-Dist: openai-agents>=0.1; extra == 'openai-agents'
Provides-Extra: pdf
Requires-Dist: fpdf2>=2.7.4; extra == 'pdf'
Provides-Extra: pq
Requires-Dist: pqcrypto>=0.4; extra == 'pq'
Description-Content-Type: text/markdown

# Aegis Ledger SDK

**Tamper-evident audit logs for AI agents.**

When autonomous agents take actions, their logs become verifiable audit evidence. Aegis hash-chains every tool call, signs it with Ed25519 or post-quantum signatures (ML-DSA-65, ML-DSA-87, SLH-DSA-128s, Hybrid), and stores it on the [Internet Computer](https://internetcomputer.org) — where tampering is cryptographically detectable. Not by you, not your ops team, not the hosting provider — any modification breaks the hash chain.

[![PyPI](https://img.shields.io/pypi/v/aegis-ledger-sdk)](https://pypi.org/project/aegis-ledger-sdk/)
[![Python](https://img.shields.io/pypi/pyversions/aegis-ledger-sdk)](https://pypi.org/project/aegis-ledger-sdk/)
[![Downloads](https://img.shields.io/pypi/dm/aegis-ledger-sdk)](https://pypi.org/project/aegis-ledger-sdk/)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)

```
pip install aegis-ledger-sdk
```

For MCP server support: `pip install aegis-ledger-sdk[mcp]`
For post-quantum signatures: `pip install aegis-ledger-sdk[pq]`
For everything: `pip install aegis-ledger-sdk[all]`

## The Problem

Your AI agent just autonomously called a payment API, transferred $47,000, and the client says it wasn't authorized. Your logs are in CloudWatch. The client's lawyer asks: **"Can you prove these logs haven't been edited since the incident?"**

You can't. Aegis fixes this.

## Quickstart

```python
from aegis import AegisClient

# After: pip install aegis-ledger-sdk && aegis init
client = AegisClient.from_config()

@client.trace()
def call_stripe(amount: int, currency: str) -> dict:
    return stripe.PaymentIntent.create(amount=amount, currency=currency)

# Every call is now tamper-evident logged:
#   SHA-256(input) + SHA-256(output) + signature (Ed25519/PQ) + hash-chain link
```

Verify any entry — no authentication required:

```bash
aegis verify toqqq-lqaaa-aaaae-afc2a-cai act_a7f3b2c19e4d
# VERIFIED — chain hash valid, signature valid
```

## Explicit Logging API

```python
# Tool/API calls
client.log_tool_call("stripe.charge", input_data={"amount": 5000}, output_data={"id": "ch_xxx"}, duration_ms=340)

# Decisions with reasoning
client.log_decision("Selected cheapest shipping provider", confidence=0.92, input_data=options)

# Observations (sensor data, API responses)
client.log_observation(input_data=sensor_reading, output_data=parsed_result)

# Errors
client.log_error("payment.process", input_data=request, error=exc, duration_ms=120)

# Human overrides (EU AI Act Art. 14 compliance)
client.log_human_override("Manager approved exception", input_data=original, output_data=override)

# Batch import
client.log_batch([
    {"tool": "search", "input_data": "query", "output_data": "results"},
    {"tool": "summarize", "input_data": "results", "output_data": "summary"},
])
```

## Span Grouping

Group related actions under a parent for structured traces:

```python
with client.span("process_order", reasoning="Customer checkout flow") as span_id:
    client.log_tool_call("inventory.check", ...)
    client.log_tool_call("payment.charge", ...)
    # Both calls have parent_action_id = span_id
```

## Session Management

```python
# Start a new session (resets sequence counter)
new_id = client.new_session()

# Use as context manager for automatic cleanup
with AegisClient(...) as client:
    client.log_tool_call(...)
# Spill buffer drained on exit
```

## KYA — Know Your Agent (Roadmap)

> **Note:** `register_agent()` and `update_agent_profile()` are currently available via `CanisterOps` only. A convenience wrapper on the main `AegisClient` is planned.

Register agent identity on-chain for transparent AI governance:

```python
# Register an agent profile (via CanisterOps)
client.register_agent(
    agent_id="agent-billing-v2",
    name="Billing Agent",
    description="Handles invoice generation and payment processing",
    capabilities=["stripe.charge", "invoice.create", "refund.process"],
    framework="langchain",
    model_id="gpt-4o",
)

# Update an existing profile
client.update_agent_profile("agent-billing-v2", name="Billing Agent v3", model_id="gpt-4.1")

# Retrieve public agent facts (no auth required)
facts = client.get_agent_facts("agent-billing-v2")
```

Agent profiles are stored on-chain and publicly verifiable — any third party can inspect what an agent claims to do.

## OpenTelemetry Correlation

Aegis entries can carry OpenTelemetry context for correlation with your existing observability stack:

```python
# Auto-extracted from active OTel span (if opentelemetry SDK installed)
client.log_tool_call("search", input_data=q, output_data=r, duration_ms=50)
# → otel_trace_id, otel_span_id auto-populated

# Or pass explicitly
client.log_tool_call(
    "search", input_data=q, output_data=r, duration_ms=50,
    otel_trace_id="abc123", otel_span_id="def456",
    cost_usd=0.003, token_count=1500,
)
```

## Framework Integrations

### LangChain

```python
from aegis.langchain import AegisCallbackHandler

handler = AegisCallbackHandler(client)
agent.invoke({"input": "Process refund"}, config={"callbacks": [handler]})
```

### CrewAI

```python
from aegis.crewai import AegisCrewCallback

callback = AegisCrewCallback(client)
crew = Crew(agents=[...], tasks=[...], step_callback=callback)
```

### OpenAI Agents SDK

```python
from aegis.openai_agents import AegisAgentTracer

tracer = AegisAgentTracer(client)
with tracer.trace() as tid:
    result = await Runner.run(agent, "Process this request")
```

### AutoGen / AG2

```python
from aegis.autogen import AegisAutoGenHook

hook = AegisAutoGenHook(client)
hook.on_tool_call("search", arguments={"q": "test"}, caller="assistant")
hook.on_tool_result("search", result="found 5 items", caller="assistant")
```

### Anthropic Agent SDK

```python
from aegis.anthropic_sdk import AegisAnthropicTracer

tracer = AegisAnthropicTracer(client)
tracer.on_tool_use("search", tool_input={"q": "test"}, tool_response="5 results")
tracer.on_session_start("session_123")
tracer.on_subagent_start("sub_1", "researcher")
```

### MCP (Model Context Protocol)

```bash
pip install aegis-ledger-sdk[mcp]
aegis-mcp  # starts MCP server (stdio transport)
```

Any MCP-compatible agent can log actions to the tamper-evident ledger via MCP tools.

## Async & Batch Support

```python
# Async functions work directly with @trace
@client.trace()
async def fetch_data(url: str) -> dict:
    async with aiohttp.ClientSession() as session:
        resp = await session.get(url)
        return await resp.json()
```

## Post-Quantum Signatures

Five signature algorithms with crypto-agility:

| Algorithm | Type | Key Size | Use Case |
|-----------|------|----------|----------|
| Ed25519 | Classical | 32 B | Default, fast |
| ML-DSA-65 | Post-Quantum (FIPS 204) | 1952 B | PQ Level 3 |
| ML-DSA-87 | Post-Quantum (FIPS 204) | 2592 B | CNSA 2.0 Level 5 |
| SLH-DSA-128s | Hash-based (FIPS 205) | 32 B | Conservative PQ fallback |
| Hybrid | Ed25519 + ML-DSA-65 | 1984 B | Best of both worlds |

```python
# Generate PQ keys
# aegis keygen ./key.mldsa65 --algorithm ml-dsa-65
# aegis keygen ./key --algorithm hybrid

client = AegisClient(
    ...,
    signature_scheme="hybrid",
    signing_key_path="./key.mldsa65",
)
```

Configure via `~/.aegis/config.toml`:

```toml
[signing]
default_scheme = "hybrid"
signing_key_path = "~/.aegis/keys/agent.mldsa65"
```

## PII Protection

PII is automatically detected and redacted before transmission (enabled by default):

```python
client = AegisClient(..., redact_pii=True)  # default

# Detected patterns: email, phone, IP, SSN, AHV (Swiss), credit cards
# PII is replaced with sha256:<128-bit hash> — verifiable but not reversible
```

## CLI

```bash
# Setup & diagnostics
aegis init                                                 # Interactive setup wizard
aegis test                                                 # Send test entry + verify on-chain
aegis doctor                                               # Check SDK health (config, keys, canister)
aegis version                                              # Print SDK version

# Key generation
aegis keygen ./key.pem                                     # Generate Ed25519 keypair
aegis keygen ./key.mldsa65 --algorithm ml-dsa-65           # Generate ML-DSA-65 keypair
aegis keygen ./key --algorithm hybrid                      # Generate Hybrid keypair

# Verification
aegis verify <canister_id> <action_id>                     # Verify single entry
aegis verify-chain <canister_id> <session_id>              # Verify full session chain

# Canister queries
aegis status <canister_id>                                 # Canister health + chain stats
aegis list-sessions <canister_id>                          # List your sessions
aegis session-analytics <session_id>                       # Error rate, duration, action types
aegis org-stats <canister_id>                              # Aggregated org statistics
aegis spill-status                                         # Show pending offline buffer

# Compliance reports
aegis report <canister_id> --format eu-ai-act              # EU AI Act Art. 12
aegis report <canister_id> --format all -o ./reports/      # All formats

# Key management (self-service)
aegis register-key <id> --key-file <f>                     # Register new API key
aegis revoke <key_id>                                      # Revoke key (confirmation required)
aegis reactivate-key <key_id>                              # Reactivate revoked key
aegis delete-key <key_id>                                  # Permanently delete revoked key
aegis update-key-desc <key_id> <desc>                      # Update key description

# Migration
aegis migrate <canister_id> <session_id> --to hybrid       # Re-sign with new algorithm
aegis purge-session <session_id>                           # Purge session entries (owner/admin)
```

## How It Works

```
Your Agent                    Aegis SDK                    ICP Canister
    |                             |                             |
    |-- call_stripe(500, "usd") ->|                             |
    |                             |-- SHA-256(input)            |
    |                             |-- SHA-256(output)           |
    |                             |-- sign (Ed25519/PQ) ------->|
    |                             |                    verify signature
    |                             |                    check sequence
    |                             |                    chain_hash = SHA-256(
    |                             |                      prev_hash + payload
    |                             |                    )
    |                             |                    store in append-only ledger
    |                             |<-- action_id ---------------|
    |<-- return result -----------|                             |

Fail-open: if canister unreachable, entries buffer locally (~/.aegis/spill/) and retry.
```

## What Gets Logged

| Field | Description |
|-------|-------------|
| `input_hash` | SHA-256 of full input (raw data never stored on-chain) |
| `output_hash` | SHA-256 of full output |
| `tool` | Tool/API name |
| `duration_ms` | Wall-clock execution time |
| `chain_hash` | SHA-256 linking to previous entry |
| `payload_signature` | Cryptographic signature (Ed25519, ML-DSA-65, ML-DSA-87, SLH-DSA-128s, or Hybrid) |
| `sequence_number` | Monotonic counter (gap detection) |
| `otel_trace_id` | OpenTelemetry trace ID (optional, for correlation) |
| `otel_span_id` | OpenTelemetry span ID (optional) |
| `cost_usd` | LLM call cost in USD (optional) |
| `token_count` | Token usage (optional) |

**What does NOT get logged:** Raw payloads, API keys, secrets, PII. Only hashes — you control your data.

## Compliance

Generate verifiable compliance reports:

```python
from aegis.report import generate_report, generate_pdf, ReportFormat

report = generate_report("toqqq-...", format=ReportFormat.EU_AI_ACT, stats=stats, health=health)
generate_pdf(report, "compliance-report.pdf")
```

Supported frameworks: **EU AI Act Art. 12**, **ISO/IEC 42001**, **AIUC-1** (insurance underwriting).

## Links

- [Dashboard](https://www.aegis-ledger.com)
- [Documentation](https://www.aegis-ledger.com/docs)
- [GitHub](https://github.com/VladislavRoss/aegis-ledger-sdk)

Normal logging = trust the system. **Aegis = verify the record.**

## License

MIT
