Building & Publishing8 min read

ANP Manifest Reference: How to Write a Package Manifest

Complete reference for the ANP manifest.yaml format. Every field explained with examples, including multi-tool packages, permissions, and runtime configuration.

By agentnode

Overview

Every ANP package requires a manifest.yaml file in the root of the package directory. This file tells AgentNode what your package is, what tools it provides, what inputs and outputs each tool expects, and what runtime requirements must be met for installation. If the manifest is wrong, the package either will not publish or will fail verification.

This reference covers every field in the current manifest specification (version 0.2), with examples for each.

Top-Level Fields

manifest_version (required)

The version of the ANP manifest specification your package conforms to. Currently, the only supported value is "0.2".

manifest_version: "0.2"

This field exists so the specification can evolve without breaking existing packages. Always use the latest supported version when creating new packages.

package_id (required)

A globally unique identifier for your package. Must be a lowercase slug: letters, numbers, and hyphens. No underscores, no uppercase, no spaces.

package_id: web-article-extractor

Choose carefully — this cannot be changed after publishing. It becomes part of the install URL and the registry listing. Good package IDs are short, descriptive, and unlikely to conflict with other packages.

Valid: json-validator, pdf-to-text, sentiment-analyzer, s3-uploader

Invalid: JSON_Validator, my tool, pdf.to.text, a (too short)

version (required)

The semantic version of this release. Must follow semver format.

version: "0.1.0"

When publishing an update, the version must be strictly higher than the currently published version. AgentNode sorts versions semantically, so "0.2.0" comes after "0.1.9", not after "0.1.10" (which is how string sorting would order them).

Conventions:

  • 0.x.x — Pre-stable; breaking changes may happen between minor versions.
  • 1.0.0 — First stable release; you are committing to backward compatibility.
  • Bump the patch version for bug fixes, minor for new features, major for breaking changes.

Capabilities

The capabilities section declares what your package can do. Currently, it contains a single key: tools.

capabilities.tools (required)

A list of tools provided by this package. Each tool is an object with the following fields:

Tool: name (required)

The name of the tool. This is what agents use to refer to the tool after installation. Use snake_case.

- name: extract_article

Tool: entrypoint (required)

The Python import path to the function, in module:function format. The module path uses dots to separate directories and the colon separates the module from the function name.

  entrypoint: web_article_extractor.tool:extract_article

This means: "import extract_article from web_article_extractor/tool.py." The module must be importable from the package root. The function must be a callable that accepts keyword arguments matching the input_schema and returns a value matching the output_schema.

More examples:

  • my_pack.core:run — Function run in my_pack/core.py
  • tools.text.summarize:summarize_text — Function summarize_text in tools/text/summarize.py
  • main:process — Function process in main.py (top-level module)

Tool: input_schema (required)

A JSON Schema object describing the inputs the tool accepts. This schema is used for validation during smoke testing and by agents to construct correct calls.

  input_schema:
    type: object
    properties:
      url:
        type: string
        description: "The URL of the webpage to extract"
      max_length:
        type: integer
        description: "Maximum characters to return"
        default: 5000
    required: [url]

Key points:

  • The top level must be type: object with properties.
  • Use required to list mandatory fields. Optional fields should have default values.
  • Include description for every property — agents use these to understand what to pass.
  • Supported types: string, integer, number, boolean, object, array, null.
  • You can use enum to restrict values: type: string, enum: ["csv", "json", "xml"].

Tool: output_schema (required)

A JSON Schema object describing what the tool returns. The verification pipeline checks that the actual output conforms to this schema, which contributes to the contract compliance score (10 points).

  output_schema:
    type: object
    properties:
      title:
        type: string
      text:
        type: string
      word_count:
        type: integer
      extracted_at:
        type: string
        description: "ISO 8601 timestamp of extraction"

Be precise. If your tool sometimes returns null for a field, declare it as a union: type: [string, "null"]. If a field is always present, include it. If it is only sometimes present, do not list it in a required array on the output schema.

Multi-Tool Packages

A single package can provide multiple tools. List them all under capabilities.tools:

capabilities:
  tools:
    - name: validate_json
      entrypoint: json_toolkit.validate:validate_json
      input_schema:
        type: object
        properties:
          data:
            type: object
          schema:
            type: object
        required: [data, schema]
      output_schema:
        type: object
        properties:
          valid:
            type: boolean
          errors:
            type: array
            items:
              type: string

    - name: format_json
      entrypoint: json_toolkit.format:format_json
      input_schema:
        type: object
        properties:
          data:
            type: object
          indent:
            type: integer
            default: 2
        required: [data]
      output_schema:
        type: object
        properties:
          formatted:
            type: string
          size_bytes:
            type: integer

Each tool is verified independently. If one tool passes smoke testing and another fails, you earn partial credit. Keep tools in the same package only if they are logically related and share dependencies.

Runtime

The runtime section specifies execution requirements.

runtime.language (required)

The programming language. Currently, only python is supported.

runtime:
  language: python

runtime.min_version (required)

The minimum language version required. The verification sandbox runs Python 3.10+, so do not set this below "3.10".

  min_version: "3.10"

runtime.dependencies (required, may be empty)

A list of pip-installable packages with optional version constraints. These are installed in the verification sandbox and on the user's machine during resolve_and_install.

  dependencies:
    - requests>=2.31
    - beautifulsoup4>=4.12
    - lxml>=5.0

If your tool uses only the Python standard library, provide an empty list:

  dependencies: []

Version constraint formats follow pip conventions:

  • requests>=2.31 — Minimum version
  • requests>=2.31,<3.0 — Version range
  • requests==2.31.0 — Exact version (not recommended — too rigid)
  • requests — Any version (not recommended — may break with future releases)

Frameworks

The optional frameworks field indicates which agent frameworks your package is designed to integrate with. This is metadata for discoverability — it does not affect how the package works.

frameworks:
  - langchain
  - crewai
  - autogen

If your package is framework-agnostic (most are), you can omit this field entirely.

Permissions

The optional permissions field declares what external resources your tool needs access to. This helps agents and users understand the security profile of the package before installing it.

permissions:
  network:
    - "https://api.example.com/*"
  environment:
    - EXAMPLE_API_KEY
  filesystem:
    - read: "/tmp/cache"

permissions.network

A list of URL patterns the tool makes HTTP requests to. Use wildcards for path segments.

permissions.environment

A list of environment variable names the tool reads. This signals to users that they need to set these variables before using the tool.

permissions.filesystem

Filesystem paths the tool reads from or writes to. Specify whether it is read or write access.

Permissions are currently informational — they are not enforced at runtime. But declaring them honestly helps users trust your package and may affect scoring in future specification versions.

Complete Example

Here is a full manifest for a multi-tool package with all optional fields:

manifest_version: "0.2"
package_id: weather-toolkit
version: "1.2.0"

capabilities:
  tools:
    - name: get_current_weather
      entrypoint: weather_toolkit.current:get_current_weather
      input_schema:
        type: object
        properties:
          city:
            type: string
            description: "City name (e.g., 'London', 'New York')"
          units:
            type: string
            enum: ["celsius", "fahrenheit"]
            default: "celsius"
        required: [city]
      output_schema:
        type: object
        properties:
          city:
            type: string
          temperature:
            type: number
          units:
            type: string
          condition:
            type: string
          humidity:
            type: integer

    - name: get_forecast
      entrypoint: weather_toolkit.forecast:get_forecast
      input_schema:
        type: object
        properties:
          city:
            type: string
            description: "City name"
          days:
            type: integer
            description: "Number of days to forecast (1-7)"
            default: 3
        required: [city]
      output_schema:
        type: object
        properties:
          city:
            type: string
          forecast:
            type: array
            items:
              type: object
              properties:
                date:
                  type: string
                high:
                  type: number
                low:
                  type: number
                condition:
                  type: string

runtime:
  language: python
  min_version: "3.10"
  dependencies:
    - httpx>=0.27
    - python-dateutil>=2.9

frameworks:
  - langchain
  - crewai

permissions:
  network:
    - "https://api.openweathermap.org/*"
  environment:
    - OPENWEATHER_API_KEY

Common Mistakes

  • Mismatched entrypoint and file path. If the entrypoint says my_tool.core:run, the file my_tool/core.py must exist and contain a function called run. This is the most common cause of import failures.
  • Missing dependencies. If your code does import requests but requests is not in runtime.dependencies, the install step passes but the import step fails.
  • Schema mismatch. If the output_schema says a field is an integer but your function returns a float, you lose contract compliance points.
  • Using hyphens in module names. The package_id can be my-tool, but the Python module directory must be my_tool. Python cannot import modules with hyphens.
  • Forgetting __init__.py. Without this file in your module directory, Python will not recognize it as an importable package.
  • Setting min_version too low. If you use features like match statements (3.10+) or type aliases with | syntax (3.10+), set the minimum version accordingly.

Validation

Before publishing, you can validate your manifest locally by checking it against these rules:

  1. manifest_version is "0.2".
  2. package_id matches the pattern ^[a-z0-9]+(-[a-z0-9]+)*$.
  3. version is valid semver.
  4. Every tool has name, entrypoint, input_schema, and output_schema.
  5. Every entrypoint has exactly one colon separating the module path from the function name.
  6. The referenced files exist on disk.

The CLI also validates the manifest before uploading, so you will catch errors before they reach the verification pipeline.

For further details on publishing, see the Publishing Guide. For testing strategies that maximize your verification score, see Writing Tests for Your Agent Skill.

LLM Runtime: Let the Model Handle It

If your agent uses OpenAI or Anthropic tool calling, AgentNodeRuntime handles tool registration, system prompt injection, and the tool loop automatically. The LLM discovers, installs, and runs AgentNode capabilities on its own — no hardcoded tool calls needed.

from openai import OpenAI
from agentnode_sdk import AgentNodeRuntime

runtime = AgentNodeRuntime()

result = runtime.run(
    provider="openai",
    client=OpenAI(),
    model="gpt-4o",
    messages=[{"role": "user", "content": "your task here"}],
)
print(result.content)

The Runtime registers 5 meta-tools (agentnode_capabilities, agentnode_search, agentnode_install, agentnode_run, agentnode_acquire) that let the LLM search the registry, install packages, and execute tools autonomously. Works with Anthropic too — just change provider="anthropic" and pass an Anthropic client.

See the LLM Runtime documentation for the full API reference, trust levels, and manual tool calling.

#manifest#reference#anp#specification#documentation