Know the current state.
A dashboard reads the latest value for CNC-01 from the cache. The timestamp tells you when that value was observed.
Read current values →FN-UNS / THE REFERENCE IMPLEMENTATION
fn-uns is a working implementation of a Unified Namespace. It collects machine signals, keeps production history, and makes the results available to dashboards and other applications. Start with simulated machines, then adapt it to your factory.
FROM SIGNAL TO RECORD
A machine publishes a state change. The pipeline keeps its latest value and records when the change happened. Dashboards, engineering tools, and analysis can work from the same machine identity and timestamps.
A dashboard reads the latest value for CNC-01 from the cache. The timestamp tells you when that value was observed.
Read current values →Keep the original signals, state transitions, and operator entries. Follow a change back to its machine and time.
Store the signal history →Select a machine and time window. Supply the relevant history and notes to the model alongside the question.
Follow an example below ↓03 / ANALYSIS
A current state tells you what a machine is doing. History and operator notes explain the sequence around it. Here is what that context can look like for one question.
Worked example · Synthetic records and an illustrative response
ACTIVE → IDLE
CNC-01 stops running.“Tool change in progress.”
An operator records a note for CNC-01.IDLE → ACTIVE
CNC-01 resumes running.THE QUESTION
EXAMPLE RESPONSE
CNC-01 was idle from 10:14 to 10:32, a period of 18 minutes. 1 3
At 10:16, an operator recorded “Tool change in progress.” 2
The timestamps establish the duration. The operator supplies the note. The model can bring those facts together in a readable account.
Use the same machine name across signals, history, and manual entries.
Select a time window and calculate durations from the stored records.
Include the relevant events and notes with the question sent to the model.
Data flows through three stages. Each stage is independent and composable — built from small functions that do one thing well.
Machines publish status, program, and tool data to MQTT every 3 seconds. The framework subscribes to the entire namespace and caches every message in Valkey — current value and previous value, for change detection.
HTTP functions poll the cache, detect changes, and write structured records to PostgreSQL — state durations, stoppage classifications, production runs, and operator input.
KPI functions query all PostgreSQL tables and compute manufacturing metrics on demand — utilisation, availability, throughput, MTBF, MTTR, and stoppage pareto.
All functions run as Containers on a shared network. External access goes through Caddy (automatic TLS) → fnkit-gateway (auth, routing, rate limiting). Internal communication happens directly between containers. Deployed via git push using fnkit's GitOps workflow.
Each function is a standard Go or Node.js program — its own container, its own repo, its own deploy lifecycle. They compose through shared infrastructure, not through each other.
These are the core pipeline components. The full reference covers all 12, including the historian, dashboards, and optional AI analysis.
RUNNING THE SOFTWARE
The implementation keeps processing logic in code and runs components in containers. This gives an engineering team control over changes, while leaving them responsible for deployment, monitoring, backups, and data quality.
For the team writing and deploying processing logic: topic structure, messaging, containers, and a code example.
Three ideas come together: an ISA-95 topic hierarchy gives every data point a canonical address, lightweight functions process the data, and MQTT connects everything in real time.
All data is organised using the ISA-95 international standard — a structured path from enterprise down to individual data points. The hierarchy is self-describing: any consumer can parse the topic path to understand where data comes from without mapping tables or documentation.
MQTT decouples producers from consumers. Machines publish to topics, applications subscribe to what they need. The broker handles delivery. Adding a new machine means publishing to a new topic — the entire pipeline picks it up automatically.
Each piece of logic is a small, independent function — Go or Node.js. No monolithic platform, no flow builder. Functions read from a shared cache, write to PostgreSQL, and compose through infrastructure rather than through each other.
Every function is version controlled. Deploy with
git push. Roll back with
git revert. Full audit trail, code review, and CI/CD — the same workflow
your software team already uses.
The data flow: Machines publish → MQTT broker distributes → Functions cache in Valkey → Functions detect changes and write to PostgreSQL → KPI functions query and compute on demand.
The deploy flow: Write code → git commit → git push → fnkit builds container → running in production. No manual server management, no UI configuration.
No drag-and-drop flow builders. No visual wiring. No opaque configuration UIs. Just code that any developer can read, review, and extend.
// Read current + previous for every topic const pipe = rdb.pipeline() for (const topic of topics) { pipe.get(`uns:data:${topic}`) pipe.get(`uns:prev:${topic}`) } const results = await pipe.exec() // Did the value change? const changed = current !== previous
The cache stores two versions of every topic — current and
previous. A single pipelined read returns both, plus metadata. The
changed
flag tells downstream functions whether to act.
This is the pattern that powers the entire pipeline. State tracking, stoppage classification, production logging — they all read from this cache and only write to PostgreSQL when something actually changes.
Standard Node.js. Standard Redis commands. No proprietary SDK, no vendor abstraction layer.
TRY FN-UNS
The quick start brings up the simulator, topic monitor, and cache API. You will see machine values in JSON. The deployment guide then adds stored production records and metrics.