Governed & Auditable Agent Messaging
The problem
When an agent lives in a chat channel, three questions come up fast:
- What happened? — A user reports a bad response. You need to reconstruct the exact sequence: what was sent, what policy applied, which agent handled it, what was delivered.
- What should be blocked? — Compliance needs certain content filtered before it reaches the agent or before the agent's response reaches users.
- Can we prove it? — Audit requires a tamper-evident record of every message path outcome, including denied and failed deliveries.
Scattered logs across chat platform APIs, agent runtimes, and custom middleware cannot answer these questions reliably.
How CAR solves it
Canonical 7-event chain
Every message produces a complete event chain in the ledger:
message.received ← inbound message canonicalized → policy.decision.made ← governance verdict (allow / deny) → route.decision.made ← which agent handles this → agent.invocation.requested → agent.response.completed → message.send.requested → message.sent ← delivery confirmed If denied or failed: → event.blocked ← reason, stage, and context preserved
Every event carries correlation_id and causation_id, linking the full causal chain. The ledger is append-only — events are never modified or deleted.
Inbound and outbound policy
Define policy rules in YAML. CAR evaluates them on the message path before routing (inbound) and before delivery (outbound):
rules:
- name: block-sensitive-keywords
match:
keywords: ["SSN", "credit card", "password"]
action: deny
reason: "Sensitive content detected"
- name: allow-support-channel
match:
channel_pattern: "support-*"
action: allow
Blocked messages produce event.blocked in the ledger with the denial reason — the outcome is auditable, not silent.
Replay and query
The HTTP API exposes the ledger for querying:
$ curl http://localhost:3000/api/conversations/conv_abc/events [ { "type": "message.received", "correlation_id": "req_123", ... }, { "type": "policy.decision.made", "payload": { "decision": "allow" }, ... }, { "type": "route.decision.made", ... }, { "type": "agent.invocation.requested", ... }, { "type": "agent.response.completed", ... }, { "type": "message.send.requested", ... }, { "type": "message.sent", ... } ]
What you get
Full message path visibility
Reconstruct any message's journey from ingress to delivery (or denial) using correlation IDs and the canonical event chain.
Policy-as-config
Keyword, regex, and custom policy rules in YAML. Inbound filters before the agent sees the message; outbound filters before delivery.
Append-only ledger
SQLite-backed durable storage. Events are never modified. Query by conversation, correlation, or time range.
Structured failure outcomes
Denied and failed deliveries produce event.blocked with stage, reason, and context — no silent drops.