Manifest Schemas

Reference for every manifest/payload file format used by installable catalog artifacts: MANIFEST.toml (package metadata, every package type), the per-type payload file (SKILL.md, COMPETENCY.md, AGENT.md, workflow.json, mcp.json/adapter.json), and COLLECTION.toml.

Two layers

Every package is MANIFEST.toml (identity/dependencies/standards) plus a payload/ directory containing exactly one payload file, whose name is fixed by [package] type:

typePayload fileContains
skillpayload/SKILL.mdYAML frontmatter + markdown body (tool config / prompt context)
competencypayload/COMPETENCY.mdYAML frontmatter + markdown body (system prompt)
agent-templatepayload/AGENT.mdYAML frontmatter + markdown body (system prompt)
workflow-templatepayload/workflow.jsonNative JSON — a DAG of steps, not a document
integrationpayload/mcp.json (or payload/adapter.json for a REST/SOAP contract, ADR-057)Native JSON
contractpayload/CONTRACT.jsonNative JSON — a schema-bearing tool-surface role (ADR-066)

There is no tool package type — packages of type skill cover both single-tool and multi-tool bundles. The full type enum is exactly: skill, competency, agent-template, workflow-template, integration, contract.

Package identity (name) lives only in MANIFEST.toml [package]. None of the payload frontmatter formats carry id/name fields — MANIFEST.toml [package] name is the sole identity other packages reference via skills/integrations/competencies/dependency keys. Author attribution for a package also does not live in MANIFEST.toml — there is no [package.author] section on the real schema. Package attribution is the authenticated publisher_id/publisher_role the registry records at publish time, not self-declared text (issue #619). COLLECTION.toml is the one place a free-text [author] is still valid — collections are an admin-curated resource, a lower-stakes context.

MANIFEST.toml (Package Metadata)

[package]
type = "competency"                    # skill | competency | agent-template | workflow-template | integration
name = "claims-intake"                 # kebab-case, 3-64 chars — the package's sole identity
title = "Claims Intake"                # required, human-readable display name (non-blank)
version = "1.2.0"                      # semver 2.0 (MAJOR.MINOR.PATCH, optional pre-release)
description = "FNOL processing"        # required, ≤500 chars
license = "Apache-2.0"                 # SPDX identifier (non-empty, no newlines/tabs)
min_platform_version = "0.5.0"         # required, valid semver

[package.metadata]
repository = "https://github.com/..."  # optional, must be http(s)
homepage = "https://..."               # optional, must be http(s)
keywords = ["insurance", "claims"]     # max 20 entries, each ≤50 chars
categories = ["insurance/claims"]      # taxonomy paths (no format validation beyond being strings)
regions = ["ZA", "US"]                 # ISO 3166-1 alpha-2 codes (empty = all regions); case-insensitive on input, normalized upper-case

[dependencies]
document-ocr = "^1.0"                  # semver constraint. The catalog resolver ONLY ever
postgresql-connector = ">=2.0.0, <3.0.0"  # walks [dependencies] -- there is no optional/peer
                                        # dependency concept; every payload ref this manifest
                                        # can carry (skills/integrations/competencies/
                                        # agents_required) is mandatory at equip time

[standards]
mcp_compatible = true                  # only valid for skill/integration package types
openapi_spec = "payload/openapi.yaml"  # only valid for skill/integration package types

[signing]
content_hash = "sha256:a1b2c3d4..."    # populated by `hoziron-cli package build` — SHA-256
                                        # Merkle root over payload/. Provenance (publisher
                                        # identity, registry signature) is added by the
                                        # registry at publish time, stored in the package
                                        # index -- not in the archive itself, and not a
                                        # MANIFEST.toml field

[implements.claims-write]              # only for integration packages (ADR-066).
version = "1.0.0"                      # Declares this integration satisfies the
                                        # "claims-write" contract package at the
                                        # given version.

  [implements.claims-write.tool_map]    # contract tool name -> this integration's
  create_claim = "create_fnol"          # native tool name. Omit an entry when the
                                        # native name already matches the contract's.

  [implements.claims-write.field_map.create_fnol]  # per-tool: contract field name ->
  policy_ref = "policy_number"                       # native field name. Omit a tool's
                                                      # entry, or a field within it, when
                                                      # the native name already matches.

Package types

TypePayloadUse case
skillSKILL.mdTool bundle + runtime config (covers single- and multi-tool packages)
competencyCOMPETENCY.mdAgent behavior definition — system prompt + equipped skills
agent-templateAGENT.mdPre-configured agent (competencies + tool visibility)
workflow-templateworkflow.jsonMulti-agent pipeline (DAG of steps)
integrationmcp.json or adapter.jsonMCP server, or REST/SOAP adapter contract
contractCONTRACT.jsonSchema-bearing tool-surface role (ADR-066) that an integration package's [implements.<name>] satisfies

[package] validation rules

FieldRule
name[a-z0-9][a-z0-9-]*[a-z0-9], 3–64 chars. No leading/trailing/consecutive hyphens
version, min_platform_versionValid semver: MAJOR.MINOR.PATCH, optional -prerelease suffix; each numeric component must parse as an integer
licenseNon-empty; no newlines or tabs (informal SPDX check, not a full identifier list)
descriptionNon-empty, ≤500 characters
dependenciesKey 3–64 chars; value non-empty and must contain a version number; recognized operator prefixes: >= <= > < = ^ ~ *
standards.openapi_specOnly valid for skill/integration types
standards.mcp_compatibleOnly valid for skill/integration types
metadata.keywordsEach ≤50 chars, non-empty; at most 20 entries
metadata.repository/metadata.homepageMust start with http:// or https:// if present
metadata.regionsEach entry must be a currently-assigned ISO 3166-1 alpha-2 code

Semver constraint syntax

SyntaxMeaningExample
*Any versionMatches everything
^1.2.3Compatible updates>=1.2.3, <2.0.0
~1.2.3Patch-level only>=1.2.3, <1.3.0
=1.2.3Exact matchOnly 1.2.3
>=1.0.0, <2.0.0RangeCompound constraint

hoziron-cli package build also auto-derives [dependencies] entries (with constraint >=0.0.0) for any payload reference (a competency's skills, an agent template's competencies, a workflow template's agents_required) not already declared by hand — additive only, never overwrites an existing hand-set constraint (issue #618).

COMPETENCY.md (payload for type = "competency")

YAML frontmatter delimited by ---, followed by the markdown body — the body is the system prompt (serde_yaml parses the frontmatter with deny_unknown_fields, so a typo'd or legacy field fails the build loudly rather than being silently dropped).

---
description: "Handles first-notice-of-loss intake and triage"
skills: [document-ocr, policy-lookup]
tools: []
contracts: []
integrations: [guidewire-claimcenter]
settings:
  - key: strictness
    label: "Review Strictness"
    description: "How strict the intake validation should be"
    type: Select
    default: medium
    values: [low, medium, high]
schedule: "0 */6 * * *"
schedule_action: "run-triage-sweep"
inputs:
  - name: loss_description
    type: string
    required: true
outputs:
  - name: claim_number
    type: string
---

You are a claims-intake specialist. Extract the loss description, classify
severity, and route to the correct claim workflow...

Frontmatter fields

FieldTypeRequiredDescription
descriptionstringYesNon-empty
skillsstring[]Yes (at least 1)Kebab-case package names
toolsstring[]No
contractsstring[]NoIntegration contract names this competency invokes
integrationsstring[]No
settingsarray of {key, label, description, type, default, values}Notype must be Select/Text/Toggle/Number; Select requires non-empty values
inputs / outputsarray of {name, type, required?, values?, range?}Notype is a free string (string/integer/date/boolean/enum by convention); required only meaningful on inputs; range: [min, max] for integer; values for enum
schedulestring (cron expression)NoRequires schedule_action when set
schedule_actionstringConditionalRequired when schedule is set

There is no id, name, or category field in COMPETENCY.md frontmatter — a manifest carrying any of them fails to parse (deny_unknown_fields). Identity comes from MANIFEST.toml [package] name/title; catalog classification comes from MANIFEST.toml [package.metadata] categories (free-form taxonomy paths, not a fixed enum). If you're migrating an older competency that had category: Insurance in its frontmatter, delete that line and add the equivalent path to MANIFEST.toml [package.metadata] categories instead.

Markdown body must be non-empty — it becomes the agent's system prompt.

SKILL.md (payload for type = "skill")

---
version: "1.0.0"
description: "OCR extraction for scanned claim documents"
license: "Apache-2.0"
tools: []
runtime: promptonly
entry: ""
config: {}
---

# Document OCR

Extract structured fields from scanned claim documents...
FieldTypeRequiredDescription
descriptionstringYesNon-empty
versionstringNoValid semver if present
licensestringNo
toolsstring[]No
runtimestringNo (default promptonly)Recognized: python, wasm, node, shell, builtin, promptonly, starlark. Only promptonly and starlark are actually permitted to compile (ADR-041) — the others parse but are rejected at build time
entrystringConditionalRequired for any runtime other than promptonly/builtin
configtableNoFree-form skill runtime config

promptonly skills require a non-empty markdown body (it becomes prompt_context).

AGENT.md (payload for type = "agent-template")

---
description: "Front-line FNOL intake agent"
competencies: [claims-intake]
allow_skill_tools: []
allow_integration_tools: []
---

You are the front-line intake agent for new claims...
FieldTypeDescription
descriptionstringRequired
competenciesstring[]
allow_skill_toolsstring[]Per-class visibility: in-process skill tools (ADR-052)
allow_integration_toolsstring[]Per-class visibility: MCP/integration tools (ADR-052)

There is deliberately no model-selection fielddeny_unknown_fields means a manifest with a model: block fails to parse rather than being silently honored or dropped. Model selection is routing-gateway/policy authority (ADR-049/ADR-054), never a package-level lever.

There is also no triggers field — deny_unknown_fields means a manifest with a triggers: key fails to parse rather than being silently honored or dropped. Source acceptance is determined structurally instead — see invocation-model.md.

workflow.json (payload for type = "workflow-template")

Native JSON, not markdown+frontmatter — a workflow is a data definition (DAG of steps), not a document.

{
  "description": "FNOL intake through to triage assignment",
  "agents_required": ["intake-agent", "triage-agent"],
  "steps": [],
  "variables": {}
}
FieldTypeDescription
descriptionstringRequired
agents_requiredstring[]Agent template names this workflow references
stepsarrayStep definitions (workflow-engine-specific shape)
variablestableWorkflow-scoped variables

mcp.json / adapter.json (payload for type = "integration")

mcp.json matches the de facto MCP ecosystem config shape used by Claude Desktop, VS Code, Cursor, etc.:

{
  "command": "npx",
  "args": ["-y", "@company/claimcenter-mcp"],
  "env": { "CLAIMCENTER_TOKEN": "" },
  "url": null
}
FieldTypeDescription
commandstringSubprocess command (e.g. npx, uvx, node)
argsstring[]Arguments
envtableEnv vars for the server process
urlstringRemote server URL, for streamable-HTTP/SSE transports instead of a subprocess

If payload/adapter.json is present instead, the package uses a REST/SOAP adapter contract (ADR-057) — no live MCP handshake; each operation is dispatched over plain HTTP through the same mediated conn.call_tool() chokepoint as MCP tools. See the integration authoring guide for the adapter.json operation schema.

CONTRACT.json (payload for type = "contract")

Promotes a "contract" (ADR-051's named tool-surface role on a competency) from a name-only string to a standalone, versioned artifact carrying a real JSON Schema per tool (ADR-066, Issue #792). A contract package carries no executable behavior — the payload is pure schema data, authored once as the product-level definition of an interface, checked against by every integration that implements it (see [implements.<name>] above).

{
  "schema_version": "1",
  "tools": [
    {
      "name": "create_claim",
      "description": "File a new claim against a policy.",
      "input_schema": {
        "type": "object",
        "properties": {
          "policy_ref": { "type": "string" },
          "loss_date": { "type": "string", "format": "date" }
        },
        "required": ["policy_ref", "loss_date"]
      },
      "output_schema": { "type": "object", "properties": { "claim_id": { "type": "string" } } }
    }
  ]
}
FieldTypeDescription
schema_versionstringForward-compat version for this JSON shape itself (own field, not coupled to min_platform_version); defaults to "1"
toolsarrayThe tool surface this contract declares. Order is preserved for display but not semantically significant — lookups are by name
tools[].namestringCanonical tool name (e.g. create_claim). This is the vocabulary the agent/model always sees — an implementing integration's native name, if different, is reconciled via its tool_map
tools[].descriptionstring, optionalHuman-readable description
tools[].input_schemaJSON SchemaFull JSON Schema for the tool's input — the exact shape an MCP tools/list response carries in Tool.input_schema
tools[].output_schemaJSON Schema, optionalExpected return shape. Not enforced by the connect-time conformance check (only inputs are structurally diffable against a live MCP tools/list) — carried for documentation and future use

COLLECTION.toml

name = "insurance-starter"
display_name = "Insurance Starter Kit"
description = "Everything needed to start processing claims"
version = "1.0.0"
license = "MIT"
min_platform_version = "0.5.0"         # optional
featured = true
tags = ["insurance", "claims", "starter"]
icon = "shield-check"

[author]
name = "Hoziron Team"
email = "platform@hoziron.com"         # optional
url = "https://hoziron.com"            # optional

[metadata]
categories = ["insurance"]
regions = ["ZA"]

[[packages]]
name = "claims-intake"
version = "1.2.0"
package_type = "competency"
is_dependency = false

Unlike MANIFEST.toml, COLLECTION.toml does carry a free-text [author] (name required, email/url optional) — collections are an admin-curated resource type where self-declared attribution is acceptable.

Closure invariant

A collection must include ALL transitive dependencies. Installing a collection never requires fetching packages from outside it.


Related: