# The package manifest

Source: https://opvs.ai/docs/guides/vendors/package-manifest

> Every field of package.yaml, the package layout, skill ids, peer dependencies, and what goes into the signed bundle.

Your package ships as one signed, gzipped tarball with a `package.yaml` manifest at its root. The registry validates the manifest strictly: **unknown top-level keys are refused** with `extra fields not permitted`, so a typo fails the publish with a `422`.

## Identity (required)

Field

Format

Rule

`name`

`@vendor/slug`

lowercase. The scope must equal `@` + `vendor`.

`version`

SemVer

`0.1.0`, not `0.1` or `v1`.

`description`

text

1–1024 characters.

`vendor`

slug

`[a-z0-9][a-z0-9_-]*`, no leading `@`.

`category`

text

1–64 characters, free text (`board`, `data-collection`, …).

`license`

text

`UNLICENSED`, `MIT`, …

`trust_domain`

slug

required; usually the same as `vendor`.

```yaml
name: "@acme/leads"
version: "1.2.0"
description: Find and enrich B2B leads from company websites.
vendor: acme
category: data-collection
license: UNLICENSED
trust_domain: acme
```

## Signing block (placeholders)

Write these placeholders exactly; `opvs-skills publish` replaces them with the real values. See [Sign and publish](https://opvs.ai/docs/guides/vendors/publish.md).

```yaml
signature: "ed25519:unsigned"
signed_at: "1970-01-01T00:00:00Z"
cert_fingerprint: "SHA256:unsigned"
```

## `provider_config` (required)

How the runtime reaches your API. Required even for a guidance-only skill (use a placeholder and a `schema.yaml` with no `methods:`). Give **either** `base_url_env` **or** `upstream`.

Field

Rule

`base_url_env`

name of the environment variable that holds the base URL, `^[A-Z][A-Z0-9_]*$`

`upstream`

your own API's address (`base_url`, optional `host`). The host must be on your vendor's egress allowlist, which OPVS approves; ask vendors@opvs.ai.

`auth.type`

`bearer`, `basic`, `header` or `none`

`auth.token_env`

required for `bearer`, `basic` and `header`: the variable holding the secret

`auth.header`

required for `header`: the header name

`default_format`

`yaml` or `json`

`timeout_ms`

default `30000`, 1–600000

`rate_limit`

a package-wide default rate limit (see [Security review](https://opvs.ai/docs/guides/vendors/security-review.md))

```yaml
provider_config:
  base_url_env: OPVS_API_URL
  auth:
    type: bearer
    token_env: OPVS_PAT
  default_format: yaml
```

A `header` skill needs both names, or the runtime sends an empty key:

```yaml
auth:
  type: header
  header: x-api-key
  token_env: ACME_API_KEY
```

## `credentials` (optional)

Secrets the workspace must provide before the package runs, in two lists, `required` and `optional`. Each entry has `name` (environment variable), `auth_type`, `provider` (lowercase slug), and optionally `help_url` and `description`. Vendors may use the `auth_type` values `pat`, `api_key`, `oauth`, `oauth_pkce` and `hmac_sha256`; the others are reserved for OPVS.

## `entitlements` (optional)

What the package may touch, in `required` and `optional` lists. Every name must be known: a fixed name (`agentboard.task.write`, `brand.read`, …) or a parameterised one (`network.egress.provider.<name>`, `credits.consume.<name>`, or your own `vendor.<vendor>.<surface>.<verb>`). A name cannot be in both lists.

```yaml
entitlements:
  required:
    - vendor.acme.leads.search
    - network.egress.provider.acme
  optional:
    - vendor.acme.leads.export
```

Declare entitlements over your own API with `vendor.<vendor>.<surface>.<verb>`: exactly three parts after `vendor.`, and `<vendor>` must be your own slug.

## `skills`

The skills the package ships.

```yaml
skills:
  - id: leads
    schema: ./skills/leads/schema.yaml
    visibility: public
    entitlements:
      - vendor.acme.leads.search
```

- `id` is unique in the package, `^[a-z0-9][a-z0-9_-]*$`. Agents call the skill by this id, so choose it on purpose; it does not have to match the package name.
- A skill's `entitlements` must be a subset of the package's.

## Other fields

Field

Default

What it does

`type`

`skill`

`skill` or `profession`. See [Profession anatomy](https://opvs.ai/docs/guides/vendors/profession-anatomy.md).

`profession`

none

required when `type: profession`

`aliases`

`[]`

up to 20 phrases agents might search for. Without them, a review warning.

`tags`

`[]`

up to 20 tags

`tier`

`beta`

`beta` is visible and installable at once; `internal` is a hidden test tier. See [Versions and trust tiers](https://opvs.ai/docs/guides/vendors/versions-and-tiers.md).

`revocable_by`

`[]`

who else may revoke

`docs`

`{}`

relative paths: `readme`, `skill_guide`, `changelog`, `learnings`

`peer_dependencies`

`[]`

see below

`inbound_events`

`[]`

webhook event declarations

`media`, `marketing`

`{}`

detail-page copy: hero image, features, author card

`support`

`{}`

where users report problems

`pricing`

`model: none`

accepted (`none`, `per_call`, `subscription`) but not billed today. See [Promote your package](https://opvs.ai/docs/guides/vendors/promote.md#payouts).

## Package layout

```
my-package/
├── package.yaml
├── README.md
├── CHANGELOG.md
├── SKILL.md            # single-skill packages
├── client/
│   └── schema.yaml
└── skills/             # multi-skill packages
    └── <skill-id>/
        ├── SKILL.md
        ├── schema.yaml
        ├── references/
        ├── learnings/
        └── registry/
```

**Flat** (one skill, schema at `./client/schema.yaml`) and **nested** (`./skills/<id>/schema.yaml`) are both valid. What goes into each layer is on [The 4-layer skill format](https://opvs.ai/docs/guides/vendors/four-layer-format.md).

## Peer dependencies

Use `peer_dependencies` when your package needs another one installed.

```yaml
peer_dependencies:
  - name: "@opvs-ai/opvs-foundation"
    range: "^1.0.0"
```

Ranges follow semver: `^1.0.0`, `~1.2.0`, `1.2.3`, `>=1.2.0 <2.0.0`. A package with **no** skills and **no** inbound events but some peers is a valid **meta-package**: installing it installs its peers. A package with none of the three is refused.

## What goes in the bundle

`opvs-skills publish` packs the **whole package folder** and removes a fixed list. You cannot add a `files:` field (unknown keys are refused).

Included

Always excluded

`package.yaml`, `README.md`, `CHANGELOG.md`

`node_modules/`, `.git/`

`SKILL.md`, `client/`, `skills/`

`.env`, `.env.local`

`references/`, `learnings/`, `registry/`, `scripts/`

`dist/`, `build/`, `.turbo/`, `.next/`

any other file in the folder

`.DS_Store`

**Anything not excluded is shipped and signed.** Keep CI secrets, private keys and `*.local` files out of the package folder.

## Next

[Sign and publish](https://opvs.ai/docs/guides/vendors/publish.md).
