A headless-first, LLM-native toolkit for IEC 61131-3 PLC programming.
Compile, validate, and manage Structured Text programs from the terminal or through an LLM agent. No GUI required.
Industrial automation is stuck in vendor silos. Siemens TIA Portal, Rockwell Studio 5000, CODESYS — each locks you into a proprietary IDE with no CLI, no API, and no way for an LLM to interact with the toolchain.
Meanwhile, LLMs can write decent Structured Text but have no way to compile or validate it. Without compiler feedback, they get it right about 27% of the time. With structured feedback in a loop, that jumps to 90%+.
plc-toolkit is the missing layer: a universal, headless PLC toolkit that connects LLM agents to real compilation, reads any vendor's code, and treats the terminal as a first-class citizen.
| Tool | Problem |
|---|---|
| CODESYS | Proprietary, expensive, Windows-only, no CLI |
| Siemens TIA Portal | Proprietary, thousands of dollars, no programmatic access |
| Rockwell Studio 5000 | Same story |
| OpenPLC Editor | Open source but GUI-only, no CLI, no LLM integration |
| Beremiz | Same — GUI-only |
| MatIEC | C compiler, but outputs unstructured text, no library API |
- Headless-first — the core is a library and CLI, not an app. GUIs are consumers, not the product.
- LLM-native — every error is structured JSON with a fix suggestion. The MCP server makes PLC tools callable by any AI agent.
- Compiler-in-the-loop — the killer feature. LLMs iterate against real compiler output until the code compiles.
- Vendor-neutral — parse PLCopen XML, Rockwell L5X, Siemens SimaticML into one common AST. Convert between them. (Roadmap)
- Native compilation — RuSTy compiles ST to LLVM IR, then to native machine code for x86, ARM, RISC-V, WASM, or ESP32. No C toolchain needed.
# Enter the dev environment (requires Nix)
cd plc-toolkit && nix develop
# Compile a Structured Text file — outputs JSON with diagnostics or LLVM IR
cargo run -- compile examples/counter.st
# Validate without generating output
cargo run -- validate examples/counter.st{
"success": true,
"diagnostics": [],
"ir": "; ModuleID = '<internal>'\n..."
}{
"success": false,
"diagnostics": [
{
"severity": "error",
"message": "Unknown type: TON",
"suggestion": "Check spelling of the type name. Standard types: BOOL, INT, DINT, REAL, LREAL, STRING, TIME"
}
]
}Every diagnostic includes a suggestion field when possible — designed for LLMs to act on directly.
LLVM IR (Intermediate Representation) is the universal assembly language of the LLVM compiler framework. When plc-toolkit compiles your Structured Text:
ST source → RuSTy parser → AST → LLVM IR → native machine code
LLVM IR is the pivot point. From there, LLVM can generate native binaries for any supported target:
- x86-64 — standard PCs and industrial controllers
- ARM — Raspberry Pi, embedded PLCs
- RISC-V — next-generation embedded
- WASM — run PLC logic in a browser
- ESP32 / AVR — microcontrollers
This is a step change from the old MatIEC approach (ST → C → gcc → binary), which required a C toolchain on every target and produced unstructured error output.
plc compile <file.st> Compile ST, output JSON diagnostics + LLVM IR
plc compile <file.st> -o out.ll Write LLVM IR to file
plc validate <file.st> Validate without generating output
Exit codes: 0 success, 1 compile/validation error, 2 internal error.
plc-toolkit/
Cargo.toml Workspace root
crates/
plc-toolkit-core/ Core library — RuSTy integration, structured diagnostics
plc-toolkit-cli/ CLI — plc compile, plc validate
plc-toolkit-mcp/ MCP server for LLM agents (coming soon)
examples/
counter.st Simple counter program
blink.st Toggle output on timer (uses TON function block)
motor_control.st Industrial motor start/stop with interlocks
Requires Nix (for reproducible LLVM 21 + Rust environment):
git clone https://github.com/Adjoint-uk/plc-toolkit.git
cd plc-toolkit
nix develop
cargo build
cargo testOr bring your own Rust toolchain + LLVM 21:
export LLVM_SYS_211_PREFIX=/path/to/llvm-21
cargo buildplc-toolkit uses RuSTy as its compiler backend — an open-source IEC 61131-3 Structured Text compiler written in Rust that targets LLVM. We call RuSTy as a library (not a subprocess), which gives us:
- Native structured diagnostics (no regex parsing)
- Direct AST access for future LSP/IDE features
- Single binary distribution
- All LLVM compilation targets
| Phase | What | Status |
|---|---|---|
| 1 | TypeScript prototype (proof of concept) | Complete — tagged v0.1.0-typescript-prototype |
| 1b | Rust reboot with RuSTy backend | MVP complete |
| 2 | Language intelligence — ST Language Server (LSP) | Planned |
| 3 | Multi-vendor import — Rockwell L5X, Siemens SimaticML, CODESYS | Planned |
| 4 | LLM agent workflows — compiler-in-the-loop, RAG over IEC 61131-3 | Planned |
| 5 | Web IDE — Monaco editor, visual FBD/LD viewer, OPC-UA deploy | Planned |
See PLAN.md for the full architecture and design rationale.
See the Getting Started guide for a walkthrough — write a traffic light controller, compile it, see the errors, understand the output.
See CONTRIBUTING.md.
LGPL-3.0-or-later (matching RuSTy)