# Pack format

Generated from the protocol specification, section 7. For what each check means in plain words, see [Verification packs](/docs/packs).

## The file

A single JSON file:

```json
{"format":"signafaide-pack/1","generated":"...","project":"...","project_name?":"...","env":"...",
 "service_keys":[...],"agent_keys":[{"agent","key_id","public_key","valid_from","valid_to"}],
 "filter":{"agents":null,"from":null,"to":null},
 "heads":[{"head","head_sig"}],
 "records":[{"envelope","key_id","sig","content?","salt?","receipt"}],
 "anchors":[{"anchor","anchor_sig","paths":{"<batch_hash>":{"index":0,"path":["..."]}}}],
 "export_sig":"..."}
```

`project_name` is optional: the project's name as the customer named it (1 to 200 characters, no control characters). When present it is part of the export statement, so it is signed; a verifier names the project with it in its first line. `filter` is the export's filter (`agents`: null for every agent, or the agent names; `from` and `to`: null or a time). `heads` holds the newest signed head, at export time, of each agent that has records in the pack. Every key entry has a valid `valid_from` time and a `valid_to` that is null or a time; anything else makes the pack malformed.


## Export statement

 The service signs what the pack covers, so nobody who holds the pack can change it unnoticed:

```json
{"project","project_name?","env","generated","filter","heads":[<each heads[i].head, in pack order>],"records_hash":"..."}
```

`project_name` is in the statement exactly when it is in the pack. `records_hash = sha256(JCS(list))` of every record's `receipt.record_hash`, in pack order. `export_sig` is the service's signature over domain `export` and `sha256(JCS(statement))`, by a service key active at `generated`. Every export head's `server_time` is at or before `generated`.


## Inputs besides the pack

 The service keys must come from a source independent of the pack (`--keys <file|url>`). The agent keys must too (`--agent-keys <file|url>`, the customer's §2.5 manifest from `signafaide keys export`); a key's `valid_to` is the earlier of the manifest's (the customer's signed retirement) and the pack's `agent_keys` entry for the same key (the service's record of a revocation or retirement): each can only narrow the window. Keys over plain `http://` are accepted only from a loopback address (`localhost`, `127.0.0.0/8`, `::1`), with a warning, and then do not count as independent; from any other host they are refused (exit 2). Optional: `--head <file>`, the client's §8 `head.json` (the SDK CLIs use the project's own `.signafaide/head.json` by default); `--content`; `--timestamp-check <url>`, an Esplora-style explorer API that confirms public timestamps (default `https://mempool.space/api`; `https://blockstream.info/api` also works), or `--offline`. An explorer over plain `http://` is never asked: check 11 is then not checked.
