# Seal and verify.

> Turn one encrypted capture into a portable evidence package, inspect its canonical OpenTelemetry trace, and verify the entire package offline.

Part of the Exalto Capture docs. Page: https://capture.exalto.ai/docs/trace-packages. Every page is listed in https://capture.exalto.ai/llms.txt; the whole site in one file is https://capture.exalto.ai/llms-full.txt.

## Seal one interaction

Select a Captured Trace in the native app, local dashboard, command line or administration API. The service atomically commits `trace-packages/<trace-id>.llmtrace`, records that exact package in Trace metadata, and retains the encrypted source capture.

```sh
capture traces seal trc-example --wait
```

```http
POST /v1/traces/{trace_id}/notarizations
```

Sealing is asynchronous. Without `--wait`, the response carries an `op-…` operation identifier; poll `GET /v1/operations/{operation_id}` until its `state` is `succeeded`, `failed` or `interrupted`.

1. **Select a compatible notary.** Hosted use refreshes the Exalto Seal Registry, selects a worker compatible with the capture, and checks the resulting evidence against locally pinned key history. For local or self-hosted use, set `notary.endpoint` and `notary.public_key` together in `config.toml`.
2. **Open a fresh session.** The original provider stream and proxy no longer need to be running. A new notary session using the compatible signing identity can finish the work from the encrypted local capture.
3. **Commit the package.** The service writes the package atomically, records its exact identity, and keeps the private capture so the operation remains retryable.

> **Proof generation takes time**
>
> Private proof generation is slower than capture. Deferring it keeps the interactive response fast and makes proof work an explicit background or batch operation. If sealing fails or the service stops, retry through `POST /v1/traces/{trace_id}/notarizations`. The capture is not consumed, but interrupted proof computation starts over.

## Follow the evidence boundary

**Captured.** Private retry state on this device. Nothing here is independently verifiable yet. Path: Provider interaction → Local encrypted capture → Ready to seal.

-   `capture.llmcapture`, private: Vault-encrypted request, response, and deferred TLS state
-   `Authenticated HTTP`, pending: Created only when this Trace is sealed
-   `trace.otlp.json`, pending: No portable OpenTelemetry evidence yet
-   `Portable package`, none: The Trace remains local and unshared

**Sealed.** Portable evidence whose disclosed bytes and derived trace can be verified offline. Path: Encrypted capture → Compatible notary → Verifiable .llmtrace.

-   `evidence.tlsn`, signed: Notary signature and authenticated provider TLS session
-   `disclosed HTTP`, authenticated: Bodies are disclosed; header values are hidden by default
-   `trace.otlp.json`, derived: Deterministic GenAI mapping of authenticated bytes
-   `archive-manifest.json`, bound: Ordered sizes and hashes bind the package together

Captured is sensitive, private retry state. Sealed is the portable state: authenticated TLS evidence, disclosed HTTP bytes, deterministic OpenTelemetry, and a manifest that binds the archive together.

## Inspect the package

```text
<trace-id>.llmtrace (ZIP)
├── archive-manifest.json
├── evidence.tlsn
├── manifest.json
├── request.disclosed.http
├── response.disclosed.http
└── trace.otlp.json
```

| Artifact | Responsibility |
| --- | --- |
| `archive-manifest.json` | Defines the deterministic archive format, ordered entry sizes and hashes, and package digest. |
| `evidence.tlsn` | Carries the cryptographic TLSNotary evidence and notary signature. |
| `request.disclosed.http` | Contains authenticated request bytes selected for disclosure. Header values are hidden except the structural value `Transfer-Encoding: chunked`; the body remains disclosed. |
| `response.disclosed.http` | Contains the authenticated provider response, including streamed events. Header values follow the same default-deny rule; the body remains disclosed. |
| `trace.otlp.json` | Maps authenticated bytes deterministically into OpenTelemetry GenAI data, including text, model-emitted tool calls, correlated tool results, model, and usage. |
| `manifest.json` | Records versioned source metadata and the trace hash. The cryptographic signature lives in `evidence.tlsn`, not in this JSON file. |

The `.llmtrace` package carries all cryptographic evidence and can be verified independently. A shared Trace is a readable view derived from that package and retains the exact admitted bytes for export and independent verification.

## Verify a portable package

Use the local CLI to verify on your machine, or upload the package at [seal.exalto.ai/verify](https://seal.exalto.ai/verify). The hosted page checks a `.llmtrace` file without saving it. The CLI accepts either a Trace held by the local service or a `.llmtrace` file.

```sh
capture --json traces verify trc-example
capture --json traces verify ./capture.llmtrace
```

The result's `outcome` is `passed`, `failed` or `unsupported`, with `verified_at_unix_ms`, `notary_key_id`, `trust_source` and, on failure, a `failure_code`. Report exactly that; opening a package is not verifying it.

The same check is available without installing anything. Send the package bytes to the hosted verifier and read `verified`, the authenticated `provider` and `host`, `authenticated_at_unix_ms`, `notary_key_id`, `trust_source` and the package and content digests:

```sh
curl -fsS https://api.exalto.ai/api/verify \
  -H 'Content-Type: application/vnd.exalto.notary.trace-package+zip' \
  --data-binary @capture.llmtrace
```

For a Trace already held by the local service:

```http
GET /v1/traces/{trace_id}/package.llmtrace
POST /v1/traces/{trace_id}/verify
```

Verification checks:

-   The notary signature and expected notary public key.
-   The authenticated provider identity and TLS evidence.
-   The disclosed HTTP bytes against the cryptographic evidence.
-   Every artifact hash named by the package manifest.
-   The deterministic, versioned OTLP mapping byte-for-byte.

### Offline trust

Verification does not contact the provider or a live notary. It uses the notary key history already cached by the service, or `notary.public_key` for a self-hosted endpoint. A hosted service must successfully refresh its Registry before it can trust previously unseen evidence.

## Review before sharing

A `.llmtrace` can include system context, tool definitions, session metadata, prompts, responses, and tool results. All HTTP header values are hidden by default, but request and response bodies remain disclosed. Inspect the package before sharing it. The encrypted `.llmcapture` is private retry state and must stay local.

> **Tool-use boundary**
>
> Verification proves that the model emitted a tool call and, on a later request, that the client sent a particular tool result. It does not prove that the local tool executed or that its reported output was truthful.
