---
title: Agent Ledger
description: Read Titan's hash-chained record of every agent decision, execution
  and control, filter it, and verify that nothing was changed or removed.
url: https://hexelstudio.com/docs/titan/agent-ledger
---

The Agent Ledger is an append-only record of what Titan decided and did for your agents in one Titan deployment. Titan writes each entry in the same database transaction as the decision or action it records. Each entry carries the SHA-256 digest of the one before it, so changing or removing an entry breaks the chain.

## What an entry holds

Entries hold identifiers, outcomes and digests only. They never contain tokens, credentials, tool arguments, request or response bodies, or your policy source.

| Field | Meaning |
| --- | --- |
| `seq` | Position in the chain, from 1 |
| `event_type` | `decision` (Titan allowed, denied or asked for approval), `execution` (an action ran and how it ended), `control` (quarantine, kill and similar), `session_control` (suspend, resume, revoke), `lifecycle` |
| `outcome`, `reason_code` | What happened and why, for example a denial with `environment_frozen` |
| `agent_id`, `deployment_id`, `session_id`, `runtime_principal_id` | Which agent, agent deployment, session and runtime identity |
| `capability_id` | The capability, for example `slack.message.post` |
| `workspace_id`, `environment_id`, `organization_id` | Where it happened |
| `subject_id` | The record behind the entry, such as an execution or a control event |
| `executor_code` | The executor's own refusal code, when it refused before running the action |
| `created_at` | When it was written |
| `prev_digest`, `entry_digest` | The chain: `entry_digest` is SHA-256 of `prev_digest` followed by the entry's canonical JSON (RFC 8785) |

## Read the Ledger

You need the `titan:ledger:read` permission. In the console, open **Titan → Ledger**. With the CLI:

```bash
hexel titan ledger list --limit 20
hexel titan ledger list --after 300 --type execution --outcome failed
```

With the API:

```bash
curl "https://api.hexelstudio.com/v1/titan/admin/ledger?order=desc&limit=20&reason_code=environment_frozen" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Titan-Enforcement-Deployment: $TITAN_ENFORCEMENT_ID"
```

| Query parameter | Meaning |
| --- | --- |
| `order` | `asc` (oldest first) or `desc` (latest first) |
| `after`, `before` | Only entries with a `seq` above or below this; use them to page |
| `limit` | How many entries to return |
| `event_type`, `outcome`, `reason_code` | Exact-match filters |
| `agent_id`, `deployment_id`, `session_id`, `capability_id`, `workspace_id`, `environment_id`, `runtime_principal_id` | Exact-match filters |

## Verify the chain

Verification recomputes every digest from the start of the chain to the newest entry, and reports where the chain breaks if it does.

```bash
hexel titan ledger verify
```

```bash
curl https://api.hexelstudio.com/v1/titan/admin/ledger/verify \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Titan-Enforcement-Deployment: $TITAN_ENFORCEMENT_ID"
```

| Field | Meaning |
| --- | --- |
| `ok` | `true` when every entry's digest matches |
| `count` | Entries checked |
| `head_seq`, `head_digest` | The newest entry and its digest. Keep `head_digest` to show later that the chain up to it hasn't changed. |
| `broken_at_seq` | The first entry whose digest doesn't match, when `ok` is `false` |
| `pruned_through_seq`, `pruned_through_digest` | Where checking starts when older entries have been removed by a retention setting. On Titan Cloud nothing is pruned. |

The CLI exits with status 1 when the chain is broken, so you can run `hexel titan ledger verify` from a scheduled job.
