Skip to main content

agentlens

Tamper-evident audit logging for Claude agents — Claude Code hooks and Anthropic SDK. Local-first, append-only, OSS.

Why

Anthropic logs API calls for their own safety monitoring — but that log is not yours. When your Claude-powered agent takes an action, you need your own tamper-evident record: for compliance (EU AI Act Art. 12, ISO/IEC 42001 A.6.2.8), incident response, and accountability.

agentlens captures every tool_use / tool_result event into a SHA-256 hash-chained JSONL file on your own machine — via Claude Code hooks (recommended) or as a drop-in Anthropic SDK wrapper. It can also block dangerous tool calls before they execute (deterministic rules, no LLM in the loop).

Quickstart: Claude Code / Claude Agent SDK (v0.6.0+)

pip install agentlens-io
agentlens hook install   # prints the settings.json snippet

.claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {"matcher": "*", "hooks": [
        {"type": "command", "command": "agentlens hook pre --log ~/.agentlens/audit.jsonl --block critical"}
      ]}
    ],
    "PostToolUse": [
      {"matcher": "*", "hooks": [
        {"type": "command", "command": "agentlens hook post --log ~/.agentlens/audit.jsonl"}
      ]}
    ]
  }
}

Now every tool call in Claude Code is audit-logged, and rm -rf /-class commands are denied before execution:

agentlens view   ~/.agentlens/audit.jsonl        # colorized event viewer
agentlens summary ~/.agentlens/audit.jsonl       # per-session stats
agentlens verify ~/.agentlens/audit.jsonl        # ✅ hash-chain integrity / ❌ tamper detected
agentlens feedback ~/.agentlens/audit.jsonl --emit-code   # suggest whitelist rules from suppressed violations (v0.8.0+)

feedback reads the accumulated log — including the suppressed_violations that the whitelist keeps instead of deleting — and proposes narrowly-scoped WhitelistRules for rules with a high false-positive rate. It is suggestion-only: it never rewrites your ruleset. A ruleset that auto-tunes from its own logs can be poisoned, so a human stays in the loop. Flags: --min-occurrences N (default 3), --threshold F (default 0.9), --emit-code.

Options: --block critical|high|off (default critical), --whitelist rules.json (false-positive suppression — suppressed violations stay in the log), --standalone (post-hook logs tool_use+result when no pre-hook is registered). Hooks are fail-open: the logger can never break your agent loop.

Design principles

  • Read-only interception — requests and responses are never altered
  • Append-only writes — log entries cannot be edited after creation
  • No AI in the logger — capture logic is deterministic code, not an LLM
  • Your data stays local — FileWriter (default) writes to your own machine; no data leaves your environment

Usage: SDK wrapper

from agentlens import AuditedAnthropic

# Drop-in replacement for anthropic.Anthropic()
client = AuditedAnthropic(log_path="./audit.jsonl")

response = client.messages.create(
    model="claude-opus-4-6",
    max_tokens=1024,
    tools=[...],
    messages=[{"role": "user", "content": "..."}],
)
# Every tool_use and tool_result is now in audit.jsonl

Async (v0.7.0+)

AsyncAuditedAnthropic is the drop-in for anthropic.AsyncAnthropic — same audit logging and pre-execution blocking, awaited:

from agentlens import AsyncAuditedAnthropic

client = AsyncAuditedAnthropic(log_path="./audit.jsonl", block_on_critical=True)

response = await client.messages.create(
    model="claude-opus-4-6",
    max_tokens=1024,
    tools=[...],
    messages=[{"role": "user", "content": "..."}],
)
# Raises PreExecutionBlockedError before a critical tool call reaches you.

Streaming (v0.9.0+)

messages.stream() is wrapped too. Text passes through untouched; the audit and the pre-execution gate fire when the message completes — before your code reads the finished tool_use and acts on it. Works on the sync and async clients:

with client.messages.stream(
    model="claude-opus-4-6",
    max_tokens=1024,
    tools=[...],
    messages=[{"role": "user", "content": "..."}],
) as stream:
    for text in stream.text_stream:
        print(text, end="")
    message = stream.get_final_message()  # tool_use audited + gated here
# block_on_critical raises PreExecutionBlockedError before you touch tool_use.

Provenance — who ran the agent (v0.10.0+)

The log answers what happened. Provenance adds who caused it and under what authority — stamped onto every event so a reader can prove attribution later.

from agentlens import AuditedAnthropic, Provenance

client = AuditedAnthropic(
    log_path="./audit.jsonl",
    provenance=Provenance(
        agent_id="deploy-bot",            # which agent
        principal="alice@corp",           # on whose behalf
        authority=["repo:read", "ci:run"],# scopes it was granted
        # run_id auto-generated; pass parent_run_id to record lineage
    ),
)

Hosted/CI agents usually get their identity from the platform via env, so Provenance.from_env() reads AGENTLENS_AGENT_ID, AGENTLENS_PRINCIPAL, AGENTLENS_AUTHORITY (comma/space separated), AGENTLENS_RUN_ID, AGENTLENS_PARENT_RUN_ID. Provenance is recorded, not enforced — and it is covered by the hash chain, so tampering with who did it breaks verify too. agentlens view shows a by: line per call; summary breaks Tool Use down by agent.

Log format (JSONL)

{"event_type": "tool_use", "tool_use_id": "toolu_01xxx", "tool_name": "bash", "tool_input": {"command": "ls -la"}, "model": "claude-opus-4-6", "timestamp": "2026-04-05T10:00:00+00:00", "session_id": "...", "provenance": {"agent_id": "deploy-bot", "principal": "alice@corp", "authority": ["repo:read"], "run_id": "..."}}
{"event_type": "tool_result", "tool_use_id": "toolu_01xxx", "result_content": "file1.txt\nfile2.txt", "is_error": false, "timestamp": "2026-04-05T10:00:01+00:00", "session_id": "...", "provenance": {"agent_id": "deploy-bot", "run_id": "..."}}

Custom writer

from agentlens.writers import BaseWriter

class MyWriter(BaseWriter):
    def write(self, event) -> None:
        # send to your own DB, S3, SIEM, etc.
        my_db.insert(event.to_json())

client = AuditedAnthropic(writer=MyWriter())

Run tests

pip install -e ".[dev]"
pytest tests/

License

MIT

Release files for agentlens-io 0.10.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for agentlens-io 0.10.0
File Size Uploaded
agentlens_io-0.10.0.tar.gz 38.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for agentlens-io 0.10.0
File Interpreter ABI Platform
agentlens_io-0.10.0-py3-none-any.whl Python 3 none any Details

Total release size: 66.5 kB

Release files / agentlens_io-0.10.0.tar.gz

Download URL agentlens_io-0.10.0.tar.gz
Size 38.3 kB
Tags Source
SHA-256 checksum
How to use checksums
bd7f80a3ecca9aa88ee8db7a780a5001718fa94c4e6a12c29b34fb3cae15143c
BLAKE2b-256 checksum
How to use checksums
e0b40d4c3b6dc1456baf696bf81f549ea64ee3ca91223bcf3742d1a8323c9f69
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / agentlens_io-0.10.0-py3-none-any.whl

Download URL agentlens_io-0.10.0-py3-none-any.whl
Size 28.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7b8ea4b8ef0055e878b4afd9afbc35bb5be77ad9597ad0878d5dca65be8693af
BLAKE2b-256 checksum
How to use checksums
3baf5980289538ce4f18f16f4ef8782f878f726c82d5cbb30f537cf1ab8bd97c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

0.11.0

2 release files

This release

0.10.0 This release

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page