Faramesh Docs
Concepts

Auditing

Decision Provenance Records, the hash-chained WAL, KMS signing, and how Faramesh proves what happened.

Faramesh records every decision into a Decision Provenance Record (DPR), writes it to a hash-chained WAL, and optionally signs it with an external KMS. The result is a sequence you can verify end-to-end with one command.

This page covers what's in a DPR, how the chain is built, how to verify it, and how to ship the stream into your SIEM.

What a DPR contains

Every permit, defer, deny, budget_warning, and rate_exceeded produces a DPR. The schema (version dpr/2.0) carries:

FieldDescription
idULID for the decision. Returned to the SDK as action-<ulid>.
timeRFC3339 timestamp.
lamport_seqPer-agent monotonically increasing sequence. Makes ordering total.
agent_idAgent identity as resolved by the identity provider.
agent_svidSPIFFE id, if a SPIFFE provider is configured.
toolTool name.
action_typetool_call, delegate, completion_event, model_call.
args_hashSHA-256 of the redacted argument tree.
effectpermit, defer, deny.
rule_refFile + line of the rule that fired (governance.fms:12).
rule_digestHash of the compiled rule AST node.
policy_versionHash of the full compiled AST.
denialStructured denial payload (when applicable). See errors.
credential_refProvider id + scope hash if a credential was minted.
costTokens and dollars (from the cost provider).
latency_msPipeline timing per stage.
delegation_chainParent decisions if this call came from a delegation.
prev_hashSHA-256 of the previous DPR.
signatureDetached signature over the canonical DPR bytes.

Args are never stored raw. Only the SHA-256 of the redacted-args tree is in the DPR. The redacted args themselves go to the audit sink stream, where you control retention and access.

The hash chain

Output
DPR(n-1)  ──hash──►   prev_hash field of DPR(n)   ──KMS sign──►   signature field

Each DPR carries the hash of the previous DPR. A break in the chain (prev_hash mismatch) signals tampering or a missing record. The first DPR after a faramesh apply carries the policy version hash so you can prove which policy was in force during which window.

Signatures

Two signing modes:

ModeWhere the key livesWhen to use
LocalEphemeral ed25519 key on diskLocal runs and CI. Chain verifies; tampering requires writing both DPRs and the key.
External KMSAWS KMS, GCP KMS, or HashiCorp Vault TransitProduction. The daemon never holds the private key; an attacker with root cannot re-sign forged segments.

Configure the KMS provider in governance.fms:

governance.fms
provider "kms-aws" {
  type    = "aws-kms"
  region  = "us-east-1"
  key_arn = "arn:aws:kms:us-east-1:123456789012:key/abc-123"
}

The daemon batches DPR signing, calls return immediately on permit and the signature is added asynchronously. The signing latency does not block tool execution.

The WAL

The WAL is the append-only log that backs the DPR chain. By default it lives in wal_dir (set in runtime { ... }) as a sequence of sealed segments plus an active segment:

Output
faramesh-wal/
├─ active.wal              ← currently being written
├─ 00000001.wal            ← sealed
├─ 00000001.wal.manifest   ← segment manifest with hash root
├─ 00000002.wal            ← sealed
└─ ...

Sealed segments are immutable; a tampered byte breaks the manifest hash.

Backends:

BackendUse
sqliteDefault. Local file. Suitable for single-host stacks.
postgresProduction. WAL is replicated as a Postgres table; multi-daemon stacks share state.

runtime { backend = "postgres" } plus a connection string switches you over without policy changes.

Verification

The CLI walks the chain and verifies every signature:

Terminal
faramesh audit verify
faramesh audit verify --from 2026-05-01 --to 2026-05-31

Example output:

Verifying WAL segments 1..12 (122,041 DPRs)
  signature scheme  : aws-kms (arn:aws:kms:...:key/abc-123)
  chain hash root   : ok
  per-segment manifests : 12/12 ok
  policy continuity : 4 policy versions, no gaps
✓ Chain is intact.

Any failure prints the first offending DPR id and the field that broke (prev_hash mismatch, signature invalid, args_hash mismatch).

faramesh explain

For a single decision, faramesh explain <action-id> reconstructs the full pipeline:

Decision  action-01JTX5Y0K9
Time      2026-05-17T13:42:18Z
Agent     payments-bot   (spiffe://corp.faramesh.dev/agents/payments-bot)
Tool      stripe/charge
Effect    permit
Rule      governance.fms:12  permit stripe/charge if amount < $500
Args      { amount: 240.00, currency: "USD" }
          (raw args read from audit-splunk; redacted: card_number, cvv)
Credential vault://kv/data/payments/stripe-token  (issued 13:42:18, ttl 30s)
Cost      $0.0021  (cost-static@1.0.0)
Latency   policy 0.7ms · credential 4.1ms · execute 142ms · total 146.9ms
Signature ok (aws-kms key/abc-123)
Chain     prev_hash matches; chain intact back to 00000001.wal

Streaming to your SIEM

DPRs are also fanned out to audit sinks for downstream consumption. The WAL is authoritative, the sink stream is a copy for indexing and search.

Built-in sinks:

SinkConfiguration
Splunk HECsplunk-sink provider
Datadog Logsdatadog-sink provider
Elasticelastic-sink provider
S3s3-sink (NDJSON files per hour)
GCSgcs-sink
Webhookwebhook-sink
stdoutDefault in local runs

See Providers → audit sinks.

What's redacted, what's logged

FieldIn DPRIn sink stream
Tool nameYesYes
Args (named in redact)Hash onlyMasked tokens (***)
All other argsHash onlyFull value
Credential valueNeverNever
Credential ref / scope / TTLYesYes
Rule that firedYes (rule_ref)Yes
Result codeYesYes
Latency breakdownYesYes

You never put raw secrets in the audit chain. Anything an operator might be tempted to log is configurable via redact.

Compaction and retention

Sealed segments older than wal_retention are compacted into a single signed manifest plus a per-DPR digest index. The full bodies move to the audit sink for long-term storage; the chain stays intact because each compacted segment keeps its manifest hash.

governance.fms
runtime {
  wal_retention = "90d"
}

faramesh audit verify --include-archived walks both the live WAL and the compacted manifests.

Compliance affordances

  • GDPR / right-to-erasure. Redact-by-default for any field that may contain PII. The DPR records only a hash; the sink retention controls where raw values live.
  • SOC 2 / evidence. faramesh audit export --from --to --format csv produces a per-decision CSV with the full pipeline. KMS signature metadata is preserved.
  • PCI / financial. Use redact <tool> args: ["card_number", "cvv"] and a KMS that produces FIPS-validated signatures. The chain is your tamper-evidence boundary.

What's next

On this page