File 'charmcraft.yaml'

List of files in the charm project > charmcraft.yaml

Source

See also: How to configure Charmcraft

Starting with Charmcraft 2.5, the charmcraft.yaml file is the only yaml file generated by charmcraft init and the only yaml file in a charm project that a charm author is supposed to edit directly.

(charmcraft pack will use the information you provide here to generate the actions.yaml, config.yaml, and metadata.yaml, as well as all the other files it usually does.)

The charmcraft.yaml file is a file in your charm project that contains keys that allow you to declare various types of information about the project (type, name, summary, etc.; how it should build, and what actions, configurations, integrations, etc.) in a form that can be used by Charmcraft, Charmhub, and Juju.

If you’re starting from an empty file, the only required key is the type key. However, depending on what value you set it to (charm or bundle), other keys become required as well.


Expand to view the full spec with sample content all at once
#This is intentionally designed to be a fairly complex charm definition. It makes use
#  of every available keyword in charmcraft.yaml, expressing as much as possible.

type: charm
name: full-charm
summary: A fully-defined charm, making use of all the available charm keywords.
description: |
  This is intentionally designed to be a fairly complex charm definition. It makes use
  of every available keyword in charmcraft.yaml, expressing as much as possible.
analysis:
  ignore:
    attributes:
    - framework
    linters:
    - entrypoint
charmhub:
  api-url: https://api.staging.charmhub.io
  storage-url: https://storage.staging.snapcraftcontent.com
parts:
  im-not-calling-this-what-you-expect:
    plugin: charm
    source: .
    charm-entrypoint: src/charm.py
    charm-binary-python-packages: []
    charm-python-packages: []
    charm-requirements: []
    charm-strict-dependencies: false
  another-part:
    plugin: nil
bases:
- build-on:
  - name: ubuntu
    channel: '22.04'
    architectures:
    - amd64
    - riscv64
  - name: ubuntu
    channel: '20.04'
    architectures:
    - amd64
    - arm64
  run-on:
  - name: ubuntu
    channel: '22.04'
    architectures:
    - amd64
  - name: ubuntu
    channel: '22.04'
    architectures:
    - riscv64
  - name: ubuntu
    channel: '22.04'
    architectures:
    - arm64
- build-on:
  - name: ubuntu
    channel: '24.04'
  run-on:
  - name: ubuntu
    channel: '24.04'
    architectures:
    - amd64
    - arm64
    - riscv64
    - s390x
    - ppc64el
    - armhf
actions:
  snapshot:
    description: Take a snapshot of the database.
    params:
      filename:
        type: string
        description: The name of the snapshot file.
      compression:
        type: object
        description: The type of compression to use.
        properties:
          kind:
            type: string
            enum:
            - gzip
            - bzip2
            - xz
          quality:
            description: Compression quality
            type: integer
            minimum: 0
            maximum: 9
    required:
    - my-favourite-photo.tiff
    additionalProperties: false
assumes:
- any-of:
  - juju >= 2.9
  - all-of:
    - juju >= 3.0
    - juju < 4.0
- k8s-api
containers:
  super-app:
    resource: super-app-image
    mounts:
    - storage: logs
      location: /logs
devices:
  super-cool-gpu:
    type: amd.com/gpu
    description: Some sweet AMD GPU
    countmin: 69
    countmax: 420
  lame-gpu:
    type: nvidia.com/gpu
    description: A GPU I regret buying
    countmin: 0
    countmax: 1
extra-bindings:
  Ring of Power: null
peers:
  friend:
    interface: life
    limit: 150
    optional: true
    scope: container
provides:
  self:
    interface: identity
requires:
  parent:
    interface: birth
    limit: 2
    optional: false
    scope: global
resources:
  water:
    type: file
    filename: /dev/h2o
  super-app-image:
    type: oci-image
    description: OCI image for the Super App (hub.docker.com/_/super-app)
storage:
  jbod:
    type: block
    description: A nice block storage for me to use as swap space
    shared: false
    properties:
    - transient
subordinate: false
terms:
- Butterscotch is regal
- Cara is adorable
links:
  contact: Please send your answer to Old Pink, care of the Funny Farm, Chalfont
  documentation: https://juju.is/docs/sdk/charmcraft-yaml
  issues:
  - https://launchpad.net/~charmcraft-team
  - https://github.com/canonical/charmcraft/issues
  source:
  - https://github.com/canonical/charmcraft
  website:
  - https://snapcraft.io/charmcraft
config:
  options:
    name:
      default: Wiki
      description: The name, or Title of the Wiki
      type: string
    skin:
      default: vector
      description: skin for the Wiki
      type: string
    logo:
      description: URL to fetch logo from
      type: string
    admins:
      description: 'Comma-separated list of admin users to create: user:pass[,user:pass]+'
      type: string
    debug:
      default: false
      type: boolean
      description: turn on debugging features of mediawiki

Read on to find out more about each key.

Contents:

actions

Example:

actions:
  snapshot:
    description: Take a snapshot of the database.
    params:
      filename:
        type: string
        description: The name of the snapshot file.
      compression:
        type: object
        description: The type of compression to use.
        properties:
          kind:
            type: string
            enum:
            - gzip
            - bzip2
            - xz
          quality:
            description: Compression quality
            type: integer
            minimum: 0
            maximum: 9
    required:
    - my-favourite-photo.tiff
    additionalProperties: false

analysis

Status: Optional.

Purpose: Defines how the analysis done on the package will behave. This analysis is run implicitly as part of the pack command but can be called explicitly with the charmcraft analyze command.

Structure: So far the only thing that can be configured is which attributes or linters will be ignored.

analysis:
  ignore:
    attributes: [<check-name>,...]
    linters: [<check-name>,...]

Example:

analysis:
  ignore:
    attributes:
    - framework
    linters:
    - entrypoint

assumes

Status: Optional. Recommended for Kubernetes charms.

Purpose: Allows charm authors to explicitly state in the metadata of a charm various features that a Juju model must be able to provide to ensure that the charm can be successfully deployed on it. When a charm comes preloaded with such requirements, this enables Juju to perform a pre-deployment check and to display user-friendly error messages if a feature requirement cannot be met by the model that the user is trying to deploy the charm to. If the assumes section of the charm metadata is omitted, Juju will make a best-effort attempt to deploy the charm, and users must rely on the output of juju status to figure out whether the deployment was successful. The assumes key is available since 2.9.23.

Structure: The key consists of a list of features that can be given either directly or, depending on the complexity of the condition you want to enforce, nested under one or both of the boolean expressions any-of or all-of, as shown below. In order for a charm to be deployed, all entries in the assumes block must be satisfied.

assumes:
    - <feature_name>
    - any-of:
        - <feature_name>
        - <feature_name>
    - all-of:
        - <feature_name>
        - <feature_name>

The supported feature names are as below:

juju <comparison predicate> <version number>

E.g., juju < 3.0.
E.g., juju >= 2.9

The charm deploys iff the model runs agent binaries with the specified Juju version(s). Since 2.9.23
k8s-api The charm deploys iff the underlying substrate for the model is Kubernetes. Since 2.9.23

The Boolean expressions are defined as below:

any-of The sub-expression is satisfied if any of the provided child expressions is satisfied.
all-of The sub-expression is satisfied if all of the provided child expressions are satisfied.

Examples:


Expand to see a simple example
assumes:
    - juju >= 2.9.23
    - k8s-api

Expand to see an example with a nested expression
assumes:
- any-of:
  - juju >= 2.9
  - all-of:
    - juju >= 3.0
    - juju < 4.0
- k8s-api

bases

Changes starting with Charmcraft 3:

bases is replaced by base , build-base, and platforms.

See more
# The run time base, the base format is <os-name>@<os-release>,
# accepted bases are:
# - ubuntu@24.04
base: <base>
# The build time base, if not defined the base is also the build time 
# base, in addition to valid bases, the build-base can be "devel"
# which would use the latest in development Ubuntu Series.
build-base: <base>

platforms:
     # The supported platforms, may omit build-for if platform-name
     # is a valid arch, valid architectures follow the Debian architecture names,
     # accepted architectures are:
     # - amd64
     # - arm64
     # - armhf
     # - ppc64el
     # - riscv64
     # - s390x
     <platform-name>:
         # The build time architecture
         build-on: <list-of-arch> | <arch>
         # The run time architecture
         build-for: <list-of-arch> | <arch>

Status: If the type key is set to charm, required. (If the type key is set to bundle, leads to an error.)

Purpose: Specifies a list of environments (OS version and architecture) where the charm must be built on and run on.

When packing in “destructive mode”, the base(s) that match(es) the current environment will be used, otherwise an instance will be requested to LXD or Multipass for each specified base to pack in that environment.

Structure: This key supports a list of bases where the charm can be built, and where that build can run. Each item can be expressed using two different internal structures, a short and a long form. The long one is more explicit:

bases:
  - build-on:
      - name: <name>
        channel: <channel>
        architectures:
          - <arch>
    run-on:
      - name: <name>
        channel: <channel>
        architectures:
          - <arch>

The run-on part of each build-on is optional, and defaults to what’s specified in the corresponding ‘build-on’. And in both structures the list of architecture strings is also optional, defaulting to the machine architecture.

The short form is more concise and simple (at the cost of being less flexible):

bases:
  - name: <name>
    channel: <channel>
    architectures:
      - <arch>

It implies that the specified base is to be used for both build-on and run-on. And as above, the list of architecture strings is also optional, defaulting to the machine architecture.

Be sure to check this detailed documentation for more information and the different possibilities of these structures, including several examples.

Example:

bases:
- build-on:
  - name: ubuntu
    channel: '22.04'
    architectures:
    - amd64
    - riscv64
  - name: ubuntu
    channel: '20.04'
    architectures:
    - amd64
    - arm64
  run-on:
  - name: ubuntu
    channel: '22.04'
    architectures:
    - amd64
  - name: ubuntu
    channel: '22.04'
    architectures:
    - riscv64
  - name: ubuntu
    channel: '22.04'
    architectures:
    - arm64
- build-on:
  - name: ubuntu
    channel: '24.04'
  run-on:
  - name: ubuntu
    channel: '24.04'
    architectures:
    - amd64
    - arm64
    - riscv64
    - s390x
    - ppc64el
    - armhf

charmhub

In Charmcraft 3.0 and up, these keys will no longer be valid in charmcraft.yaml. Use the environment variables CHARMCRAFT_STORE_API_URL, CHARMCRAFT_UPLOAD_URL and CHARMCRAFT_REGISTRY_URL instead.

Status: Optional.

Purpose: Configures Charmcraft’s interaction with store servers.

Structure: This key allows for the configuration of two values—the base URL for the Charmhub API and the base URL to push binaries to Charmhub. These keys are also optional.

charmhub:
  api-url: <api url>
  storage-url: <storage url>
  registry-url: <registry url>

The key is used mostly in the context of “private” charm stores, defaulting to the standard Canonical services to operate with charms.

Example:

charmhub:
  api-url: https://api.staging.charmhub.io
  storage-url: https://storage.staging.snapcraftcontent.com

config

See also: How to add a configuration option to a charm

Status: Optional.

Purpose: The config key allows you to create configuration options for your charm.

config:
  options:
    # Each option name is the name by which the charm will query the option.
    <option name>:
      # (Required) The type of the option
      type: string | int | float | boolean | secret
      # (Optional) The default value of the option
      default: <a reasonable default value of the same type as the option>
      # (Optional): A string describing the option. Also appears on charmhub.io
      description: <description string>

For the case where the type is secret: This is a string that needs to correspond to the secret URI.

Example:

Expand to see an example containing each type
config:
  options:
    name:
      default: Wiki
      description: The name, or Title of the Wiki
      type: string
    skin:
      default: vector
      description: skin for the Wiki
      type: string
    logo:
      description: URL to fetch logo from
      type: string
    admins:
      description: 'Comma-separated list of admin users to create: user:pass[,user:pass]+'
      type: string
    debug:
      default: false
      type: boolean
      description: turn on debugging features of mediawiki

containers

Status: Required for Kubernetes charms (except for proxy charms running on Kubernetes).

Purpose: The containers key allows you to define a map of containers to be created adjacent to the charm (as a sidecar, in the same pod).

Structure: This key consists of a list of containers along with their specification. Each container can be specified in terms of resource, bases, and mounts, where one of either the resource or the bases subkeys must be defined, and mounts is optional. resource stands for the OCI image resource used to create the container; to use it, specify an OCI image resource name (that you will then define further in the resources block). bases is a list of bases to be used for resolving a container image, in descending order of preference; to use it, specify a base name (for example, ubuntu, centos, windows, osx, opensuse), a channel, and an architecture. And mounts is a list of mounted storages for this container; to use it, specify the name of the storage to mount from the charm storage and, optionally, the location where to mount the storage.

containers:
  <container name>:
    resource: <resource name>
    bases:
      - name: <base name>
        channel: <track[/risk][/branch]>
        architectures:
          - <architecture>
    mounts:
      - storage: <storage name>
        location: <path>

Example:

Expand to see an example with `resource` and `mounts`
containers:
    super-app:
        resource: super-app-image
        mounts:
            - storage: logs
              location: /logs

description

Status: If the type key is set to charm, required.

Example:

description: |
  A Juju-operated Traefik operator that routes requests from the outside of a
  Kubernetes cluster to Juju units and applications.
  

devices

Status: Optional

Purpose: Defines the device requests for the charm, for example a GPU.

Structure:

devices:
    # Each key represents the name of the device
    <device name>:

        # (Required) The type of device requested
        type: gpu | nvidia.com/gpu | amd.com/gpu

        # (Optional) Description of the requested device
        description: <description>

        # (Optional) Minimum number of devices required
        countmin: <n>

        # (Optional) Maximum number of devices required
        countmax: <n>

Example:

devices:
  super-cool-gpu:
    type: amd.com/gpu
    description: Some sweet AMD GPU
    countmin: 69
    countmax: 420
  lame-gpu:
    type: nvidia.com/gpu
    description: A GPU I regret buying
    countmin: 0
    countmax: 1

extra-bindings

Status: Optional.

Purpose: Extra bindings for the charm. For example binding extra network interfaces.

Structure: A key-only map; key represents the name of the binding:

extra-bindings:
    <binding name>:

Example:

extra-bindings:
  Ring of Power: null

Status: Optional. Recommended.

Purpose: Links to various additional information, to be displayed on Charmhub.

Example:

links:
  contact: Please send your answer to Old Pink, care of the Funny Farm, Chalfont

  # Link to documentation cover page on Discourse:
  documentation: https://discourse.charmhub.io/t/traefik-k8s-docs-index/10778

  # Link to bug tracker:
  issues: 
  - https://github.com/canonical/traefik-k8s-operator/issues

  # Link to source code:
  source:
  - https://github.com/canonical/traefik-k8s-operator

  # Link to charm project website outside of Charmhub, if available.
  website:
  - https://charmed-kubeflow.io/

name

Status: If the type key is set to charm, required.

Purpose: The name of the charm. Determines the charm page URL in Charmhub and the name administrators will ultimately use to deploy the charm. E.g. juju deploy <name>.

Structure:

name: <name>

Example:

name: traefik-k8s

parts

Status: Optional. Only used by the pack command.

Purpose: Configures the various mechanisms to obtain, process and prepare data from different sources that end up being a part of the final charm. It’s optional, and only used by the pack command.

Value: Map. Keys are user-defined part names. The value of each key is a map where keys are part properties. Regarding the plugin property: In addition to the standard set, Charmcraft provides 3 further plugins: charm, bundle, reactive.

See more: Craft Parts | Part properties

Example:

parts:
  libs:
    plugin: dump
    source: /usr/local/lib/
    organize:
      "libxxx.so*": lib/
    prime:
      - lib/

Details:

A part is a declarative representation on how to add a source or component to the charm. It specifies the mechanisms to obtain, process and prepare individual subsets of the final artefact (each “part” of the “whole”).

Parts have logic encoded in plugins: a plugin is what has the knowledge into how to transform a given source declared in a part into a usable artefact for a charm.

The parts key is optional. If not included, it will default to a charm or bundle part (depending on the project type), which will use a charm or bundle plugin correspondingly.

Those two plugins and the reactive one, all detailed below, are provided by Charmcraft itself and can be used by other custom parts.

Other plugins are provided by the Craft Parts library (which is a Charmcraft dependency), check this supported plugins page. Furthermore, other plugins can be written if needed, refer to this writing local plugins documentation.

Beyond plugins, Charmcraft gives the possibility of using the full power of the parts lifecycle, allowing to add parts, and also to override and customise steps of a part’s lifecycle (pull, build, stage, and prime) using shell scripts directly sourced from charmcraft.yaml, both for custom written parts and the ones included by Charmcraft. Please refer to the Parts Lifecycle documentation to learn more about this.

The charm plugin

Used to pack a Charm that is based on the Operator Framework.

Supports the following configuration:

parts:
  my-charm:
    plugin: charm
    charm-entrypoint: <path to an entrypoint script>
    charm-requirements: <list of requirements files>
    charm-python-packages: <list of package names>
    charm-binary-python-packages: <list of package names>
    prime: <list of paths to extra files>

In detail:

  • charm-entrypoint: The charm entry point, relative to the project directory. It is optional (new in charmcraft 1.2), if not defined defaults to src/charm.py.

  • charm-requirements: A list of requirements files specifying Python dependencies. It is optional (new in charmcraft 1.2); if not defined, defaults to a list with one requirements.txt entry if that file is present in the project directory.

  • charm-python-packages: A list of Python packages to install before installing requirements. These packages will be installed from sources and built locally at packing time. It is optional (new in charmcraft 1.4), defaults to empty.

  • charm-binary-python-packages: A list of python packages to install before installing requirements and regular Python packages. Binary packages are allowed, but they may also be installed from sources if a package is only available in source form. It is optional (new in charmcraft 1.4), defaults to empty.

  • prime: List of extra file and directory paths to include in the charm. Note that bundle.yaml, the entry point file and hooks are included automatically when packing a charm. Additionally, config.yaml, metrics.yaml, actions.yaml, lxd-profile.yaml, templates, version, lib and mod will be included if they exist in the project directory. It is optional.

The bundle plugin

Used to pack a charm bundle, a collection of charms which have been carefully combined and configured in order to automate a multi-charm solution.

Supports the following configuration:

parts:
  my-bundle:
    prime: <list of paths to extra files>
    plugin: bundle

In detail:

  • prime: List of extra file and directory paths to include in the bundle. Note that bundle.yaml and README.md are included automatically when packing a bundle. Optional.

The reactive plugin

Used to pack charms using the reactive framework.

Note that this is a framework that has now been superseded by the Ops library, please use that framework instead of reactive. Support for reactive in Charmcraft is only to ease the transition of old charms into the new framework.

Supports the following configuration:

parts:
  charm:
    source: .
    plugin: reactive
    build-snaps: [charm]
    reactive-charm-build-arguments: <list of command line options>

The reactive_charm_build_arguments allows to include extra command line arguments in the underlying charm build call.

Example:

parts:
  im-not-calling-this-what-you-expect:
    plugin: charm
    source: .
    charm-entrypoint: src/charm.py
    charm-binary-python-packages: []
    charm-python-packages: []
    charm-requirements: []
    charm-strict-dependencies: false
  another-part:
    plugin: nil

peers, provides, requires

See also: Relation (integration)


Expand to view an example featuring all three relation keys (peers, provides, or requires)
peers:
  friend:
    interface: life
    limit: 150
    optional: true
    scope: container
provides:
  self:
    interface: identity
requires:
  parent:
    interface: birth
    limit: 2
    optional: false
    scope: global

Expand to view the full schema for a chosen relation type (peers, provides, or requires)
<relation type>: # 'peers', 'provides', or 'requires'
    # Each key represents the name of the relation as known by this charm
    <relation name>:

        # (Required) The interface schema that this relation conforms to
        interface: <interface name>

        # (Optional) Maximum number of supported connections to this relation
        # endpoint. This field is an integer
        limit: <n>

        # (Optional) Defines if the relation is required. Informational only.
        optional: true | false

        # (Optional) The scope of the relation. Defaults to "global"
        scope: global | container

<relation type>

Status: If you want to define any kind of integration, required.

Purpose: To define an integration endpoint.

Structure: Name: Depending on what kind of an integration you are trying to define: peers, provides, or requires. Type: Map. Value: One or more key-value pairs denoting a relation and its associated properties.

<relation type>.<relation name>

Status: Required.

Purpose: To define the name of the relation as known by this charm.

Structure: Name: User-defined. Type: string. Value:

<relation type>.<relation name>.interface

Status: Required.

Purpose: To define the interface schema that this relation conforms to.

Structure: Type: String. Value: The name of the interface. Usually defined by the author of the charm providing the interface. Cannot be juju. Cannot begin with juju-. Must only contain characters a-z and - and cannot start with -. :warning: The interface name is the only means of establishing whether two charms are compatible for integration; and carries with it nothing more than a mutual promise that the provider and requirer somehow know the communication protocol implied by the name.

<relation type>.<relation name>.limit

Status: Optional.

Purpose: To define the maximum number of supported connections to this relation endpoint.

Structure: Type: Integer. Value: User-defined. Default value: nil.

<relation type>.<relation name>.optional

Status: Optional.

Purpose: To define if the relation is required. Informational only.

Structure: Type: Boolean. Possible values: true, false. Default value: false.

<relation type>.<relation name>.scope

Status: Optional.

Purpose: To define the scope of the relation, that is, the set of units from integrated applications that are reported to the unit as members of the integration.

Structure: Type: String. Possible values: container, global. Container-scoped integrations are restricted to reporting details of a single principal unit to a single subordinate, and vice versa, while global integrations consider all possible remote units. Subordinate charms are only valid if they have at least one requires integration with container scope. Default value: global.

resources

See also: Resource

Status: Optional.

Purpose: The resources key is where you defines the resources mentioned under the resource key of the containers key.

Structure:

# (Optional) Additional resources that accompany the charm
resources:
    # Each key represents the name of a resource 
    # mentioned in the 'resource' subkey of the 'containers' key.
    <resource name>:

        # (Required) The type of the resource
        type: file | oci-image

        # (Optional) Description of the resource and its purpose
        description: <description>

        # (Required: when type:file) The filename of the resource as it should 
        # appear in the filesystem
        filename: <filename>

Examples:


Expand to see an example with a file resource
resources:
  water:
    type: file
    filename: /dev/h2o

Expand to see an example with an OCI-image resource
resources:
    super-app-image:
        type: oci-image
        description: OCI image for the Super App (hub.docker.com/_/super-app)

storage

Status: Optional.

Purpose: Storage requests for the charm.

Structure:

storage:
  # Each key represents the name of the storage
  <storage name>:

      # (Required) Type of the requested storage
      type: filesystem | block

      # (Optional) Description of the storage requested
      description: <description>

      # (Optional) The mount location for filesystem stores. For multi-stores
      # the location acts as the parent directory for each mounted store.
      location: <location>

      # (Optional) Indicates if all units of the application share the storage
      shared: true | false

      # (Optional) Indicates if the storage should be made read-only (where possible)
      read-only: true | false

      # (Optional) The number of storage instances to be requested
      multiple:
          range: <n> | <n>-<m> | <n>- | <n>+

      # (Optional) Minimum size of requested storage in forms G, GiB, GB. Size 
      # multipliers are M, G, T, P, E, Z or Y. With no multiplier supplied, M 
      # is implied.
      minimum-size: <n>| <n><multiplier>

      # (Optional) List of properties, only supported value is "transient"
      properties:
          - transient

Example:

storage:
  jbod:
    type: block
    description: A nice block storage for me to use as swap space
    shared: false
    properties:
    - transient

subordinate

Status: Optional.

Purpose: Configures whether the charm is meant to be deployed as a subordinate to a principal charm.

Structure:

subordinate: true | false

Example:

subordinate: false

summary

Status: If the type key is set to charm, required.

Structure: A short, one-line description of the charm.

Example:

summary: |
  A Juju charm to run a Traefik-powered ingress controller on Kubernetes.

terms

Status: Optional.

Purpose: Lists the terms that any charm user agree to when they’re using the charm.

Structure: The list of terms:

terms:
    - <term>

Example:

terms:
- Butterscotch is regal
- Cara is adorable

title

Status: Optional.

Purpose: Defines the title of your charm on Charmhub.

Example:

title: |
  Traefik Ingress Operator for Kubernetes

type

Status: Required.

Purpose: Indicates the type of entity for which the present config exists.

Structure: Type: String. Value: charm or bundle.

Example:

type: charm

I don’t quite understand how this example works for actions. In what sense does my-favourite-photo.tiff relate to the required key? I’m interested in how you specify that a particular action’s parameter is required.

This part gets passed directly to juju as-is so I’m not 100% sure, but I believe that should be:

required:
  - filename

That is to say, the parameter named filename is required for this action, but the one named compression is optional.

@mthaddon Looking at the content we had for the actions.yaml file, copied below, it seems like required is a JSON schema object instance keyword (https://json-schema.org/understanding-json-schema/reference/object#required). You can indeed use it either at the top-level of an action but also nested under a particular param. I’ll update this doc to make this clearer. Thanks!


  1. The additionalProperties and required keys from JSON Schema can be used at the top-level of an action (adjacent to description and params), but also used anywhere within a nested schema.

<action>.*

  • Status: Optional.
  • Purpose: To define additional validation or annotation keywords of the action schema object.
  • Structure: Name: A valid keyword of a JSON Schema object instance that will be merged into the action schema object. For example, additionalProperties or required. Type: Various.