FIG. 3 — Raw PLC tags to a Unified Namespace, with LLMs in the loop
UNSHelper
A visual, node-based pipeline builder that puts language models to work on the hardest manual step in any Industry 4.0 program: deciding what every tag in every PLC actually represents. It ingests real Rockwell/Allen-Bradley exports, classifies equipment, generates descriptions, and proposes the namespace hierarchy.
- Status
- Working prototype · 834 commits
- Context
- 2026 · Independent work
- Role
- Sole designer & engineer
- Code
- Private — on request

2,903 tags from a real controller export, mid-enrichment: LLM equipment classification, area assignment, and generated descriptions per tag, with the namespace hierarchy under construction on the right — and the running API spend in the corner.
The problem
A Unified Namespace is the organizing idea behind most modern industrial data architectures — one coherent, hierarchical, self-describing view of everything a plant knows about itself. Getting there requires deciding what every tag in every controller means.
The raw material is a legacy L5K export with thousands of tags whose names are abbreviations invented by whoever commissioned the skid, sometimes decades ago. Classifying them by hand is the work that quietly stalls UNS programs: the job is enormous, it's tedious, and it needs exactly the domain knowledge that's scarcest on the team.
For a language model, though, it's close to an ideal task: pattern recognition over short, dense, domain-specific strings, where a knowledgeable engineer can verify an answer in seconds but would need hours to produce one.
How it works
- 01
Fourteen node types on a canvas
DataSource, Model, Swarm and JSwarm for per-item calls, Transform, Clean, Route, Partition, GroupByPattern, PredicateRouter, Downsample, ForEach, Merge, Reduce, Output — wired together on a drag-and-drop canvas and serialized to portable pipeline files. It's visual because the person who knows what a tag means is a process or controls engineer, and the tool has to meet them where they work.
- 02
Straight from the controller export
An L5K parser ingests real Rockwell/Allen-Bradley exports, expanding UDT and AOI tag members so nested structures resolve into the individual points they represent. A real site can hand you an L5K file; it usually can't hand you a clean tag spreadsheet, so the raw export had to be the starting point.
- 03
Structured output enforced per provider
Zod schemas define what the model must return, and each provider enforces them differently: Azure OpenAI in strict JSON-schema mode, OpenRouter in json_object mode, local LM Studio and Ollama through prompt instruction plus markdown-fence stripping. One environment variable switches the whole pipeline between cloud and fully local inference, which is what makes it usable inside an OT security boundary.
- 04
Deterministic work between the model calls
Transform, Clean, Route, and Partition nodes do the reshaping between inference steps, and a character-budget batching system keeps prompts inside context limits. Every step that can be deterministic is deterministic; the model only gets the parts that need judgment.
- 05
The content-filter problem
Azure's safety filter trips on legitimate industrial hazard and alarm terminology — the vocabulary of a plant's most important tags reads, out of context, like something to block. The fix is a single targeted retry with an injected safety preamble. A blind retry loop would have worked too, but it would bury genuine filter events, and I wanted those visible.
Plates

One tag up close: the raw name, the empty description field it shipped with, and what the model inferred — with the classification reasoning exposed so the engineer can judge it in seconds.

Site knowledge as data: 458 unit/area insights that ground the model's descriptions in what the equipment actually is. Editing one re-runs only the affected tags.
General note
The model does the tedious pass; the engineer does the judging. Any design that flips that ordering fails on contact with a real plant.
Why it matters
It goes after the specific bottleneck that stalls real Unified Namespace programs — the manual classification pass — and leaves the already-tractable parts alone.
The local-inference path means the tool can run entirely inside an OT security boundary, which is a precondition for touching production controller data at all.
The content-filter behavior only shows up when you point a real model at real industrial data. I've never seen it mentioned in a tutorial.
The engineer stays in the verification seat the whole way through.
Stack
- Frontend
- React 18ViteReact FlowZustandTailwind
- Backend
- TypeScriptExpress 5Node.jsZod
- AI providers
- Azure OpenAIOpenRouterLM StudioOllamagpt-tokenizer
- Industrial
- Rockwell L5K parserUDT / AOI expansion
- Infrastructure
- TerraformAzureVitest
Want the architecture in more depth, or a walk through the code? I'm glad to go there.
Get in touch