Audit Trail

How does the hash chain work?

Every audit entry links to the previous entry via SHA-256, forming a tamper-evident chain where modifying or deleting any entry causes verification to fail. This context database uses the hash chain to guarantee AI memory operation history cannot be retroactively altered.

The genesis entry uses a 64-zero hash as its prev_hash. Each subsequent entry computes its hash over the sequence number, timestamp, event type, actor ID, subject ID, details string, and the previous entry’s hash. All variable-length fields are length-prefixed with a 4-byte big-endian integer before hashing, preventing second-preimage attacks via field boundary manipulation — an attacker cannot shift bytes between adjacent fields to produce the same hash.

Chain integrity is verifiable at any time via verify_chain(), which recomputes every hash and checks the chain links. A bounded variant verify_chain_bounded(limit) caps CPU usage on large databases.

# Verify audit chain integrity (CLI only — no HTTP endpoint)
areev audit --verify

What events does Areev audit?

Areev records 90+ audit event types across memory operations, security, compliance, cluster management, and more. Every state-changing operation produces at least one audit entry in this autonomous memory system.

The event types span 15+ categories: Memory (memory.added, memory.forgotten, memory.corrected, memory.recalled, memory.accumulated), Consent (consent.granted, consent.revoked, processing.restricted, processing.unrestricted), Security (key.rotated, key.destroyed, user.erased, authz.changed, authz.access_denied, authz.org_access_denied), Tier (tier.grain_moved, tier.compaction_run, tier.grain_promoted, tier.erasure_attempt), Agent (agent.recall, agent.write), Policy (policy.sealed, policy.upgraded, policy.downgraded, policy.enforced), Erasure (scope.erased, erasure.cross_user_redacted, user.data_exported), Cluster (cluster.node_joined, cluster.node_left, cluster.leader_elected, cluster.leader_lost, cluster.write_forwarded, cluster.distributed_recall, cluster.snapshot_installed), Auth (auth.login, auth.register, auth.logout, auth.failed_login, auth.org_switch), Envelope (envelope.created, envelope.verified), Import (import.job_created, import.job_completed, data.imported), Region (region.failover_initiated, region.failover_completed, region.cross_border_transfer), System (system.provider_config_changed, system.admin_settings_changed), Hooks (hook.created, hook.updated, hook.deleted), and Chat (chat.thread_created, chat.thread_deleted).

Feature-gated events (CAL queries, LLM reranking, hooks, distributed operations, authentication, chat, import) compile only when the corresponding feature is enabled, keeping the binary lean for deployments that do not need them.

CategoryExample Events
Memorymemory.added, memory.forgotten, memory.corrected, memory.recalled, memory.accumulated
Consentconsent.granted, consent.revoked, processing.restricted
Securitykey.rotated, key.destroyed, user.erased, authz.access_denied
Authauth.login, auth.register, auth.logout, auth.failed_login, auth.org_switch
Policypolicy.sealed, policy.upgraded, policy.downgraded, policy.enforced
Tiertier.grain_moved, tier.compaction_run, tier.grain_promoted, tier.erasure_attempt
Agentagent.recall, agent.write
Clustercluster.node_joined, cluster.node_left, cluster.leader_elected, cluster.write_forwarded
Envelopeenvelope.created, envelope.verified
Regionregion.failover_initiated, region.failover_completed, region.cross_border_transfer
Importimport.job_created, import.job_completed, data.imported

How are actor identities protected?

Actor and subject IDs are pseudonymized using HMAC-SHA256 before storage, so plaintext user identifiers never appear in the audit trail. The HMAC key is the master encryption key itself (or a deterministic fallback derived from the data directory path when no master key is configured), ensuring that this AI agent memory system maintains privacy even in the audit log.

The pseudonymization process computes HMAC-SHA256(hmac_key, identity), truncates to 16 bytes (128 bits), and hex-encodes the result into a 32-character string. The same user always produces the same pseudonym with the same HMAC key, enabling correlation across audit entries without exposing identity. Different HMAC keys produce different pseudonyms, so audit trails from different Areev instances cannot be cross-referenced. This satisfies GDPR Art. 25 data protection by design requirements.

Pseudonymization:
  1. HMAC-SHA256(hmac_key, "john")
  2. Truncate to 16 bytes (128 bits)
  3. Hex-encode -> 32-character string

Result: "john" -> "7a3f9b2c1d4e8f05..."  (deterministic, non-reversible)

How do I query the audit trail?

Audit entries can be queried by time range, event type, and sequence number via the API or CLI. Each entry includes its sequence number, event type, pseudonymized actor, timestamp, and hash chain links.

The count_by_event() method enables compliance tooling to verify audit completeness — for example, confirming that every memory.added event has a corresponding audit entry. This context database retains audit entries indefinitely by default, though retention policies can be configured per deployment to meet specific regulatory requirements.

import requests

# Query recent audit entries
resp = requests.get("http://localhost:4009/api/memories/default/audit", params={
    "from_ms": 1709251200000,
    "limit": 50
})
entries = resp.json()
GET /api/memories/default/audit?from_ms=1709251200000&limit=50 HTTP/1.1
Host: localhost:4009
areev audit --from 2026-03-01 --to 2026-03-09 --limit 50
  • Provenance: Decision-level provenance tracking linked to audit entries
  • Crypto-Erasure: Erasure events in the audit trail
  • Encryption: Encryption of audit trail HMAC keys
  • SOC 2: SOC 2 CC7.2 audit logging requirements