Skip to content

About

AI Catalog CLI

Resources

Code of conduct

Contributing

Security policy

Stars

12 stars

Watchers

0 watching

Forks

ai-catalog-cli

OpenSSF Scorecard

Command-line tool for inspecting, validating, and packaging AI Catalog documents.

Resource Link
Specification https://agent-card.github.io/ai-catalog/
Upstream repository https://github.com/Agent-Card/ai-catalog
Rust libraries https://github.com/Agent-Card/ai-catalog-rust

The crate is named ai-catalog-cli; the installed binary is ai-catalog.

Install

On macOS and Linux, install from the tap in this repository:

brew tap Agent-Card/ai-catalog-cli https://github.com/Agent-Card/ai-catalog-cli
brew trust Agent-Card/ai-catalog-cli
brew install ai-catalog

On Windows, install with WinGet:

winget install --id AgentCard.AICatalog --exact

Open a new terminal afterwards so the ai-catalog command is on your PATH. Upgrade later with winget upgrade --id AgentCard.AICatalog --exact.

Prebuilt binaries for Linux, macOS, and Windows are attached to each release. Download the archive for your platform, verify it against the accompanying .sha256 file, and place ai-catalog on your PATH:

VERSION=v0.1.0
NAME=ai-catalog-darwin-arm64   # see the release page for other platforms
BASE=https://github.com/Agent-Card/ai-catalog-cli/releases/download/$VERSION

curl -fsSLO "$BASE/$NAME.tar.gz" -O "$BASE/$NAME.sha256"
shasum -a 256 -c "$NAME.sha256"
tar -xzf "$NAME.tar.gz"
install -m 0755 ai-catalog /usr/local/bin/

Linux archives come in gnu (glibc 2.28 or newer) and musl (statically linked) flavours; pick musl for Alpine or other non-glibc distributions.

With a Rust toolchain installed:

cargo install ai-catalog-cli

From a checkout of this repository:

cargo install --path .

Or run without installing, replacing ai-catalog with cargo run -- in any example below:

cargo run -- --help

Agent skill

SKILL.md follows the Agent Skills standard and teaches an AI agent to use this CLI to discover, inspect, and install AI artifacts from a catalog. It requires the ai-catalog binary on PATH.

Each skill is loaded from a directory named after it, so install it as:

mkdir -p ~/.agents/skills/ai-catalog-cli
cp SKILL.md ~/.agents/skills/ai-catalog-cli/

~/.agents/skills/ is read by Cursor, Copilot, VS Code, Codex, and Gemini CLI. For Claude Code, use ~/.claude/skills/ instead.

Development

just build          # cargo build
just lint           # fmt --check + clippy -D warnings
just test           # cargo test
just coverage       # llvm-cov summary

This CLI builds on the four AI Catalog library crates, released separately from Agent-Card/ai-catalog-rust: ai-catalog, ai-catalog-validate, ai-catalog-trust, and ai-catalog-oci.

CLI reference

ai-catalog validate [--json] <path|->
ai-catalog verify [--json] [--did-document <DID=PATH>]... [--offline] [--strict] <path|->
ai-catalog format <path|->
ai-catalog oci pack <path|->
ai-catalog oci unpack <path|->
ai-catalog oci export-layout [--tag <tag>] [--cosign-key <path>] [--cosign-public-key <path>] [--sigstore-services <tlog,tsa>] [--signing-config <path>] <path|-> <layout-dir>
ai-catalog oci unpack-layout [--ref-name <name>] <layout-dir>
ai-catalog oci push [--tag <tag>] [--plain-http] [--insecure] [--to-oci-layout-path <layout-dir>] [--cosign-key <path>] [--cosign-public-key <path>] [--sigstore-services <tlog,tsa>] [--signing-config <path>] <path|-> <target>
ai-catalog oci add <name> <layout-dir> [--ref-name <tag>]
ai-catalog oci search [--regex] [-n <limit>] [--json] <keyword>
ai-catalog oci show [--json] [--media-type <type>] <identifier>
ai-catalog oci pull [--output <path>] [--media-type <type>] <identifier>
ai-catalog catalog add <name> <url>
ai-catalog catalog list [--json]
ai-catalog catalog remove <name-or-url>
ai-catalog catalog update <name>
ai-catalog search [--regex] [-n <limit>] [--json] <keyword>
ai-catalog show [--scope <catalog-name-or-url>] [--json] [--media-type <type>] <identifier>
ai-catalog pull [--output <path>] [--scope <catalog-name-or-url>] [--media-type <type>] <identifier>
ai-catalog --version

Use - as <path> to read from stdin. Every command accepts --help.


validate

Validates a catalog document against the AI Catalog specification and reports its structural conformance level (Minimal or Discoverable). The Trusted level requires verifying signatures and artifacts; use verify for that.

ai-catalog validate catalog.json          # text report
ai-catalog validate --json catalog.json   # JSON report
cat catalog.json | ai-catalog validate -  # from stdin

Exits with code 0 on success, 1 on validation errors.

With --json, each error and warning has a stable code (for example entry-duplicate) next to its path and message. Match on the code rather than the message. code is null when the input could not be parsed.


verify

Validates a catalog and verifies the signatures and artifacts of its root entries, using ai_catalog_validate::verify.

ai-catalog verify catalog.json
ai-catalog verify --json catalog.json
ai-catalog verify --offline --did-document did:web:example.com=did.json catalog.json

For each trust manifest it reports the did-web-v1 signature (signer, protected header, assertionMethod key in the signer's root did:web document, validity period, and the detached ES256 JWS) and the release binding of its subject to the entry. For each entry it reports whether the publisher endorsed it and, once a manifest is accepted, whether the artifact matches digest. The catalog's conformance level is Trusted only when an entry has a verified publisher endorsement and none fails.

DID documents and artifacts are fetched over HTTPS only, without redirects, with size and time limits, and refusing private, loopback, and link-local addresses. --did-document DID=PATH supplies a DID document locally, and --offline never fetches.

Each check is verified, failed, or unverifiable (it could not run, for example a fetch skipped with --offline). Exits with 1 when the catalog is invalid or any check fails; with --strict, also when a check is unverifiable.


format

Pretty-prints a catalog document to stdout without modifying the source file.

ai-catalog format catalog.json
cat catalog.json | ai-catalog format -

catalog add

Fetches a catalog from a URL, a domain or a local file, stores all catalog blobs in the local content-addressed cache, and registers the catalog in the local registry. Nested catalogs are fetched recursively (up to depth 4).

ai-catalog catalog add my-registry https://example.com/ai-catalog.json
ai-catalog catalog add example     https://example.com    # or just: example.com
ai-catalog catalog add local-demo  file:///path/to/catalog.json

Makes network requests. All other consumer commands operate on the local cache.

A domain or an https:// URL does not have to be the catalog itself. If it isn't one, the CLI follows the specification's discovery procedure: a Link header with rel="ai-catalog", then an HTML <link rel="ai-catalog"> element, then /.well-known/ai-catalog.json. The catalog that is found is the one that gets registered, under its own URL, which is what catalog update fetches again. If nothing is found, the error lists every URL that was tried. Files and http:// URLs are used as they are, without discovery.

References inside a catalog must be https (or relative to the catalog). A local file:// path is followed only from a local catalog, so a remote catalog can't read your disk. Cycles, http:// references and nesting beyond depth 4 are skipped with a warning, and catalogs are limited to 10 MiB.


catalog list

Lists all catalogs registered in the local registry.

ai-catalog catalog list
ai-catalog catalog list --json

catalog update

Re-fetches a registered catalog from its source URL and refreshes the local cache. Accepts a catalog name.

ai-catalog catalog update my-registry

catalog remove

Removes a catalog from the local registry by name or source URL. Also removes the cached object blob if no other registered catalog references it.

ai-catalog catalog remove my-registry
ai-catalog catalog remove https://example.com/ai-catalog.json

search

Searches entries across all registered catalogs (all sources).

ai-catalog search "finance agent"                # substring match
ai-catalog search --regex "urn:example:(agent|data).*"
ai-catalog search --json dataset                 # JSON output
ai-catalog search -n 5 embeddings               # limit to 5 results

Matches against identifier, displayName, description, and tags. Default limit is 50.


show

Shows full details of a single catalog entry by identifier.

ai-catalog show urn:example:agent:v1
ai-catalog show --json urn:example:agent:v1
ai-catalog show --scope my-registry urn:example:agent:v1  # restrict to one catalog
ai-catalog show --scope https://example.com/ai-catalog.json urn:example:agent:v1
ai-catalog show --media-type application/json urn:example:catalog:nested

--scope accepts a registered catalog name or source, or a catalog URL, which is fetched and cached on the fly without registering it.

For an entry that is itself a nested catalog, --media-type resolves its children and shows the single child of that type. Omitting it, or passing application/ai-catalog+json, shows the catalog entry itself.


pull

Downloads an entry's content to disk. For nested-catalog entries the full catalog JSON is written; for other types the raw bytes from entry.url are fetched. An http(s) URL given as the identifier is fetched as a catalog if it is not registered.

ai-catalog pull urn:example:data:dataset-v1
ai-catalog pull --output ./downloads urn:example:data:dataset-v1
ai-catalog pull --output ./report.json urn:example:data:dataset-v1
ai-catalog pull --output - urn:example:data:dataset-v1   # stream to stdout
ai-catalog pull --scope https://example.com/ai-catalog.json urn:example:agent:v1

If --output is a directory, a filename is derived from the identifier. If it is a file path, that path is used directly. - streams the artifact bytes to stdout. Omitting --output writes to the current directory.

--scope follows the same name-or-URI rules as show.

If the entry has a digest, the content is checked against it first, and a mismatch fails the pull. Signatures are not verified.

When the identifier resolves to a nested catalog entry (application/ai-catalog+json), --media-type is required:

--media-type Result
application/ai-catalog+json Writes the catalog JSON document itself
any other type Pulls the single child entry of that type; errors on 0 or more than 1 match
omitted Errors, suggesting --media-type

oci pack

Packs a catalog into the internal JSON artifact-set envelope used by the Rust library. Useful for debugging or pipeline integration when you need to inspect how the CLI represents a catalog before pushing it to an OCI registry.

ai-catalog oci pack catalog.json
cat catalog.json | ai-catalog oci pack -

Output is JSON written to stdout.


oci unpack

Unpacks an internal JSON artifact-set envelope back into AI Catalog JSON.

ai-catalog oci unpack artifacts.json

Output is JSON written to stdout.


oci export-layout

Exports a catalog as a standard OCI image layout directory. Each catalog entry is stored as a separate OCI manifest; the catalog itself becomes an OCI image index tagged with --tag.

ai-catalog oci export-layout catalog.json /path/to/layout
ai-catalog oci export-layout --tag v1.0 catalog.json /path/to/layout

With Cosign signing (see Trust manifest signing):

ai-catalog oci export-layout \
  --cosign-key cosign.key \
  --cosign-public-key cosign.pub \
  catalog.json /path/to/layout
Flag Description
--tag <tag> OCI tag to apply (default: latest)
--cosign-key <path> Path to Cosign private key; triggers signing of trust manifests
--cosign-public-key <path> Path to PEM public key (derived from --cosign-key if omitted)
--sigstore-services <list> Public Sigstore services to sign with, comma-separated: tlog (Rekor transparency log), tsa (RFC 3161 timestamp). Default: none
--signing-config <path> Cosign signing config to use instead, for example a private Sigstore deployment

Reads from stdin when <path> is -.


oci unpack-layout

Imports a standard OCI image layout back into AI Catalog JSON. Prints the reconstructed catalog to stdout.

ai-catalog oci unpack-layout /path/to/layout
ai-catalog oci unpack-layout --ref-name v1.0 /path/to/layout
Flag Description
--ref-name <name> Tag to import (default: first entry in index.json)

oci push

Pushes a catalog to an OCI registry. Internally calls oci export-layout into a temporary directory, then delegates distribution to oras cp -r.

ai-catalog oci push catalog.json ghcr.io/example/ai-catalog:latest
ai-catalog oci push --tag v1.0 catalog.json ghcr.io/example/ai-catalog:v1.0

With signing and registry options:

ai-catalog oci push \
  --cosign-key cosign.key \
  --cosign-public-key cosign.pub \
  catalog.json ghcr.io/example/ai-catalog:latest
Flag Description
--tag <tag> OCI tag (default: latest)
--plain-http Use plain HTTP instead of HTTPS
--insecure Skip TLS certificate verification
--to-oci-layout-path <dir> Also write the exported layout to this directory
--cosign-key <path> Path to Cosign private key
--cosign-public-key <path> Path to PEM public key
--sigstore-services <list> Public Sigstore services to sign with, comma-separated: tlog (Rekor transparency log), tsa (RFC 3161 timestamp). Default: none
--signing-config <path> Cosign signing config to use instead, for example a private Sigstore deployment

Reads from stdin when <path> is -. Requires oras on PATH.


oci add

Imports a local OCI image layout into the local registry. Unpacks all catalog entries from the layout and registers the catalog with a urn:ai-catalog:oci: identifier prefix.

ai-catalog oci add my-layout /path/to/layout
ai-catalog oci add my-layout /path/to/layout --ref-name v1.0
Flag Description
--ref-name <tag> Tag to import from the layout (default: first entry)

oci search

Searches entries across OCI-sourced catalogs only (those added via oci add). Accepts the same flags as search.

ai-catalog oci search embeddings
ai-catalog oci search --regex "^urn:ai-catalog:oci:"
ai-catalog oci search --json nlp
ai-catalog oci search -n 10 agent

oci show

Shows full details of an entry from OCI-sourced catalogs only. Accepts the same --media-type flag as show.

ai-catalog oci show urn:ai-catalog:oci:abc12345
ai-catalog oci show --json urn:ai-catalog:oci:abc12345
ai-catalog oci show --media-type application/json urn:ai-catalog:oci:abc12345

oci pull

Pulls an entry from OCI-sourced catalogs to disk. Accepts the same --output and --media-type flags as pull.

ai-catalog oci pull urn:ai-catalog:oci:abc12345
ai-catalog oci pull --output ./artifact.json urn:ai-catalog:oci:abc12345
ai-catalog oci pull --media-type application/json urn:ai-catalog:oci:abc12345

Local storage

The local registry lives at ~/.ai-catalog/ by default. Override with the AI_CATALOG_CACHE_DIR environment variable.

~/.ai-catalog/
├── catalog.json      # registry index (AiCatalog document)
├── refs.json         # source URL → SHA-256 hash map
└── objects/
    └── <sha256>.json # cached catalog blobs

Entries added via catalog add are stored under their source URL and use the urn:ai-catalog:local: convention. Entries added via oci add use the urn:ai-catalog:oci: prefix and are scoped separately. The plain search, show, and pull commands span all sources; the oci search / show / pull variants are restricted to OCI-sourced entries. See docs/storage.md for details.


Trust manifest signing

When --cosign-key is supplied to oci export-layout or oci push, the CLI:

  1. Canonicalizes each entry trust manifest (key-sorted JSON, signature.jws and additionalSignatures stripped)
  2. Signs the canonical blob with cosign sign-blob and a Sigstore signing config that lists only the services you choose. By default it lists none, so nothing leaves the machine. --sigstore-services tlog records each signature in the public Rekor log (permanent and public); --sigstore-services tsa adds an RFC 3161 timestamp from the Sigstore timestamp authority, which receives only a hash. --signing-config <path> passes your own config, for example a private Rekor or timestamp authority. Log entries and timestamps are kept in the Cosign bundle stored with each signature.
  3. Attaches three OCI referrer artifacts to each signed entry:
    • the canonical trust manifest (application/vnd.ai-catalog.trust-manifest.v1+json)
    • the detached Cosign signature (application/vnd.ai-catalog.cosign.signature.v1), with the Sigstore bundle from cosign sign-blob --bundle as a second layer (application/vnd.dev.sigstore.bundle.v0.3+json)
    • the public key (application/vnd.ai-catalog.cosign.public-key.v1)

Signatures live in the OCI layout as referrers, not embedded in the AI Catalog JSON. Use oras discover to inspect the referrer tree and cosign verify-blob --key cosign.pub --bundle <bundle> <payload> to verify. A bundle signed without a transparency-log entry also needs --insecure-ignore-tlog=true. See demo/trust-walkthrough.sh for a complete end-to-end example.


Environment variables

Variable Description
AI_CATALOG_CACHE_DIR Override the default cache directory (~/.ai-catalog/)
AI_CATALOG_COSIGN_BIN Path to the cosign binary (default: cosign)
AI_CATALOG_ORAS_BIN Path to the oras binary (default: oras)
COSIGN_PASSWORD Password for an encrypted Cosign private key

Demo

All demos create a temporary workspace and clean up on exit.

Demo Command Prerequisites
OCI image layout just demo-oci-layout cargo, cosign, oras
Consumer workflow just demo-consumer cargo
Trust sign & verify just demo-trust cargo, cosign, oras

OCI layout walkthrough (just demo-oci-layout)

Exercises the full OCI publish/verify flow: validate → generate Cosign key pair → oci export-layout --cosign-key → oras discover referrers → print signature and public key → oci unpack-layout round-trip → oci push to a second layout. Script: demo/oci-layout-walkthrough.sh.

Consumer workflow walkthrough (just demo-consumer)

Exercises every author and consumer command without external tools or network calls: validate, format, catalog add/list/update/remove, search (keyword, regex, JSON, limit), show (text, JSON, scoped), pull (inline-data and file-URL entries), and the full OCI consumer path (oci add, oci search, oci show, oci pull). Script: demo/consumer-walkthrough.sh.

Trust sign & verify walkthrough (just demo-trust)

Demonstrates the complete trust manifest lifecycle: validate → generate Cosign key pair → sign via oci export-layout --cosign-key → oras discover referrer tree → extract canonical trust manifest and detached signature → cosign verify-blob → tamper detection → oci unpack-layout round-trip. Script: demo/trust-walkthrough.sh.

This walkthrough is POSIX only; there is no PowerShell port yet.


Governance

File Purpose
LICENSE Apache License 2.0
CONTRIBUTING.md Contribution workflow and local checks
CODE_OF_CONDUCT.md Collaboration expectations
SECURITY.md Vulnerability reporting guidance
GOVERNANCE.md Project decision-making and branch policy

About

AI Catalog CLI

Resources

Code of conduct

Contributing

Security policy

Stars

12 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages