Ioc Convert

Convert a builder XML IOC to ibek ioc.yaml, validate schema, generate runtime assets, and iterate until correct.

epics-containers 1 updated 1mo ago
Claude CodeGeneric
View source ↗
---
argument-hint: <path/to/IOC.xml> [<path/to/services-repo>]
description: Convert a builder XML IOC to ibek ioc.yaml, validate schema, generate runtime assets, and iterate until correct.
---

# IOC Convert and Validate Workflow

Convert builder XML `$1` to ibek `ioc.yaml` in the services repo `$2`, fix any
support YAML or converter issues, generate runtime assets, and verify `st.cmd`
and `ioc.subst` are correct.

This command uses **parallel subagents** for support YAML creation and error
fixing, to keep the main context small and speed up large IOCs.

---

## Phase 0 — Create isolated EPICS_ROOT (main agent)

Create a unique temporary directory for this agent's ibek state. This ensures
multiple `/ioc-convert` invocations can run in parallel without conflicting
over `/epics/runtime/`, `/epics/ibek-defs/`, or `/epics/ioc/`.

```bash
export EPICS_ROOT=$(mktemp -d /tmp/epics-ioc-convert-XXXXXX)

All subsequent ibek and ./update-schema commands in this session (and in subagent prompts) must have EPICS_ROOT set to this value.


Phase 1 — Setup and XML conversion (main agent)

1a. Resolve the services repo

Follow services-repo-resolution.md using $2 (if provided) or the IOC prefix from $1.

  • If INSTANCE_DIR already exists:
    • Check $INSTANCE_DIR/values.yaml — if it contains dev-c7:, this is a legacy IOC. Remove the entire folder (rm -rf $INSTANCE_DIR) and recreate it from .ioc_template (fall through to the "does not exist" case below).
    • Otherwise, if config/ioc.yaml is present: run git -C <services-repo> status — if ioc.yaml is modified or untracked, ensure it is committed or stashed before overwriting.
  • If INSTANCE_DIR does not exist:
    • If <services-repo>/services/.ioc_template/ exists: cp -r <services-repo>/services/.ioc_template/ $INSTANCE_DIR
    • Otherwise: mkdir -p $INSTANCE_DIR/config/

1b. Resolve support module paths

Read the _RELEASE file next to the XML following find-module-path.md. Record a module path table mapping module name → resolved path, e.g.:

ethercat → /dls_sw/prod/R3.14.12.7/support/ethercat/7-2
rackFan  → /dls_sw/prod/R3.14.12.7/support/rackFan/2-12

This table will be passed to subagents in Phases 2 and 4.

1c. Run the conversion

Derive a terse description of the device this IOC controls from the XML filename and its contents (e.g. "Geobrick 06", "Vacuum system", "Pilatus detector"). Keep it short — a few words, no full sentences.

uv run builder2ibek xml2yaml $1 --yaml $INSTANCE_DIR/config/ioc.yaml --description "<description>"

1d. Review ioc.yaml and fix converters

Read the generated ioc.yaml. Do not read large referenced files yet — that work is delegated to subagents in Phase 2.

Scan quickly for converter issues that must be fixed before support YAML work:

Spurious name: fields — follow the name parameter rules in support-yaml-rules.md. When in doubt, keep name: type: id. If a converter is needed, create src/builder2ibek/converters/<module>.py (auto-discovered, no registration).

Attributes needing transformation — values that need renaming, numeric transformation, or removal before ibek sees them. Add or update the converter rather than editing ioc.yaml by hand.

dlsPLC entities — read docs/reference/dlsplc-migration.md and check the "What requires manual attention" table. Every case listed there should be fixed by implementing or improving the relevant converter.

Converters that emit multiple entities — when a single XML element must produce more than one ibek entity, use entity.add_entity(extra) and entity.delete_me(). Critical: pass plain dict objects to add_entity(), never Entity(...).

Auto-substitution entities (auto_*) — entity types like module.auto_xxxx correspond to a database template xxxx.template in the db/ directory of the support module. These need a support YAML entity model with just parameters and a databases section — no pre_init or post_init.

XML template entities — some builder modules use XML template files (the entity class inherits from Xml in builder.py) that expand into many child entities from other modules. Examples: SR-VA.d2PumpCart, SR-VA.gaugeSet. These should not be expanded by a converter into individual child entities. Instead:

  1. Keep the single template entity in ioc.yaml with only the macro parameters (e.g. dom, plc_ip, ts_ip).
  2. Create a support YAML entity model that uses sub_entities to instantiate the child entities from the existing entity models of the other modules (ether_ip, asyn, dlsPLC, etc.), passing the macro parameters via Jinja2 templating. This re-uses the existing entity definitions rather than duplicating pre_init / databases logic.
  3. Do NOT create a converter that expands the XML — the support YAML handles everything.

To build the sub_entities list: read the XML template file from the module's etc/makeIocs/ directory, and for each non-commented child element, add a corresponding sub_entity entry using the existing entity type. Hardcoded values from the template become literal values in the sub_entity; macro references like $(dom) become {{ dom }} Jinja2 expressions.

ethercat IOCs — the ethercat support module requires migration to fastcs-catio and cannot be converted with a standard support YAML. If an IOC uses ethercat entities, emit a TODO stub in the ioc.yaml and report to the user that it needs manual migration. Do not attempt to create an ethercat support YAML.

After any converter change: re-run xml2yaml and repeat 1d until the ioc.yaml is clean of converter-fixable issues.

1e. Enumerate modules needing support YAMLs

Parse the final ioc.yaml. For each entity type `.<En ```

Maintain Ioc Convert?

Let people know it's listed here — add the badge (live metrics, light/dark aware) or a plain link to your README or docs.

[Ioc Convert on getagentictools](https://getagentictools.com/loops/epics-containers-ioc-convert-and-validate-workflow?ref=badge)