Skip to content

Latest commit

 

History

History
108 lines (82 loc) · 5.69 KB

File metadata and controls

108 lines (82 loc) · 5.69 KB

PLC Toolkit — Assessment & Strategic Pivot

Date: 2026-03-19 Status: Pivoting from TypeScript/MatIEC to Rust/RuSTy

Assessment Summary

Check Status
Provenance Original (Adjoint Ltd)
Visibility Private
Language TypeScript (pivoting to Rust)
Phase 1 Complete — CLI, MCP server, PLCopen XML parser, tests, CI
Phase 2+ Not started — this is where the pivot happens
Tag v0.1.0-typescript-prototype preserves the TS codebase

What We Built (TypeScript Prototype)

Phase 1 delivered a working proof-of-concept:

  • MatIEC wrapper (src/compiler/matiec.ts) — shells out to iec2c binary, regex-parses text output into structured JSON diagnostics with LLM fix suggestions
  • PLCopen XML parser (src/parsers/plcopen-xml.ts) — parses IEC 61131-10 project files into vendor-neutral types
  • MCP server — 5 tools: compile_st, validate_st, plc_project_read, plc_project_create, st_reference
  • CLI — plc compile, plc validate, plc parse, plc mcp with colour output
  • Tests — unit tests for compiler diagnostics, XML parsing, type system
  • CI — GitHub Actions: lint, test, build

This validated the concept: a headless, LLM-native PLC toolkit fills a real gap. Nobody else is building this.

Why Pivot to Rust

The core problem with TypeScript + MatIEC

The entire compiler integration (matiec.ts, 282 lines) is a wrapper that:

  1. Shells out to a C binary (iec2c)
  2. Regex-parses its unstructured text output
  3. Adds structured JSON and suggestions on top

This is fragile, slow, and creates a hard dependency on discovering and distributing a C binary. It cannot scale to Phase 2 (LSP, real-time diagnostics) where you need a proper parser and AST.

MatIEC vs RuSTy

Feature MatIEC RuSTy Verdict
ST compilation Yes (ST → C) Yes (ST → LLVM native) RuSTy — no C toolchain needed
Graphical languages (LD/FBD) Yes No Irrelevant — our toolkit is ST-first, LLMs can't do graphical
Structured diagnostics No (text output, we regex it) plc_diagnostics module RuSTy — native structured errors
Library usage No (shell out to binary) Yes (Rust crate) RuSTy — direct API
LLVM targets No (needs gcc on C output) x86, ARM, RISC-V, WASM, ESP32, AVR RuSTy massively better
License LGPL-3.0 LGPL-3.0 Same
Maturity Battle-tested but stagnant v0.2.0, active development Trade-off, but RuSTy is gaining
WASM compilation No Native Enables Phase 5 web IDE

MatIEC gives us nothing over RuSTy for our use case.

Strategic alignment with Adjoint

Factor Detail
Consistent stack Other Adjoint products (cross-control, digital-twin) are Rust
Library-first ethos Rust crate is cleaner than npm package wrapping a C binary
Single binary distribution plc compile as a static binary vs requiring Node.js 20+
No host pollution Rust binary + nix flake — no node_modules, no npm
WASM for web IDE Rust compiles to WASM natively — Phase 5 gets the same engine in-browser
LSP ecosystem tower-lsp is mature; many production LSPs are Rust (rust-analyzer, taplo)
Performance Parsing vendor XML at scale — Rust is dramatically faster

What carries forward

The vision, architecture, and plan are unchanged. The 5-phase roadmap, the competitive landscape analysis, the principles (headless-first, LLM-native, compiler-in-the-loop, vendor-neutral IR) — all still apply. What changes is the implementation language and the compiler backend.

Specifically:

  • PLAN.md — vision, principles, architecture diagrams, competitive landscape — all valid
  • README.md — the product description and MCP tool interface — still the target
  • examples/ — ST example files are language-agnostic
  • The MCP server tool interface (5 tools) — same API, different implementation

What gets replaced:

  • src/compiler/matiec.ts → RuSTy crate as the compiler backend
  • src/parsers/plcopen-xml.ts → Rust XML parsing (quick-xml or roxmltree)
  • src/cli/ → Rust CLI (clap)
  • src/mcp-server/ → Rust MCP server (rmcp crate) or thin TS shim
  • src/types/ → Rust type system
  • All npm/TypeScript toolchain → Cargo

The Pivot Plan

  1. Tag preserved: v0.1.0-typescript-prototype — the full TS codebase is accessible via git checkout v0.1.0-typescript-prototype forever
  2. Clean main for Rust: remove TS source, keep docs and examples, init Cargo workspace
  3. Build on RuSTy: use the rusty crate as the ST compiler backend
  4. Reimplement Phase 1 in Rust — CLI, MCP server, PLCopen XML parser, structured diagnostics
  5. Proceed to Phase 2 natively — ST parser (from RuSTy's AST), LSP via tower-lsp
  6. MCP server — either pure Rust (rmcp) or thin TS/Python shim calling the Rust binary

RuSTy — Key Resources

Open Questions

  1. RuSTy as a library vs fork? — Can we use RuSTy as a cargo dependency, or do we need to fork/vendor it for the level of integration we need?
  2. MCP server in Rust? — The rmcp crate exists but is less mature than the TS/Python MCP SDKs. May be worth a thin TS shim initially.
  3. PLCopen XML round-trip — RuSTy doesn't do PLCopen XML. We need our own parser/serializer. This is the same work regardless of language.
  4. Contribution back to RuSTy — If we build vendor-neutral AST and PLCopen XML support, this could be upstreamed.