For decisions made about AI agents (which tool calls were allowed, which were denied, who approved what), there is a better option that is not complicated. This piece explains the signed heartbeat I/O Mesh writes over its audit records, and how to check one yourself.
The v1 fact
I/O Mesh writes one audit record per decision. Allows and denies alike.
Over those records, it emits heartbeats. A heartbeat is a signed SHA-256 digest of a window of records, linked to the previous heartbeat. A new heartbeat is emitted after 100 records or 60 seconds, whichever comes first, and only when at least one record is pending.
You verify them offline with the auditor public key.
That is the entire mechanism. The rest of this article unpacks why each part is there.
The parts, one at a time
A window of records. Records are grouped into consecutive windows. A window closes after 100 records or 60 seconds when at least one record is pending. A quiet interval does not emit an empty heartbeat.
A digest. For each window, a SHA-256 digest is computed over the records in it. Change one byte in one record and the digest changes. Remove a record and the digest changes. Reorder records and the digest changes.
A link to the previous heartbeat. Each heartbeat includes a reference to the one before it. That makes the heartbeats a chain. You cannot quietly drop a whole window, or splice in a replacement window, without breaking the link from the next heartbeat.
A signature. The heartbeat is signed. The matching public key is the auditor public key. Anyone with that public key can check that the heartbeat was produced by the holder of the signing key and has not been altered since.
Put together: records are fixed by the digest, windows are fixed in order by the chain, and the chain is attributable by the signature.
What this protects against
A few specific scenarios:
- Editing a record after the fact. Someone changes a deny to an allow, or swaps the approver name. The window digest no longer matches.
- Deleting an embarrassing record. The window digest no longer matches.
- Deleting a whole window. The next heartbeat's link points to a heartbeat that is missing. The chain breaks.
- Truncating the end. This one needs care. If someone drops the last few heartbeats, the remaining chain is still internally valid. You detect truncation by comparing the latest heartbeat you hold against what you expect: the time of the last heartbeat versus the export time, or a heartbeat you recorded independently earlier. Idle time alone is not a finding: a quiet interval emits no heartbeat.
- Swapping in a fabricated log. Without the signing key, the forger cannot produce valid signatures that check against the auditor public key.
What it does not protect against: a compromised signing key, or a decision that was wrong but correctly recorded. The heartbeat proves integrity of the record. It says nothing about whether the policy was good.
The export bundle
You do not need access to the production store to verify. I/O Mesh produces an export bundle with four things in it:
- the audit records
- the heartbeats
- the auditor public key
- a manifest
The bundle is designed to be verified without the store. Copy it to your own machine, disconnect it from the network if you like, and check it.
One process point. The auditor public key ships in the bundle for convenience. For a real audit you should also obtain the public key through a separate channel, ahead of time, and confirm it matches. Otherwise a forged bundle could carry a forged key. This is the same reason you do not trust a certificate just because it came attached to the thing it signs.
How to check one: the steps
The exact tooling will vary, but the logic is the same for any hash-linked signed chain. In order:
- Confirm the key. Compare the auditor public key in the bundle to the one you received independently.
- Check the manifest. Make sure every file it lists is present and nothing extra is in the bundle that you were not told about.
- Walk the heartbeats in order. For each heartbeat:
- verify the signature with the auditor public key
- confirm it links to the previous heartbeat
- recompute the SHA-256 digest of its window of records and compare it to the digest in the heartbeat
- Check the ends. Note the first and last heartbeat times. Compare them to the period you asked for. A quiet stretch with no pending records will not produce heartbeats; do not treat idle gaps as missing windows. Compare the latest heartbeat to the export time, or to a heartbeat you recorded independently earlier, if you need to spot a truncated end.
- Then sample. Once integrity checks pass, sample records for substance: was the caller who you expected, did money-movement allows carry an approver who is a different registered person, do denies carry a reason.
Steps 1 through 4 tell you the record is what the system wrote. Step 5 is the audit you were going to do anyway, now on a record you can rely on.
Reading the records
A few things worth knowing when you start sampling.
Denies have reasons, on the record only. The agent that asked receives a plain deny for every cause. The reason is written to the audit record. So when you look at a deny, you should see why: an exact-deny match, a policy miss, a missing or spent approval, or a fail-closed condition.
Fail-closed events are decisions too. If the audit write failed, there is no record, because the decision service denies when it cannot record. If the store errored, the deadline passed (default 5 seconds), confidence was uncertain, or the grant map was full, the result is deny and no grant is stored. If an allow cannot be delivered, the grant is dropped; the audit record for that decision is an allow, and the caller gets no usable answer. When an engineer tells you "the system was down so the agent couldn't act," the design supports that claim.
The caller is a verified identity. The caller on a record is the mapped subject of a verified OIDC bearer token, typically from the organization's existing issuer such as Okta or Entra. It is not a free-text field the agent fills in.
Approvals are named. For tagged classes (money movement, production change, customer-data export), the allow depends on a single-use approve receipt naming the department, tool, class, caller, approver, window, and nonce. The approver must be a registered person other than the caller.
Questions to put to the engineering team
If you are reviewing a deployment, these are reasonable asks:
- Where is the signing key held, and who can access it?
- How was the auditor public key delivered to us, and through which channel?
- What is the retention period for records and heartbeats, and is anything pruned before a verified export exists?
- Has anyone run the verification steps against a real export, and can we see the output?
- What happens operationally when the audit write fails? (Expected answer: the agent's action is denied.)
Limits
A signed heartbeat chain is evidence that a log is intact and attributable. It is not a certification of the system, and it does not by itself satisfy any regulation. It makes the evidence you are already asking for easier to trust, and easier to check without taking anyone's word for it.
I/O Mesh runs in your own environment. Learn more at iome.sh, or email hello@iome.sh to talk with us about Enterprise.