IOC instance YAML and schemas reference#

This page is a field-by-field reference for an IOC instance file (*.ibek.ioc.yaml) and for the three JSON schema artifacts that validate the ibek YAML files. The audience is IOC-instance designers writing the file that describes a single IOC.

An IOC instance file lists the entities (port drivers, axes, databases, …) that make up one IOC. ibek loads it into the IOC model, validates every entity against the entity models published by the support modules baked into the generic-IOC image, and renders the startup assets (st.cmd, database substitutions, etc.).

See also

The $schema header convention#

The first line of an instance file is, by convention, a yaml-language-server modeline that points an editor at the schema to validate against:

# yaml-language-server: $schema=../schemas/motorSim.ibek.ioc.schema.json

The comment is not interpreted by ibek itself — it is a hint for editors (VS Code, Neovim, …) so they offer completion and inline validation while you type. It should point at one of the ioc schemas described in Schemas below.

When an instance is managed by ibek pattern, the header is rewritten automatically to point at the self-contained per-instance schema (../ioc.schema.json) every time ibek pattern schema runs.

Top-level keys#

The instance file has four top-level keys, defined by the IOC model (ibek.ioc.IOC):

Key

Type

Required

Description

ioc_name

str

yes

Name of the IOC instance. May contain Jinja (see below).

description

str

yes

Free-text description of what the IOC does.

entities

list

yes

The ordered list of entity instances that make up the IOC.

shared

Sequence

no

Scratch space for YAML anchors; ignored by ibek. Defaults to empty.

ioc_name#

The IOC instance name. Because it is a string field it is Jinja-rendered, so it is commonly derived rather than hard-coded. Two idioms seen in real instances:

# take the name from the yaml file name (without the .ibek.ioc.yaml suffix)
ioc_name: "{{ ioc_yaml_file_name }}"
# take the name from an environment variable
ioc_name: "{{ _global.get_env('IOC_NAME') }}"

shared#

shared exists only to give you somewhere to declare reusable YAML anchors that can be aliased into multiple entities. ibek does not read it — it is dropped after YAML parsing.

Entity entries#

Each item in entities is an entity instance. Every entry has two built-in fields plus the parameters of its model:

Field

Type

Required

Default

Description

type

str

yes

Selects the entity model, written <module>.<EntityModelName>.

entity_enabled

bool

no

True

Set false to keep the entry but skip rendering it.

type names the support module and the entity model within it, e.g. asyn.AsynIP or motorSim.simMotorController. ibek looks up the matching dynamically-generated subclass of Entity (ibek.ioc.Entity) and validates the remaining keys against that model’s parameters.

Important validation behaviour:

  • Unknown keys are rejected. Entity models are validated with Pydantic extra="forbid", so a mistyped or unsupported argument is an error rather than being silently ignored.

  • Arguments are Jinja-rendered, including references between arguments of the same entity. In the sample below M: M{{ADDR}} and DESC: Motor {{ADDR}} for ioc {{ioc_name}} both interpolate other values.

  • Built-in entities (those whose type starts with ibek., such as ibek.repeat) are provided by ibek itself and subclass BuiltInEntity (ibek.ioc.BuiltInEntity) rather than coming from a support module.

Worked example#

tests/samples/iocs/motorSim.ibek.ioc.yaml — a simulated-motion IOC instance#
# yaml-language-server: $schema=../schemas/motorSim.ibek.ioc.schema.json

ioc_name: "{{ ioc_yaml_file_name }}"
description: Example simulated motion IOC for Testing ibek

entities:
  - type: asyn.AsynIP
    name: controllerOnePort
    port: 192.168.0.55:2002

  - type: motorSim.simMotorController
    port: controllerOnePort
    controllerName: controllerOne
    numAxes: 4
    P: "IBEK-MO-TST-01:"

  - type: motorSim.simMotorAxis
    controller: controllerOne
    # Use ADDR in other fields to verify jinja templating between Args
    M: M{{ADDR}}
    ADDR: 0
    # Also use ioc_name to verify jinja templating of ioc_name
    DESC: Motor {{ADDR}} for ioc {{ioc_name}}
    home: 500

  - type: motorSim.simMotorAxis
    controller: controllerOne
    M: M{{ADDR}}
    ADDR: 1
    # verify escaping for jinja templating
    DESC: Motor {{ADDR}} {% raw %} {{enclosed in escaped curly braces}} {% endraw %}
    home: 500

  - type: motorSim.simMotorAxis
    controller: controllerOne
    M: M{{ADDR}}
    ADDR: 2
    # testing default DESC
    home: 1500

  - type: motorSim.simMotorAxis
    controller: controllerOne
    M: M{{ADDR}}
    ADDR: 3
    DESC: Motor {{ADDR}}
    home: 2500

  - type: motorSim.simMotorAxis
    controller: controllerOne
    M: CS_M{{ADDR}}
    ADDR: 1
    DESC: CS Motor {{ADDR}}
    home: 100
    CS_NUM: 3
    is_cs: true

  - type: motorSim.simMotorAxis
    controller: controllerOne
    M: CS_M{{ADDR}}
    ADDR: 2
    DESC: CS Motor {{ADDR}}
    home: 100
    CS_NUM: 3
    is_cs: true

Rendering this instance produces the startup script below (one of several generated assets):

tests/samples/outputs/motorSim/st.cmd — generated from the instance above#
# EPICS IOC Startup Script generated by https://github.com/epics-containers/ibek

cd "/epics/ioc"

epicsEnvSet NAME_AS_ENV_VAR my name is controllerOnePort

dbLoadDatabase dbd/ioc.dbd
ioc_registerRecordDeviceDriver pdbbase

# Setting up Asyn Port controllerOnePort on 192.168.0.55:2002:
# AsynIPConfigure({{name}}, {{port}}, {{stop}}, {{parity}}, {{bits}}) 
AsynIPConfigure(controllerOnePort, 192.168.0.55:2002, 1, none, 8)
asynSetOption(9600, 0, N, Y)
asynOctetSetInputEos("\n")
asynOctetSetOutputEos("\n")
# motorSimCreateController(controller_asyn_port_name, axis_count)
# testing escaping:  {{enclosed in escaped curly braces}} 
motorSimCreateController(controllerOne, 4)

dbLoadRecords /epics/runtime/ioc.db
iocInit

# motorSimCreateAxis(controller_asyn_port_name, axis, axis_description)
motorSimConfigAxis(controllerOne, 0, 20000, -20000, 500, 500)
# motorSimCreateAxis(controller_asyn_port_name, axis, axis_description)
motorSimConfigAxis(controllerOne, 1, 20000, -20000, 500, 500)
# motorSimCreateAxis(controller_asyn_port_name, axis, axis_description)
motorSimConfigAxis(controllerOne, 2, 20000, -20000, 1500, 1500)
# motorSimCreateAxis(controller_asyn_port_name, axis, axis_description)
motorSimConfigAxis(controllerOne, 3, 20000, -20000, 2500, 2500)
# motorSimCreateAxis(controller_asyn_port_name, axis, axis_description)
motorSimConfigAxis(controllerOne, 1, 20000, -20000, 100, 100)
# motorSimCreateAxis(controller_asyn_port_name, axis, axis_description)
motorSimConfigAxis(controllerOne, 2, 20000, -20000, 100, 100)

Schemas#

ibek works with three JSON schema artifacts. They differ in scope — what set of entity models they describe — and in which command produces them.

Note

The schema names below are the current ones. The old names ibek.defs.schema.json and <container>.ibek.entities.schema.json are retired and should not be used or referenced.

1. The global support schema — ibek.support.schema.json#

Validates any *.ibek.support.yaml support-module file (the files that define entity models). It is global: it does not depend on any particular image or support module. Produce it with:

ibek support generate-schema [--output FILE]

Prints to stdout, or writes to --output if given. It is the Support.get_schema() JSON schema of the Support model (ibek.support.Support).

tests/samples/schemas/ibek.support.schema.json
{
  "$defs": {
    "BoolParam": {
      "additionalProperties": false,
      "description": "An argument with an bool value",
      "properties": {
        "type": {
          "const": "bool",
          "default": "bool",
          "title": "Type",
          "type": "string"
        },
        "description": {
          "description": "Description of what the argument will be used for",
          "title": "Description",
          "type": "string"
        },
        "default": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "description": "A Jinja2 template string",
              "pattern": ".*\\{\\{.*\\}\\}.*",
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Default"
        }
      },
      "required": [
        "description"
      ],
      "title": "BoolParam",
      "type": "object"
    },
    "Comment": {
      "additionalProperties": false,
      "description": "A script snippet that will have '# ' prepended to every line\nfor insertion into the startup script",
      "properties": {
        "type": {
          "const": "comment",
          "default": "comment",
          "title": "Type",
          "type": "string"
        },
        "when": {
          "$ref": "#/$defs/When",
          "default": "every",
          "description": "One of first / every / last"
        },
        "value": {
          "default": "",
          "description": "A comment to add into the startup script",
          "title": "Value",
          "type": "string"
        }
      },
      "title": "Comment",
      "type": "object"
    },
    "Database": {
      "additionalProperties": false,
      "description": "A database file that should be loaded by the startup script and its args",
      "properties": {
        "file": {
          "description": "Filename of the database template in <module_root>/db",
          "title": "File",
          "type": "string"
        },
        "enabled": {
          "default": "True",
          "description": "Set to False to disable loading this database",
          "title": "Enabled",
          "type": "string"
        },
        "args": {
          "anyOf": [
            {
              "additionalProperties": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "type": "object"
            },
            {
              "type": "null"
            }
          ],
          "description": "Dictionary of args and values to pass through to database. A value of None is equivalent to ARG: '{{ ARG }}'. See `UTILS.render_map` for more details.",
          "title": "Args"
        }
      },
      "required": [
        "file",
        "args"
      ],
      "title": "Database",
      "type": "object"
    },
    "Define": {
      "additionalProperties": false,
      "description": "A calculated value for an Entity Model",
      "properties": {
        "description": {
          "description": "Description of what the value will be used for",
          "title": "Description",
          "type": "string"
        },
        "value": {
          "description": "The contents of the value",
          "title": "Value"
        },
        "type": {
          "anyOf": [
            {
              "$ref": "#/$defs/DefineType"
            },
            {
              "type": "null"
            }
          ],
          "default": "str",
          "description": "The type of the value"
        }
      },
      "required": [
        "description",
        "value"
      ],
      "title": "Define",
      "type": "object"
    },
    "DefineType": {
      "description": "The type of a value",
      "enum": [
        "str",
        "float",
        "int",
        "bool",
        "list"
      ],
      "title": "DefineType",
      "type": "string"
    },
    "DictParam": {
      "additionalProperties": false,
      "description": "An argument with dict value",
      "properties": {
        "type": {
          "const": "dict",
          "default": "dict",
          "title": "Type",
          "type": "string"
        },
        "description": {
          "description": "Description of what the argument will be used for",
          "title": "Description",
          "type": "string"
        },
        "default": {
          "anyOf": [
            {
              "additionalProperties": true,
              "type": "object"
            },
            {
              "description": "A Jinja2 template string",
              "pattern": ".*\\{\\{.*\\}\\}.*",
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Default"
        }
      },
      "required": [
        "description"
      ],
      "title": "DictParam",
      "type": "object"
    },
    "EntityModel": {
      "additionalProperties": false,
      "description": "A Model for a class of Entity that an IOC instance may instantiate",
      "properties": {
        "name": {
          "description": "Publish EntityModel as type <module>.<name> for IOC instances",
          "title": "Name",
          "type": "string"
        },
        "description": {
          "description": "A description of the Support module defined here",
          "title": "Description",
          "type": "string"
        },
        "pre_defines": {
          "additionalProperties": {
            "$ref": "#/$defs/Define"
          },
          "default": {},
          "description": "Calculated values to use as additional arguments With Jinja evaluation before all Args",
          "title": "Pre Defines",
          "type": "object"
        },
        "parameters": {
          "additionalProperties": {
            "description": "union of arg types",
            "discriminator": {
              "mapping": {
                "bool": "#/$defs/BoolParam",
                "dict": "#/$defs/DictParam",
                "enum": "#/$defs/EnumParam",
                "float": "#/$defs/FloatParam",
                "id": "#/$defs/IdParam",
                "int": "#/$defs/IntParam",
                "list": "#/$defs/ListParam",
                "object": "#/$defs/ObjectParam",
                "str": "#/$defs/StrParam"
              },
              "propertyName": "type"
            },
            "oneOf": [
              {
                "$ref": "#/$defs/FloatParam"
              },
              {
                "$ref": "#/$defs/StrParam"
              },
              {
                "$ref": "#/$defs/IntParam"
              },
              {
                "$ref": "#/$defs/BoolParam"
              },
              {
                "$ref": "#/$defs/ObjectParam"
              },
              {
                "$ref": "#/$defs/IdParam"
              },
              {
                "$ref": "#/$defs/EnumParam"
              },
              {
                "$ref": "#/$defs/DictParam"
              },
              {
                "$ref": "#/$defs/ListParam"
              }
            ]
          },
          "default": {},
          "description": "The arguments IOC instance should supply",
          "title": "Parameters",
          "type": "object"
        },
        "post_defines": {
          "additionalProperties": {
            "$ref": "#/$defs/Define"
          },
          "default": {},
          "description": "Calculated values to use as additional arguments With Jinja evaluation after all Args",
          "title": "Post Defines",
          "type": "object"
        },
        "pre_init": {
          "default": [],
          "description": "Startup script snippets to add before iocInit()",
          "items": {
            "anyOf": [
              {
                "$ref": "#/$defs/Text"
              },
              {
                "$ref": "#/$defs/Comment"
              }
            ]
          },
          "title": "Pre Init",
          "type": "array"
        },
        "post_init": {
          "default": [],
          "description": "Startup script snippets to add post iocInit(), such as dbpf",
          "items": {
            "anyOf": [
              {
                "$ref": "#/$defs/Text"
              },
              {
                "$ref": "#/$defs/Comment"
              }
            ]
          },
          "title": "Post Init",
          "type": "array"
        },
        "databases": {
          "default": [],
          "description": "Databases to instantiate",
          "items": {
            "$ref": "#/$defs/Database"
          },
          "title": "Databases",
          "type": "array"
        },
        "env_vars": {
          "default": [],
          "description": "Environment variables to set in the boot script",
          "items": {
            "$ref": "#/$defs/EnvironmentVariable"
          },
          "title": "Env Vars",
          "type": "array"
        },
        "pvi": {
          "anyOf": [
            {
              "$ref": "#/$defs/EntityPVI"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "PVI definition for Entity"
        },
        "sub_entities": {
          "default": [],
          "description": "The sub-entity instances that this collection is to instantiate",
          "items": {
            "$ref": "#/$defs/SubEntity"
          },
          "title": "Sub Entities",
          "type": "array"
        },
        "shared": {
          "default": [],
          "description": "A place to create any anchors required for repeating YAML",
          "items": {},
          "title": "Shared",
          "type": "array"
        }
      },
      "required": [
        "name",
        "description"
      ],
      "title": "EntityModel",
      "type": "object"
    },
    "EntityPVI": {
      "additionalProperties": false,
      "description": "Entity PVI definition",
      "properties": {
        "yaml_path": {
          "description": "Path to .pvi.device.yaml - absolute or relative to PVI_DEFS",
          "title": "Yaml Path",
          "type": "string"
        },
        "ui_index": {
          "default": true,
          "description": "Whether to add the UI to the IOC index.",
          "title": "Ui Index",
          "type": "boolean"
        },
        "ui_macros": {
          "anyOf": [
            {
              "additionalProperties": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "type": "object"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Macros to launch the UI on the IOC index. These must be args of the Entity this is attached to.",
          "title": "Ui Macros"
        },
        "pv": {
          "default": false,
          "description": "Whether to generate a PVI PV. This adds a database template with info tags that create a PVAccess PV representing the device structure.",
          "title": "Pv",
          "type": "boolean"
        },
        "pv_prefix": {
          "default": "",
          "description": "PV prefix for PVI PV - e.g. \"$(P)\"",
          "title": "Pv Prefix",
          "type": "string"
        }
      },
      "required": [
        "yaml_path"
      ],
      "title": "EntityPVI",
      "type": "object"
    },
    "EnumParam": {
      "additionalProperties": false,
      "description": "An argument with an enum value",
      "properties": {
        "type": {
          "const": "enum",
          "default": "enum",
          "title": "Type",
          "type": "string"
        },
        "description": {
          "description": "Description of what the argument will be used for",
          "title": "Description",
          "type": "string"
        },
        "default": {
          "anyOf": [
            {},
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Default"
        },
        "values": {
          "additionalProperties": true,
          "description": "provides a list of values to make this argument an Enum",
          "title": "Values",
          "type": "object"
        }
      },
      "required": [
        "description",
        "values"
      ],
      "title": "EnumParam",
      "type": "object"
    },
    "EnvironmentVariable": {
      "additionalProperties": false,
      "description": "An environment variable that should be set in the startup script",
      "properties": {
        "name": {
          "description": "Name of environment variable",
          "title": "Name",
          "type": "string"
        },
        "value": {
          "description": "Value to set",
          "title": "Value",
          "type": "string"
        }
      },
      "required": [
        "name",
        "value"
      ],
      "title": "EnvironmentVariable",
      "type": "object"
    },
    "FloatParam": {
      "additionalProperties": false,
      "description": "An argument with a float value",
      "properties": {
        "type": {
          "const": "float",
          "default": "float",
          "title": "Type",
          "type": "string"
        },
        "description": {
          "description": "Description of what the argument will be used for",
          "title": "Description",
          "type": "string"
        },
        "default": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "description": "A Jinja2 template string",
              "pattern": ".*\\{\\{.*\\}\\}.*",
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Default"
        }
      },
      "required": [
        "description"
      ],
      "title": "FloatParam",
      "type": "object"
    },
    "IdParam": {
      "additionalProperties": false,
      "description": "Explicit ID argument that an object can refer to",
      "properties": {
        "type": {
          "const": "id",
          "default": "id",
          "title": "Type",
          "type": "string"
        },
        "description": {
          "description": "Description of what the argument will be used for",
          "title": "Description",
          "type": "string"
        },
        "default": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Default"
        }
      },
      "required": [
        "description"
      ],
      "title": "IdParam",
      "type": "object"
    },
    "IntParam": {
      "additionalProperties": false,
      "description": "An argument with an int value",
      "properties": {
        "type": {
          "const": "int",
          "default": "int",
          "title": "Type",
          "type": "string"
        },
        "description": {
          "description": "Description of what the argument will be used for",
          "title": "Description",
          "type": "string"
        },
        "default": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "description": "A Jinja2 template string",
              "pattern": ".*\\{\\{.*\\}\\}.*",
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Default"
        }
      },
      "required": [
        "description"
      ],
      "title": "IntParam",
      "type": "object"
    },
    "ListParam": {
      "additionalProperties": false,
      "description": "An argument with list value",
      "properties": {
        "type": {
          "const": "list",
          "default": "list",
          "title": "Type",
          "type": "string"
        },
        "description": {
          "description": "Description of what the argument will be used for",
          "title": "Description",
          "type": "string"
        },
        "default": {
          "anyOf": [
            {
              "items": {},
              "type": "array"
            },
            {
              "description": "A Jinja2 template string",
              "pattern": ".*\\{\\{.*\\}\\}.*",
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Default"
        }
      },
      "required": [
        "description"
      ],
      "title": "ListParam",
      "type": "object"
    },
    "ObjectParam": {
      "additionalProperties": false,
      "description": "A reference to another entity defined in this IOC",
      "properties": {
        "type": {
          "const": "object",
          "default": "object",
          "title": "Type",
          "type": "string"
        },
        "description": {
          "description": "Description of what the argument will be used for",
          "title": "Description",
          "type": "string"
        },
        "default": {
          "anyOf": [
            {
              "type": "string"
            },
            {},
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Default"
        }
      },
      "required": [
        "description"
      ],
      "title": "ObjectParam",
      "type": "object"
    },
    "StrParam": {
      "additionalProperties": false,
      "description": "An argument with a str value",
      "properties": {
        "type": {
          "const": "str",
          "default": "str",
          "title": "Type",
          "type": "string"
        },
        "description": {
          "description": "Description of what the argument will be used for",
          "title": "Description",
          "type": "string"
        },
        "default": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Default"
        }
      },
      "required": [
        "description"
      ],
      "title": "StrParam",
      "type": "object"
    },
    "SubEntity": {
      "additionalProperties": true,
      "description": "A loosely defined class to declare the Entities\nin an ibek.support.yaml file in the 'sub_entities' property of an Entity\nsection",
      "properties": {
        "type": {
          "description": "The type of this entity",
          "title": "Type",
          "type": "string"
        },
        "entity_enabled": {
          "default": true,
          "description": "enable or disable this entity instance",
          "title": "Entity Enabled",
          "type": "boolean"
        }
      },
      "required": [
        "type"
      ],
      "title": "SubEntity",
      "type": "object"
    },
    "Text": {
      "additionalProperties": false,
      "description": "A script snippet to insert into the startup script",
      "properties": {
        "type": {
          "const": "text",
          "default": "text",
          "title": "Type",
          "type": "string"
        },
        "when": {
          "default": "every",
          "description": "One of first / every / last",
          "title": "When",
          "type": "string"
        },
        "value": {
          "default": "",
          "description": "raw text to add to the startup script",
          "title": "Value",
          "type": "string"
        }
      },
      "title": "Text",
      "type": "object"
    },
    "When": {
      "enum": [
        "first",
        "every",
        "last"
      ],
      "title": "When",
      "type": "string"
    }
  },
  "additionalProperties": false,
  "description": "Lists the EntityModels for a support module, this defines what Entities it supports",
  "properties": {
    "shared": {
      "default": [],
      "description": "A place to create any anchors required for repeating YAML",
      "items": {},
      "title": "Shared",
      "type": "array"
    },
    "module": {
      "description": "Support module name, normally the repo name",
      "title": "Module",
      "type": "string"
    },
    "entity_models": {
      "description": "The Entity Models an IOC can create using this module",
      "items": {
        "$ref": "#/$defs/EntityModel"
      },
      "title": "Entity Models",
      "type": "array"
    }
  },
  "required": [
    "module",
    "entity_models"
  ],
  "title": "Support",
  "type": "object"
}

2. The generic-IOC entities schema — <container>.ibek.ioc.schema.json#

Validates an *.ibek.ioc.yaml instance file against the entity models built into a particular generic-IOC image. By convention it is named after the container, e.g. motorSim.ibek.ioc.schema.json. Produce it with:

ibek ioc generate-schema [DEFINITIONS...] [--output FILE] [--ibek-defs/--no-ibek-defs]
  • DEFINITIONS are paths to one or more *.ibek.support.yaml files.

  • By default (--ibek-defs) the command also adds every support file bundled in the image’s IBEK_DEFS directory, so the schema covers all built-in entities.

  • The schema is printed to stdout unless --output is given.

  • --no-ibek-defs with no DEFINITIONS is an error — there would be nothing to build a schema from.

This is the schema published as a GitHub release artifact alongside the generic-IOC image, so instance authors can validate against the exact entity set their image provides.

tests/samples/schemas/motorSim.ibek.ioc.schema.json
{
  "$defs": {
    "DIR": {
      "enum": [
        "Pos",
        "Neg"
      ],
      "title": "DIR",
      "type": "string"
    },
    "RepeatEntity": {
      "additionalProperties": false,
      "description": "A definition of RepeatEntity for the type checker\n\nThis is not really used - instead the dynamic class is created\nby the make_entity_model function is used.",
      "properties": {
        "type": {
          "const": "ibek.repeat",
          "default": "ibek.repeat",
          "title": "Type",
          "type": "string"
        },
        "entity_enabled": {
          "default": true,
          "description": "enable or disable this entity instance",
          "title": "Entity Enabled",
          "type": "boolean"
        },
        "values": {
          "anyOf": [
            {
              "items": {},
              "type": "array"
            },
            {
              "type": "string"
            }
          ],
          "description": "The list of values to iterate over",
          "title": "Values"
        },
        "variable": {
          "default": "index",
          "description": "The variable name to use in the entity model",
          "title": "Variable",
          "type": "string"
        },
        "entity": {
          "additionalProperties": true,
          "description": "The entity model to repeat",
          "title": "Entity",
          "type": "object"
        }
      },
      "required": [
        "values",
        "entity"
      ],
      "title": "RepeatEntity",
      "type": "object"
    },
    "Wait4IPEntity": {
      "additionalProperties": false,
      "description": "A definition of Wait4IPEntity for the type checker.\n\nThis is not really used - instead the dynamic class is created\nby the make_entity_models function is used.",
      "properties": {
        "type": {
          "const": "ibek.wait_ip",
          "default": "ibek.wait_ip",
          "title": "Type",
          "type": "string"
        },
        "entity_enabled": {
          "default": true,
          "description": "enable or disable this entity instance",
          "title": "Entity Enabled",
          "type": "boolean"
        },
        "device": {
          "default": "DEVICE",
          "description": "The device name to use in the database record.",
          "title": "Device",
          "type": "string"
        },
        "timeout": {
          "default": 0,
          "description": "The number of seconds to wait for a response before considering the communication attempt a failure and exiting the IOC startup process; this will trigger a restart of the IOC pod by Kubernetes.\nA value of 0 means to wait indefinitely until communication is established.",
          "title": "Timeout",
          "type": "integer"
        },
        "address": {
          "description": "The IP address and port to check communication with.",
          "title": "Address",
          "type": "string"
        }
      },
      "required": [
        "address"
      ],
      "title": "Wait4IPEntity",
      "type": "object"
    },
    "Wait4USBEntity": {
      "additionalProperties": false,
      "description": "A definition of Wait4USBEntity for the type checker.\n\nThis is not really used - instead the dynamic class created\nby the make_entity_models function is used.",
      "properties": {
        "type": {
          "const": "ibek.wait_usb",
          "default": "ibek.wait_usb",
          "title": "Type",
          "type": "string"
        },
        "entity_enabled": {
          "default": true,
          "description": "enable or disable this entity instance",
          "title": "Entity Enabled",
          "type": "boolean"
        },
        "device": {
          "default": "DEVICE",
          "description": "The device name to use in the database record.",
          "title": "Device",
          "type": "string"
        },
        "timeout": {
          "default": 0,
          "description": "The number of seconds to wait for a response before considering the communication attempt a failure and exiting the IOC startup process; this will trigger a restart of the IOC pod by Kubernetes.\nA value of 0 means to wait indefinitely until communication is established.",
          "title": "Timeout",
          "type": "integer"
        },
        "id": {
          "description": "The ID of the USB device to wait for. This should be in the format 'vendor_id:product_id', where vendor_id and product_id are the hexadecimal IDs of the USB device. For example, '1234:5678'.",
          "title": "Id",
          "type": "string"
        }
      },
      "required": [
        "id"
      ],
      "title": "Wait4USBEntity",
      "type": "object"
    },
    "asyn_AsynIP": {
      "additionalProperties": false,
      "properties": {
        "type": {
          "const": "asyn.AsynIP",
          "description": "Asyn IP Port",
          "title": "Type",
          "type": "string"
        },
        "entity_enabled": {
          "default": true,
          "description": "enable or disable this entity instance",
          "title": "Entity Enabled",
          "type": "boolean"
        },
        "port": {
          "description": "Serial port tty name / IP address optionally followed by protocol",
          "title": "Port",
          "type": "string"
        },
        "name": {
          "description": "Override name",
          "title": "Name",
          "type": "string"
        },
        "input_eos": {
          "default": "\"\\n\"",
          "description": "Input end of string (terminator)",
          "title": "Input Eos",
          "type": "string"
        },
        "output_eos": {
          "default": "\"\\n\"",
          "description": "Output end of string (terminator)",
          "title": "Output Eos",
          "type": "string"
        },
        "priority": {
          "anyOf": [
            {
              "description": "jinja that renders to <class 'int'>",
              "pattern": ".*\\{\\{.*\\}\\}.*",
              "type": "string"
            },
            {
              "description": "Priority",
              "type": "integer"
            }
          ],
          "default": 100,
          "description": "union of <class 'int'> and jinja representation of {typ}",
          "title": "Priority"
        },
        "noAuto_connect": {
          "anyOf": [
            {
              "description": "jinja that renders to <class 'bool'>",
              "pattern": ".*\\{\\{.*\\}\\}.*",
              "type": "string"
            },
            {
              "description": "Set to stop auto_connect",
              "type": "boolean"
            }
          ],
          "default": false,
          "description": "union of <class 'bool'> and jinja representation of {typ}",
          "title": "Noauto Connect"
        },
        "noProcessEos": {
          "anyOf": [
            {
              "description": "jinja that renders to <class 'bool'>",
              "pattern": ".*\\{\\{.*\\}\\}.*",
              "type": "string"
            },
            {
              "description": "Set to avoid processing end of string",
              "type": "boolean"
            }
          ],
          "default": false,
          "description": "union of <class 'bool'> and jinja representation of {typ}",
          "title": "Noprocesseos"
        },
        "baud": {
          "anyOf": [
            {
              "description": "jinja that renders to <class 'int'>",
              "pattern": ".*\\{\\{.*\\}\\}.*",
              "type": "string"
            },
            {
              "description": "Baud Rate",
              "type": "integer"
            }
          ],
          "default": 9600,
          "description": "union of <class 'int'> and jinja representation of {typ}",
          "title": "Baud"
        },
        "parity": {
          "$ref": "#/$defs/parity",
          "default": "none",
          "description": "Parity"
        },
        "crtscts": {
          "$ref": "#/$defs/crtscts",
          "default": "N",
          "description": "Set hardware flow control on"
        },
        "stop": {
          "$ref": "#/$defs/stop",
          "default": "1",
          "description": "Stop Bits"
        },
        "disconnectOnReadTimeout": {
          "$ref": "#/$defs/disconnectOnReadTimeout",
          "default": "Y",
          "description": "Disconnect when a read times out"
        },
        "bits": {
          "$ref": "#/$defs/bits",
          "default": "8",
          "description": "Bits"
        }
      },
      "required": [
        "type",
        "port",
        "name"
      ],
      "title": "asyn_AsynIP",
      "type": "object"
    },
    "bits": {
      "enum": [
        "8",
        "5",
        "7",
        "6"
      ],
      "title": "bits",
      "type": "string"
    },
    "crtscts": {
      "enum": [
        "Y",
        "N"
      ],
      "title": "crtscts",
      "type": "string"
    },
    "disconnectOnReadTimeout": {
      "enum": [
        "Y",
        "N"
      ],
      "title": "disconnectOnReadTimeout",
      "type": "string"
    },
    "motorSim_simMotorAxis": {
      "additionalProperties": false,
      "properties": {
        "type": {
          "const": "motorSim.simMotorAxis",
          "description": "Creates a simulation motor axis",
          "title": "Type",
          "type": "string"
        },
        "entity_enabled": {
          "default": true,
          "description": "enable or disable this entity instance",
          "title": "Entity Enabled",
          "type": "boolean"
        },
        "controller": {
          "description": "a reference to the motion controller",
          "title": "Controller"
        },
        "M": {
          "description": "PV suffix for the motor record",
          "title": "M",
          "type": "string"
        },
        "ADDR": {
          "anyOf": [
            {
              "description": "jinja that renders to <class 'int'>",
              "pattern": ".*\\{\\{.*\\}\\}.*",
              "type": "string"
            },
            {
              "description": "The axis number (allowed to be from 0 to controller.numAxes-1)",
              "type": "integer"
            }
          ],
          "description": "union of <class 'int'> and jinja representation of {typ}",
          "title": "Addr"
        },
        "DESC": {
          "default": "Motor {{ADDR}}",
          "description": "The description of the axis",
          "title": "Desc",
          "type": "string"
        },
        "DLLM": {
          "anyOf": [
            {
              "description": "jinja that renders to <class 'int'>",
              "pattern": ".*\\{\\{.*\\}\\}.*",
              "type": "string"
            },
            {
              "description": "The low limit of the axis (in counts)",
              "type": "integer"
            }
          ],
          "default": -20000,
          "description": "union of <class 'int'> and jinja representation of {typ}",
          "title": "Dllm"
        },
        "DHLM": {
          "anyOf": [
            {
              "description": "jinja that renders to <class 'int'>",
              "pattern": ".*\\{\\{.*\\}\\}.*",
              "type": "string"
            },
            {
              "description": "The high limit of the axis (in counts)",
              "type": "integer"
            }
          ],
          "default": 20000,
          "description": "union of <class 'int'> and jinja representation of {typ}",
          "title": "Dhlm"
        },
        "home": {
          "anyOf": [
            {
              "description": "jinja that renders to <class 'int'>",
              "pattern": ".*\\{\\{.*\\}\\}.*",
              "type": "string"
            },
            {
              "description": "The home position of the axis (in counts)",
              "type": "integer"
            }
          ],
          "default": 0,
          "description": "union of <class 'int'> and jinja representation of {typ}",
          "title": "Home"
        },
        "start": {
          "default": "{{home}}",
          "description": "The starting position of the axis (in counts)",
          "title": "Start",
          "type": "string"
        },
        "DIR": {
          "$ref": "#/$defs/DIR",
          "default": 0,
          "description": "The direction of the axis"
        },
        "VELO": {
          "anyOf": [
            {
              "description": "jinja that renders to <class 'float'>",
              "pattern": ".*\\{\\{.*\\}\\}.*",
              "type": "string"
            },
            {
              "description": "The velocity of the axis (in counts/sec)",
              "type": "number"
            }
          ],
          "default": 10.0,
          "description": "union of <class 'float'> and jinja representation of {typ}",
          "title": "Velo"
        },
        "VMAX": {
          "default": "{{VELO}}",
          "description": "The maximum velocity of the axis (in counts/sec)",
          "title": "Vmax",
          "type": "string"
        },
        "is_cs": {
          "anyOf": [
            {
              "description": "jinja that renders to <class 'bool'>",
              "pattern": ".*\\{\\{.*\\}\\}.*",
              "type": "string"
            },
            {
              "description": "Set to True if this axis a coordinate system axis",
              "type": "boolean"
            }
          ],
          "default": false,
          "description": "union of <class 'bool'> and jinja representation of {typ}",
          "title": "Is Cs"
        },
        "CS_NUM": {
          "anyOf": [
            {
              "description": "jinja that renders to <class 'int'>",
              "pattern": ".*\\{\\{.*\\}\\}.*",
              "type": "string"
            },
            {
              "description": "The coordinate system number for this axis",
              "type": "integer"
            }
          ],
          "default": 0,
          "description": "union of <class 'int'> and jinja representation of {typ}",
          "title": "Cs Num"
        }
      },
      "required": [
        "type",
        "controller",
        "M",
        "ADDR"
      ],
      "title": "motorSim_simMotorAxis",
      "type": "object"
    },
    "motorSim_simMotorController": {
      "additionalProperties": false,
      "properties": {
        "type": {
          "const": "motorSim.simMotorController",
          "description": "Creates a simulation motion controller",
          "title": "Type",
          "type": "string"
        },
        "entity_enabled": {
          "default": true,
          "description": "enable or disable this entity instance",
          "title": "Entity Enabled",
          "type": "boolean"
        },
        "controllerName": {
          "description": "The name of the controller and its Asyn Port Name",
          "title": "Controllername",
          "type": "string"
        },
        "P": {
          "description": "Device PV Prefix",
          "title": "P",
          "type": "string"
        },
        "numAxes": {
          "anyOf": [
            {
              "description": "jinja that renders to <class 'int'>",
              "pattern": ".*\\{\\{.*\\}\\}.*",
              "type": "string"
            },
            {
              "description": "The number of axes to create",
              "type": "integer"
            }
          ],
          "description": "union of <class 'int'> and jinja representation of {typ}",
          "title": "Numaxes"
        },
        "port": {
          "description": "a reference to the asyn port for communication with the controller",
          "title": "Port"
        },
        "DESC": {
          "default": "Simulated Motion Controller testing escaping: {% raw %} {{enclosed in escaped curly braces}} {% endraw %}",
          "description": "The description of the controller",
          "title": "Desc",
          "type": "string"
        }
      },
      "required": [
        "type",
        "controllerName",
        "P",
        "numAxes",
        "port"
      ],
      "title": "motorSim_simMotorController",
      "type": "object"
    },
    "parity": {
      "enum": [
        "even",
        "none",
        "odd"
      ],
      "title": "parity",
      "type": "string"
    },
    "stop": {
      "enum": [
        "one",
        "two"
      ],
      "title": "stop",
      "type": "string"
    }
  },
  "additionalProperties": false,
  "properties": {
    "ioc_name": {
      "description": "Name of IOC instance",
      "title": "Ioc Name",
      "type": "string"
    },
    "description": {
      "description": "Description of what the IOC does",
      "title": "Description",
      "type": "string"
    },
    "entities": {
      "description": "List of entities this IOC instantiates",
      "items": {
        "discriminator": {
          "mapping": {
            "asyn.AsynIP": "#/$defs/asyn_AsynIP",
            "ibek.repeat": "#/$defs/RepeatEntity",
            "ibek.wait_ip": "#/$defs/Wait4IPEntity",
            "ibek.wait_usb": "#/$defs/Wait4USBEntity",
            "motorSim.simMotorAxis": "#/$defs/motorSim_simMotorAxis",
            "motorSim.simMotorController": "#/$defs/motorSim_simMotorController"
          },
          "propertyName": "type"
        },
        "oneOf": [
          {
            "$ref": "#/$defs/asyn_AsynIP"
          },
          {
            "$ref": "#/$defs/motorSim_simMotorController"
          },
          {
            "$ref": "#/$defs/motorSim_simMotorAxis"
          },
          {
            "$ref": "#/$defs/RepeatEntity"
          },
          {
            "$ref": "#/$defs/Wait4IPEntity"
          },
          {
            "$ref": "#/$defs/Wait4USBEntity"
          }
        ]
      },
      "title": "Entities",
      "type": "array"
    },
    "shared": {
      "default": [],
      "description": "A place to create any anchors required for repeating YAML",
      "items": {},
      "title": "Shared",
      "type": "array"
    }
  },
  "required": [
    "ioc_name",
    "description",
    "entities"
  ],
  "title": "NewIOC",
  "type": "object"
}

3. The per-instance schema — ioc.schema.json#

A self-contained schema for a single IOC instance, named ioc.schema.json (the value of IOC_SCHEMA_NAME). It merges schema (2) — fetched as the published base schema for the image pinned by the instance — with the entity models from the instance’s own vendored / local support files. Produce it with:

ibek pattern schema [INSTANCE]

This writes ioc.schema.json at the instance root and rewrites the instance’s config/ioc.yaml header to # yaml-language-server: $schema=../ioc.schema.json, so the editor validates against the merged result. See Vendor runtime-support patterns into a services repo for the ibek pattern workflow.