afps-spec

AFPS Primer

This document is non-normative. It provides an accessible overview of AFPS concepts. The normative specification is spec.md.

What is AFPS?

Agent Flow Packaging Standard (AFPS) is an open specification for declaring portable AI workflow packages. Think of it as a packaging standard: it defines how to describe, version, and distribute the building blocks of AI workflows.

AFPS answers a specific question: what is this AI workflow package, and what does it need? It does not define how agents call tools, how agents talk to each other, or how a runtime executes prompts. Those concerns belong to other specifications.

Where AFPS fits in the ecosystem

The key distinction is between goals and capabilities:

Agent Skills (Anthropic / AAIF) and MCP Tools define capabilities. AFPS defines the goal layer that composes those capabilities into a complete, portable workflow:

                ┌───────────────────────────────┐
  Goal          │  AFPS Flow                     │  The user's intent, packaged.
                │  prompt.md + manifest.json    │  "What should the agent accomplish?"
                ├───────────────────────────────┤
  Capability    │  AFPS Skills / Tools           │  Reusable abilities the agent
                │  MCP Tools                    │  can draw on to reach the goal.
                ├───────────────────────────────┤
  Connection    │  AFPS Providers                │  Authenticated access to
                │  (OAuth2, API key, ...)       │  external services.
                ├───────────────────────────────┤
  Transport     │  MCP (tool invocation)        │  Runtime protocols — out of
                │  A2A (agent-to-agent)         │  AFPS's scope.
                └───────────────────────────────┘

A flow’s prompt.md replaces what a human would type to give an agent its objective. The flow manifest declares which skills, tools, and providers the agent needs to fulfill that objective. AFPS packages everything together into a versioned, distributable .afps artifact (a standard ZIP file).

MCP standardizes how an agent invokes tools at runtime. A2A standardizes how agents discover and communicate with each other. Agent Skills standardize reusable capability descriptions. AFPS standardizes the goal and its dependencies — the package that gets published, installed, and composed before any of that happens. The four are complementary.

AFPS is transport-agnostic: it does not prescribe how packages are fetched, transferred, or cached.

The four package types

AFPS defines exactly four package types. Each one serves a distinct role.

Flow

A flow is a complete AI workflow — the primary unit of execution. It represents the user’s intent: a manifest describing what the workflow needs, paired with a prompt.md file containing the objective sent to a language model.

Think of it like a docker-compose.yml for AI agents — it declares the goal, the dependencies, the inputs, the outputs, the configuration, and execution hints, all in one portable artifact. Where a skill says “I know how to rewrite text professionally”, a flow says “process these emails and create a summary” — and lists the skills, tools, and providers needed to do it.

Minimal example (manifest.json):

{
  "name": "@acme/customer-intake",
  "version": "1.0.0",
  "type": "flow",
  "schemaVersion": "1.0",
  "displayName": "Customer Intake",
  "author": "Acme Corp",
  "requires": {
    "providers": { "@acme/gmail": "1.0.0" }
  }
}

The companion prompt.md contains the actual instructions:

# Customer Intake

You are a support assistant. Read the latest emails and produce a summary.

See spec.md, Section 3.2 for the full field reference.

Skill

A skill is a declarative capability — a reusable instruction set that a flow can reference. AFPS skill packages are a superset of the Agent Skills format: a valid Agent Skill directory becomes a valid AFPS skill package when you add a manifest.json. The SKILL.md format, all frontmatter fields, and optional directories (scripts/, references/, assets/) are preserved unchanged. AFPS adds identity, versioning, and dependency resolution on top.

rewrite-tone/
├── manifest.json       # AFPS addition: identity + versioning
├── SKILL.md            # Agent Skills format (unchanged)
├── scripts/            # Optional: executable code
├── references/         # Optional: additional documentation
└── assets/             # Optional: templates, resources

manifest.json — AFPS identity layer:

{
  "name": "@acme/rewrite-tone",
  "version": "1.0.0",
  "type": "skill"
}

SKILL.md — Agent Skills format, unchanged:

---
name: rewrite-tone
description: Rewrite a draft into a concise and professional tone.
---

# Rewrite Tone

## When to Use

- Improve the tone of a customer-facing draft
- Shorten verbose text without changing meaning

The SKILL.md frontmatter supports the fields defined by Agent Skills: name, description, license, compatibility, metadata, and allowed-tools. AFPS does not modify or extend this vocabulary.

See spec.md, Section 3.3 for details.

Tool

A tool is a callable capability — executable code that an agent can invoke during flow execution. It consists of a manifest declaring the tool interface and an implementation source file. Where a skill provides instructions (declarative), a tool provides code (executable).

@acme/fetch-json.afps
├── manifest.json     # Tool interface + metadata
└── tool.ts           # Implementation source file

manifest.json:

{
  "name": "@acme/fetch-json",
  "version": "1.0.0",
  "type": "tool",
  "displayName": "Fetch JSON",
  "entrypoint": "tool.ts",
  "tool": {
    "name": "fetch_json",
    "description": "Fetch JSON from a URL and return the parsed response.",
    "inputSchema": {
      "type": "object",
      "properties": {
        "url": { "type": "string", "description": "HTTP or HTTPS URL" }
      },
      "required": ["url"]
    }
  }
}

The tool object describes the interface — what the tool is called, what it does, and what parameters it accepts. This metadata is available to consumers without executing the source code.

The entrypoint field points to the implementation source file. AFPS does not prescribe the programming language, module format, or execution strategy — those are implementation concerns.

Because tools contain executable code, they are the highest-risk package type. See spec.md, Section 3.4 and Section 8.2 for security considerations.

Provider

A provider is a service connector — it describes how to authenticate with an external service. It is manifest-only; there is no companion file. Providers declare an authentication mode (oauth2, oauth1, api_key, basic, or custom) and the metadata needed to establish a connection.

Example — an API key provider (manifest.json):

{
  "name": "@acme/openai",
  "version": "1.0.0",
  "type": "provider",
  "displayName": "OpenAI",
  "definition": {
    "authMode": "api_key",
    "credentialSchema": {
      "type": "object",
      "properties": {
        "apiKey": { "type": "string", "description": "API key" }
      },
      "required": ["apiKey"]
    },
    "credentialHeaderName": "Authorization",
    "credentialHeaderPrefix": "Bearer",
    "authorizedUris": ["https://api.openai.com/*"]
  }
}

See spec.md, Section 3.5 and Section 7 for all auth modes.

Key concepts

Scoped names

Every AFPS package has a scoped name of the form @scope/name. Both segments are lowercase, alphanumeric, and may contain hyphens — but must start and end with a letter or digit. No underscores, no uppercase.

@acme/customer-intake    valid
@my-org/gmail            valid
@Acme/Flow               invalid (uppercase)
@acme/my_flow            invalid (underscore)
acme/flow                invalid (missing @)

Scopes let registries enforce ownership: only authorized publishers can release packages within a scope. See spec.md, Section 2.2.

Semantic versioning

AFPS uses semantic versioning for package identity. Every package declares an exact version (e.g. 1.2.0), and dependencies can use semver ranges (e.g. ^1.0.0, ~2.1).

See spec.md, Section 2.3.

ZIP archive format

AFPS packages are distributed as ZIP files. Every archive must contain manifest.json at the root. Depending on the package type, additional files are required:

Type Required companion files
flow prompt.md (non-empty)
skill SKILL.md
tool Source file referenced by entrypoint
provider None beyond manifest.json

Package archives should use the .afps file extension (e.g., customer-intake-1.0.0.afps). The file is a standard ZIP — any ZIP tool can open it — but the .afps extension makes packages immediately recognizable and enables OS-level file association with AFPS-aware tooling.

Consumers must sanitize ZIP entries to prevent path traversal attacks. See spec.md, Section 2.5.

Dual dependency model

A flow composes skills, tools, and providers as dependencies. The following diagram shows a typical flow and the packages it depends on:

                  ┌──────────────────────────────────┐
                  │  @acme/customer-intake            │
                  │  type: flow                       │
                  │                                   │
                  │  prompt.md    = the objective      │
                  │  input/output = structured data    │
                  │  config       = user settings      │
                  └──────┬───────────────────────────┘
                         │ requires (runtime)
                         │ registryDependencies (install-time)
          ┌──────────────┼──────────────┐
          ▼              ▼              ▼
  ┌──────────────┐ ┌────────────┐ ┌────────────┐
  │ @acme/gmail  │ │ @acme/     │ │ @acme/     │
  │ provider     │ │ rewrite-   │ │ fetch-json │
  │              │ │ tone       │ │            │
  │ OAuth2 creds │ │ skill      │ │ tool       │
  │ scopes       │ │ SKILL.md   │ │ source     │
  └──────────────┘ └────────────┘ └────────────┘
   connection       capability      capability
   "access Gmail"   "rewrite text   "fetch JSON
                     professionally"  from a URL"

The flow says what to accomplish. The dependencies provide how — reusable capabilities and service connections the agent draws on at runtime.

AFPS distinguishes two kinds of dependency declarations, because they serve different purposes at different times:

requires — runtime composition (flows only). This tells a flow runner which packages must be loaded when the flow executes. Values are typically exact versions or *.

registryDependencies — install-time resolution (all package types). This tells a registry which packages to resolve and auto-install when a package is published or imported. Values are semver ranges.

A typical flow lists the same packages in both fields:

{
  "requires": {
    "providers": { "@acme/gmail": "1.0.0" }
  },
  "registryDependencies": {
    "providers": { "@acme/gmail": "^1.0.0" }
  }
}

The requires field says “this flow needs Gmail at runtime.” The registryDependencies field says “when installing this flow, resolve Gmail from the registry using this version range.”

They are not redundant. A skill or tool has no requires but can still declare registryDependencies. A flow might require a package that is already pre-installed in the runtime environment.

See spec.md, Section 4.1.

Constrained schema system

AFPS defines a simplified schema system for three distinct sections in a flow manifest. Although they share the same format, they serve different purposes:

The schema format is intentionally smaller than JSON Schema. Every schema must be an object with type: "object" and a properties map:

{
  "input": {
    "schema": {
      "type": "object",
      "properties": {
        "query": {
          "type": "string",
          "description": "Search query",
          "placeholder": "label:inbox newer_than:7d"
        },
        "max_results": {
          "type": "number",
          "default": 20
        }
      },
      "required": ["query"]
    }
  },
  "config": {
    "schema": {
      "type": "object",
      "properties": {
        "language": {
          "type": "string",
          "description": "Output language",
          "default": "fr",
          "enum": ["fr", "en", "es"]
        }
      }
    }
  }
}

Supported property types are string, number, boolean, array, object, and file. The file type supports additional hints like accept, maxSize, multiple, and maxFiles.

There is no nesting, no $ref, no oneOf/anyOf — the schema is flat by design, optimized for form generation and validation rather than complex data modeling.

See spec.md, Section 5.

Provider authentication modes

Provider packages declare one of five authentication modes:

Mode Use case Requires
oauth2 Standard OAuth 2.0 services authorizationUrl, tokenUrl
oauth1 Legacy OAuth 1.0a services requestTokenUrl, accessTokenUrl
api_key API key-based services credentialSchema
basic HTTP Basic authentication credentialSchema
custom Non-standard authentication schemes credentialSchema

OAuth2 providers can additionally declare PKCE support, custom scopes, token endpoint configuration, and authorized URI patterns.

See spec.md, Section 7.

Extension conventions

AFPS manifests are extensible. Unknown fields are preserved by consumers rather than rejected. When adding custom fields to a manifest or nested object, producers should use the x- prefix to avoid collisions with future specification fields:

{
  "name": "@acme/my-flow",
  "type": "flow",
  "x-internal-team": "platform",
  "x-cost-center": "eng-42"
}

This follows the same convention used by OpenAPI and other extensible specifications.

What AFPS is NOT

To set clear expectations, here is what AFPS intentionally does not cover:

AFPS is a packaging standard. It defines the artifact — the ZIP file, the manifest, the companion files, the dependency declarations — and leaves execution, transport, and discovery to other layers.

Further reading