> **Can't find what you're looking for?** Use `search_docs` on the docs MCP server at `https://docs.ampdb.io/api/mcp` to find what you need.

# Manifest Storage

A [manifest](/datasets/manifests) is the JSON document that defines a dataset: its kind, its tables and their schemas,
and for a derived dataset, its SQL and dependencies. Amp stores manifests by **content hash**, the SHA-256 hash of the
manifest's content, so the same manifest is stored once however many datasets and versions use it, and a hash always
names the same content.

Most of the time, you don't manage manifests directly: [registering a
dataset](/managing-amp/datasets#register-a-dataset) stores its manifest. This page covers the manifest commands for when
you do: generating a manifest for a raw dataset, storing one before any dataset uses it, finding a manifest by its hash,
and cleaning up the ones nothing uses. You run them with [`ampctl manifest`](/clis/ampctl/manifest) or the [Admin
API](/managing-amp/admin-api/manifests).

## Prerequisites

* Amp running, with its Admin API reachable, and `ampctl` installed, as in
  [Managing Datasets](/managing-amp/datasets#prerequisites). Generating a manifest doesn't need Amp running.

## Generate a manifest

A [raw dataset](/datasets/raw-datasets)'s manifest follows from its kind: the tables each kind extracts are fixed.
`ampctl manifest generate` writes one for you. [Derived datasets](/datasets/derived-datasets) are written by hand.

```bash
ampctl manifest generate --kind evm-rpc --network mainnet --start-block 24000000 --out eth_mainnet.json
```

Without `--out`, it prints the manifest. If `--out` is a directory, the file is named after the kind, like
`evm-rpc.json`.

| Option                        | Type    | Default  | Description                                                                                                                   |
| ----------------------------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `--kind <KIND>`               | string  | required | The dataset kind: `bitcoin-rpc`, `bittensor`, `eth-beacon`, `evm-rpc`, `solana`, `stellar`, or `tempo`, like `--kind solana`. |
| `--network <NETWORK>`         | string  | required | The network, which must match the provider's, like `--network mainnet`.                                                       |
| `--out`, `-o <PATH>`          | path    | stdout   | The file or directory to write to, like `--out eth_mainnet.json`.                                                             |
| `--start-block <START_BLOCK>` | integer | `0`      | The first block to extract, like `--start-block 100000`.                                                                      |
| `--finalized-blocks-only`     | flag    | off      | Only extract blocks the chain has finalized.                                                                                  |

## Register a manifest

Registering a manifest stores it without linking it to any dataset. A dataset can use it later by its hash, with
`ampctl dataset register acme/eth_mainnet HASH --tag 1.0.0`.

:::code-group
```bash [ampctl]
ampctl manifest register ./eth_mainnet.json
```

```bash [Admin API]
curl -X POST http://localhost:1610/manifests \
  -H 'Content-Type: application/json' \
  -d @eth_mainnet.json
```
:::

```
✓ Manifest registered successfully
→ Manifest hash: b9e2ebd92c0752ba8a61a233f9cc5d3f4f8b601b1b789a882a5dd8ece9bca56b
```

The Admin API answers `201 Created` with `{"hash": "b9e2ebd9…"}`.

* **The hash comes from the content, not the file.** Amp validates the manifest and computes its hash from a canonical
  form of its JSON, so formatting and key order don't change it. Registering the same content again returns the same
  hash.
* **It's validated like a dataset's.** A derived manifest's SQL must plan against its dependencies, which must already
  be registered. A manifest that fails gets `400 Bad Request` with an error code saying why, like `INVALID_MANIFEST` or
  `MANIFEST_VALIDATION_ERROR`.
* **The path** can be a local file or a `file://`, `s3://`, `gs://`, or `az://` URL. Object storage uses its usual
  credentials from the environment.

To keep the hash in a script, use `--json`:

```bash
HASH=$(ampctl manifest register ./eth_mainnet.json --json | jq -r .hash)
```

## List manifests

List every stored manifest, with how many datasets use it:

:::code-group
```bash [ampctl]
ampctl manifest list
```

```bash [Admin API]
curl http://localhost:1610/manifests
```
:::

```
Manifests:
  b9e2ebd92c0752ba8a61a233f9cc5d3f4f8b601b1b789a882a5dd8ece9bca56b - 1 dataset
  d22760ee354621db13e962cd4e26f71dcb57e1b36f24bd93a8452c88fdbf38e1 - 0 datasets
```

`ampctl manifest ls` is an alias. The Admin API also returns each manifest's `kind`. A manifest no dataset uses, with 0
datasets, is **orphaned**. To list only those:

```bash
ampctl manifest list --json | jq -r '.manifests[] | select(.dataset_count == 0) | .hash'
```

To see which datasets use a manifest, use the Admin API:

:::terminal
```bash
curl http://localhost:1610/manifests/b9e2ebd92c0752ba8a61a233f9cc5d3f4f8b601b1b789a882a5dd8ece9bca56b/datasets
```

```json
{
  "hash": "b9e2ebd92c0752ba8a61a233f9cc5d3f4f8b601b1b789a882a5dd8ece9bca56b",
  "datasets": [{ "namespace": "acme", "name": "eth_mainnet", "version": "1.0.0" }]
}
```
:::

It lists the versions tagged with the manifest, never `latest` or `dev`.

## Inspect a manifest

Print a manifest by its hash:

:::code-group
```bash [ampctl]
ampctl manifest inspect b9e2ebd92c0752ba8a61a233f9cc5d3f4f8b601b1b789a882a5dd8ece9bca56b
```

```bash [Admin API]
curl http://localhost:1610/manifests/b9e2ebd92c0752ba8a61a233f9cc5d3f4f8b601b1b789a882a5dd8ece9bca56b
```
:::

`ampctl manifest get` is an alias. To save it to a file, redirect the output:
`ampctl manifest inspect b9e2ebd9… > manifest.json`. To get a dataset version's manifest by name instead, use
[`ampctl dataset manifest`](/managing-amp/datasets#get-a-manifest).

## Remove a manifest

:::code-group
```bash [ampctl]
ampctl manifest rm d22760ee354621db13e962cd4e26f71dcb57e1b36f24bd93a8452c88fdbf38e1
```

```bash [Admin API]
curl -X DELETE http://localhost:1610/manifests/d22760ee354621db13e962cd4e26f71dcb57e1b36f24bd93a8452c88fdbf38e1
```
:::

`ampctl manifest remove` is an alias. A manifest a dataset uses can't be removed: the Admin API answers
`409 Conflict` with `MANIFEST_LINKED`. Remove the dataset or its version first (see
[Remove a dataset](/managing-amp/datasets#remove-a-dataset)). Removing a manifest that doesn't exist succeeds
(`204 No Content`), so you can safely run it again.

## Prune orphaned manifests

Remove every manifest no dataset uses:

:::code-group
```bash [ampctl]
ampctl manifest prune
```

```bash [Admin API]
curl -X DELETE http://localhost:1610/manifests
```
:::

```
✓ Pruned 15 orphaned manifest(s)
```

The Admin API returns `{"deleted_count": 15}`. A manifest that fails to delete is skipped and the others still are, so
the count can be lower than the number of orphaned manifests. Pruning is safe to run again, and to run on a schedule.

Removing a dataset already deletes the manifests only it used, so orphans come from manifests registered on their own,
and from versions removed one at a time.

## Authorization

When a gateway passes the caller's permissions in the `amp-capabilities` header (see
[Admin API](/managing-amp/admin-api)), `ampctl manifest list` only lists manifests used by a dataset in a namespace you
can read, and only counts those datasets. Orphaned manifests aren't listed. The other manifest commands and endpoints
(inspecting, removing, and pruning manifests, and listing a manifest's datasets) aren't scoped by namespace: they work
on every manifest.

Without the header, nothing is restricted. See [Managing Datasets](/managing-amp/datasets#authorization).
