Files
2026-03-17 13:23:56 -05:00

5.9 KiB

Ignition Project Structure — CLAUDE.md

Parent: ../CLAUDE.md

Overview

Ignition 8.3 with Git-native project storage. The project directory is mounted into the Ignition Docker container and is the single source of truth. All resources are JSON files on disk.

Git-Native Project Storage

Ignition 8.3 stores projects as files and directories:

ignition/project/
├── project.json                                  ← project metadata
├── com.inductiveautomation.perspective/
│   ├── views/
│   │   └── <view-name>/
│   │       ├── view.json                         ← view definition
│   │       └── resource.json                     ← resource metadata
│   └── page-config/
├── com.inductiveautomation.webdev/
│   └── <endpoint-name>/
│       ├── code.py                               ← Jython 2.7 handler
│       └── resource.json
└── ignition/
    ├── named-query/
    │   └── <query-name>/
    │       ├── query.sql
    │       └── resource.json
    ├── script-python/
    │   └── <package>/
    │       ├── code.py                           ← project library scripts
    │       └── resource.json
    └── global-props/
        └── props.json

JSON File Rules

All JSON files in the project directory:

  1. Must be valid JSON — validate before writing (use json.loads() then write).
  2. Must use sorted keysjson.dumps(data, sort_keys=True, indent=2)
  3. Must be backed up before overwriting — cp file.json file.json.bak
  4. Must use 2-space indentation — matches Ignition's native format.

resource.json Template

Every resource directory contains a resource.json:

{
  "props": {
    "resource.name": "<resource-name>"
  },
  "scope": "G",
  "version": 1
}
  • scope: "G" = gateway, "C" = client, "A" = all
  • version: increment on changes for cache-busting

UDT / Linking Pattern

Structure

[Device Type UDT]
├── Config/
│   ├── DeviceType      (String)
│   ├── DeviceId        (String)
│   └── Description     (String)
├── Status/
│   ├── Running         (Boolean)
│   ├── Faulted         (Boolean)
│   └── ...
├── Command/
│   ├── Start           (Boolean)
│   ├── Stop            (Boolean)
│   └── ...
└── Linking/
    └── Link/
        ├── LinkPath    (String) ← path to PLC tag
        └── LinkData    (Dataset/Document) ← signal mapping

How LinkPath Works

LinkPath contains the OPC tag path prefix for the PLC signals. Example: [ControlLogix]Program:MainProgram.P_101

LinkData maps UDT members to PLC tag suffixes:

  • Status/RunningLinkPath + ".Sts_Running"
  • Command/StartLinkPath + ".Cmd_Start"

This decouples the test/simulation layer from specific PLC I/O structures. Changing the PLC program only requires updating LinkPath and LinkData.

Rules

  • Never modify LinkPath or LinkData at runtime from external tools.
  • Set linking configuration through Ignition Designer or startup scripts.
  • Test scenarios reference device UDT paths, not raw PLC tag paths.

Scripting

Jython 2.7 Constraints

All scripts in ignition/project/ run Jython 2.7. Violating these causes runtime errors:

  • NO f-strings → use "text {}".format(val) or "text %s" % val
  • NO walrus operator :=
  • NO pathlib → use os.path
  • NO type hints → no def foo(x: int) -> str:
  • NO dataclasses, enum.auto(), asyncio
  • NO dictionary unpacking {**d1, **d2} → use d1.update(d2)
  • NO yield from → use explicit loops
  • Imports: system.* for Ignition API, standard Java/Jython libs only

Project Library Scripts (script-python/)

Jython 2.7 — see root CLAUDE.md for language constraints.

Naming convention:

script-python/
├── testing/
│   ├── code.py          ← testing.runScenario(), testing.validateResults()
│   └── resource.json
├── devices/
│   ├── code.py          ← devices.getStatus(), devices.sendCommand()
│   └── resource.json
└── util/
    ├── code.py          ← util.formatTag(), util.validateJson()
    └── resource.json

Access in Ignition: project.testing.runScenario()

Gateway Event Scripts

Located in project config, not in script-python/. Used for startup initialization, tag change events, scheduled tasks.

Common Ignition API Calls

# Tag operations
system.tag.readBlocking(["path/to/tag"])
system.tag.writeBlocking(["path/to/tag"], [value])
system.tag.browseConfiguration("path", {})

# Named queries
system.db.runNamedQuery("queryName", {"param": value})

# WebDev (inside endpoint handlers)
# request object has: data, params, headers, remoteAddr
# return dict or string — Ignition serializes to JSON

# Logging
logger = system.util.getLogger("testing")
logger.info("message")

Tag Provider Structure

[default]
├── _types_/                    ← UDT definitions
│   ├── Devices/
│   │   ├── Motor/
│   │   ├── Valve/
│   │   └── Pump/
│   └── Linking/
│       └── Link/
├── Devices/                    ← UDT instances
│   ├── Pumps/
│   │   ├── P-101/
│   │   └── P-102/
│   ├── Valves/
│   │   └── XV-1001/
│   └── Motors/
│       └── M-201/
└── System/                     ← system/status tags
    ├── Health/
    └── Config/

Perspective Views

Views are JSON definitions in com.inductiveautomation.perspective/views/. Each view folder contains view.json (component tree) and resource.json.

Rules:

  • Do not hand-edit view.json unless you understand the component schema.
  • Prefer creating views through Ignition Designer when possible.
  • If editing programmatically, validate the full JSON structure before writing.