Scripting
QUBIQ exposes one API surface, system, in three execution contexts. The same call reads
identically in Python and JavaScript, so a script moves between contexts without being rewritten.
The three contexts
| Context | Language | Runs on | Use for |
|---|---|---|---|
| Pipeline Python | Python | The Python worker | Transformations inside a dataflow |
| Gateway scripts | Python | The gateway, server-side | Transactions, long work, anything a browser must not own |
| Client scripts | JavaScript | The operator's browser | Screen interaction, validation, UI logic |
Choosing
Two rules cover nearly every case:
- Anything transactional belongs on the gateway. A browser disconnect must not be able to strand an open transaction holding locks.
- Anything that must not be lost belongs in a pipeline. Pipeline writes are covered by store-and-forward; script writes are not.
The system API
| Namespace | Purpose |
|---|---|
system.tag | Read and write namespace tags |
system.db | SQL, named queries, stored procedures, transactions |
system.hist | Historian trend queries |
system.vars | Cross-pipeline shared variables |
system.files | Read and write files in the workspace uploads folder |
system.message | Push messages from the gateway down to browsers |
system.script | Run a Gateway entry point server-side (JavaScript only) |
Full signatures, per-method detail and worked examples: System API reference.
And context, in the browser
A browser script gets a second global, context — the view, its components, the live tag values
already on screen, the operator's session, and the shell around the view (panels, toasts, popovers).
The division is worth learning early: system.* crosses the wire and is permission-gated;
context.* does not and is not. A read of context.tag["..."] costs nothing because the screen
already has the value; await system.tag.read("...") is a round trip that asks the server.
The same code, both languages
result = system.tag.read("Line1/Filler/Motor1/Speed")
if result["quality"] == "Good" and result["value"] > 2800:
system.tag.write("Line1/Filler/Motor1/SpeedSetpoint", 2500)
const result = await system.tag.read("Line1/Filler/Motor1/Speed");
if (result.quality === "Good" && result.value > 2800) {
await system.tag.write("Line1/Filler/Motor1/SpeedSetpoint", 2500);
}
The method names are camelCase in both languages — deliberately, so a script reads the same wherever it runs.
Always check quality
r = system.tag.read("Line1/Tank1/Level")
if r["quality"] != "Good":
return None # do not act on an untrustworthy value
A Bad-quality read still returns a value — the last known one. Acting on it is how a dead sensor
drives a live process. This is the single most important habit in QUBIQ scripting.
Batch, do not loop
# ❌ N round trips
values = [system.tag.read(p) for p in paths]
# ✅ one
values = system.tag.readAll(paths)
The same applies to database work: one query returning many rows beats many queries returning one.
The sandbox
Scripts run in a restricted environment. The standard set (system, math, json, datetime) is
available; administrators can install additional Python packages, which land in a managed directory
on the worker's path.
The editor
The Python editor lints as you type, so syntax errors surface while you are writing rather than when the pipeline fires at 03:00.
The Problems panel New in 1.0.6 lists what the linter found — message, severity, rule id
and Ln 4, Col 7 — and clicking a row goes there. The footer used to show a bare count, which told
you there was a problem and then declined to say what; the only route to the actual fault was to
notice a squiggle somewhere in a scrolled file and hover it. Every editor's diagnostics arrive
through the same panel, whether they came from the Python linter, TypeScript or CSS.
One font size, everywhere. New in 1.0.6 The − / + control sets the size for every
code editor in the Designer — project scripts, event and binding scripts, named queries, CSS and
the pipeline node editor — and it persists, so turning it up to read a long script does not have to
be done again in the next panel. The AI chat and the assistant panel have their own, scoped to the
message text so the header and controls stay put.
Security
- Scripts run with the gateway's authority — a script can read any tag and any connection it names. Grant script-authoring permissions accordingly.
- Prefer named queries over string-built SQL. Where inline SQL is unavoidable, always parameterise.
- Do not put credentials in scripts or in variables. Use a connection's credential storage.
- Consequential actions are recorded in the audit journal.
In this section
| Page | Contents |
|---|---|
| System API reference | Every namespace, method and signature |
| Python nodes | Scripting inside a pipeline |
| Gateway scripts | Server-side entry points |
| Client scripts | Browser-side screen logic |
| The script sandbox | What is available, and how to extend it |