Koios v1.1.0

The first minor release on top of the v1.0 line. This release focuses on the canvas and AI model experience: calibrate bindings without retraining, deploy flat (rank-2) models alongside time-series models, and wire components against any live entity — not just tags. The canvas itself gets per-instance pin layouts, custom wire routing, and end-to-end type validation that paints invalid connections red before save.

AI Models

Gain and Bias Calibration

Every model binding now has dedicated gain and bias fields for linear calibration. Apply a slope-intercept transform directly on a binding — useful for correcting sensor drift, converting engineering units, or fine-tuning a model's response without retraining or redeploying the ONNX file.

Calibration applies in addition to the existing normalization settings and is evaluated last in the binding pipeline. Defaults are identity (gain=1.0, bias=0.0), so existing bindings see no change after upgrade.

See Assigning Bindings for the full configuration guide.

Support for Flat (Rank-2) Models

Koios now accepts both flat (rank-2) and time-series (rank-3) models from ONNX and TFLite. Flat models — scikit-learn classifiers, single-step reinforcement-learning policies, and other models that take one observation per inference — no longer require padding tricks or a fake time dimension.

  • Automatic shape detection — the platform reads the model graph at upload time and detects rank, input count, and observation depth. A checksum catches metadata drift before the model goes live.
  • Clearer shape labels — model lists and detail pages now show "5 inputs, depth 1" for a flat model versus "5 inputs, depth 6" for a time-series model.
  • Faster inference for flat models — the predict engine skips historical buffer queries and reads fresh values directly from the live cache, lowering scan-cycle latency at fast scan rates.

See Model Inference Requirements for shape details and Training a Model for export guidance.

Broader ONNX Compatibility

The platform's ONNX runtime was upgraded, raising the highest ONNX IR version Koios can load from 11 to 13 and adding support for newer operator sets (opsets). Files exported by recent versions of PyTorch, TensorFlow, or the onnx exporter — which v1.0.x rejected at upload for targeting a too-new IR version — now upload and run without re-exporting to an older format.

Upload validation runs against the same runtime used for inference, so any file Koios accepts at upload is guaranteed to load in the predict engine. Files above IR 13 are still rejected at upload with a clear message — re-export at a compatible IR version, or annotate the model with the Koios model-utils library, which clamps the IR version to a safe value automatically.

Live Prediction Cycle Visualization

The model spine in the navigation now shows a radial progress ring animated around the brain icon over the model's scan rate. The ring is anchored to the server clock, so it stays in sync with what the predict engine is actually doing — and pulses briefly each time a new prediction lands. This gives you an at-a-glance signal that a model is alive and on schedule.

Scan Rate and Sample Rate Linking

In the model configuration form, scan rate and sample rate are now linked when they match (the case for nearly every forecasting model). Edit one and the other follows. A chain toggle lets you unlink for controllers that need a faster execution cadence than their training data. The chain is automatically hidden when the model belongs to a scan group, since the group controls execution.

Tag-to-Binding Visibility

Tag detail pages now show every model binding that references the tag, with the model name, binding direction, and ordinal. Helpful when you're about to disable or delete a tag and need to know what depends on it.

Canvas and Components

Wire Anything, Not Just Tags

Component input connectors now read from any live entity in Koios — devices, AI models, model bindings, and scan groups — in addition to tags and component outputs. Each entity exposes a curated set of fields (e.g., a device exposes status, last-seen, error code; a model exposes its current prediction; a binding exposes the live value flowing through it). This lets you build components that react to system state, not just sensor data.

Each connector type only exposes fields that make sense for that entity, so you cannot wire incompatible data into a component input.

Per-Instance Pin Layouts

Pin order, gaps, and visibility are now configurable per instance — not just per component type. Open the pin layout editor from any instance to:

  • Drag pins to reorder them
  • Insert gaps for visual grouping
  • Hide pins that you don't need on this particular instance

Hidden pins are kept in a side tray and can be dragged back at any time. Layouts persist across canvas saves, environment clones, and copy/paste operations. The component definition still provides the default — overrides are layered on top.

Custom Wire Routing

Click any wire to reveal a midpoint handle, then drag perpendicular to de-stack parallel wires or reshape a route for readability. Double-click resets the wire to its default path. Routing is saved with the canvas and survives copy/paste.

Structured Type Validation

Wire validation has been rebuilt to give you immediate, specific feedback:

  • Invalid wires paint red with a tooltip explaining why (e.g., "string output cannot connect to numeric input")
  • Save errors are scoped — when a save fails, the offending instance, connector, or wire is highlighted directly on the canvas rather than buried in a generic error toast
  • The wire contract is now part of the GraphQL schema — the canvas, the engine, and the builder all consume the same coercion rules and source-field allowlists, eliminating cases where validation behaved differently in different surfaces

The same validation runs in the engine: if a malformed wire ever slips through, the affected instance enters an ERROR state with the offending pin called out in the diagnostics.

Pin Type Mismatch Detection

The component engine now detects pin-type mismatches at runtime and surfaces them in the UI. Wires that pass UI validation but produce a type mismatch downstream (e.g., an upstream component changes type after a library upgrade) put the instance into ERROR with a clear diagnostic rather than producing silently wrong outputs.

Live Output Publishing

Component instances now publish a tag-value notification on every successful output write, not just when the value changes. Downstream consumers — expression tags, AI bindings, history — react immediately to fresh values without falling back to a 10-second poll. This eliminates the workaround of setting EE_IN_MEMORY_SCAN_RATE=1 to get timely sampling on in-memory inputs.

Component Builder SDK v3

The Component Builder package gains a canonical pin layout API:

class MyComponent(Component):
    class Meta:
        inputs_layout = ["input_a", Gap(), "input_b", "input_c"]
        outputs_layout = ["primary", "secondary"]

This replaces the FieldDescriptor(order=...) convention, which is now deprecated. The SDK also gains a shared wire_contract module that lets custom components participate in the same type system the canvas and engine use.

See Building Components for the full API reference.

Reliability and Performance

No More Duplicate Toasts

The event relay that powers live UI notifications used to be started inside the web server's startup hook, which spawned one relay per worker process. The result was duplicate WebSocket frames and the same toast firing two or four times in a row. The relay now runs as a single dedicated process, so each event is delivered exactly once.

Out-of-Range Debounce No Longer Oscillates

Models with rate-of-change or range-check diagnostics could enter a sawtooth where the diagnostic flipped between triggered and recovered on every cycle. The debounce counter now stays triggered until a real recovery condition is observed, eliminating the noise.

Live IN_MEMORY Tag Relay

Expression tags and AI models that consume in-memory tags (component outputs, expression results, model predictions) now receive updates via direct event dispatch instead of polling. The previous 10-second polling fallback has been demoted to a 60-second heartbeat that exists purely as a safety net to detect stale producers. You can tune the heartbeat with the new EE_IN_MEMORY_HEARTBEAT_INTERVAL environment variable; the legacy EE_IN_MEMORY_SCAN_RATE is still honored for backward compatibility.

Stopped Service Alert

A persistent footer banner now appears when a critical platform service (predict engine, datacollector, expression evaluator, component engine) is stopped or failing. The banner is severity-aware — red when everything is down, amber when only some services are affected — and can be dismissed for the session.

Server Clock Anchoring

Live timers (prediction rings, "last updated" tickers) and chart x-axes now read from a server-anchored clock instead of the browser clock. Hosts with misaligned wall time no longer cause UI drift that makes charts look broken or live values appear stale.

Restore-Safe InfluxDB Lifecycle

InfluxDB bucket creation, renaming, and deletion now happen after the database transaction commits. This eliminates a class of race conditions where a model rename in one tab could land in InfluxDB before the database knew about it, producing orphaned buckets.

Security

Component Upload Hardening

.kcl (component library) uploads are now subject to additional safety checks:

  • 500 MiB upload cap enforced before the file is read into memory
  • Safe zip extraction rejects archives with path-traversal entries (zip slip) or malformed member names
  • AST analyzer in the Component Builder now catches dangerous calls made via attribute access (e.g., builtins.eval(...)) in addition to direct calls
  • Library name validation restricts names to lowercase letters, digits, hyphens, and underscores
  • data_files path validation prevents setup.py from packaging files outside the wheel directory

These checks apply to both uploaded libraries and the Component Builder CLI used by component authors.

UI Polish

  • Tab count badges — detail page tabs that own collections (bindings, instances, libraries) now show a neutral count badge on the right, with an optional red notification dot when items are in an issue state.
  • Canvas selection preservation — selection survives drag, arrow-key nudge, and other mutations. Arrow-key moves are now part of the undo history.
  • Add Models to Scan Group modal — fixed a double-toggle bug where clicking a row checkbox cancelled itself out.

Upgrading

To upgrade from v1.0.x to v1.1.0:

  1. Back up your data — use System > Backup, or follow Backing Up Docker Volumes.

  2. Pull the new image:

    docker pull aiopinc/koios:v1.1.0
  3. Restart the service:

    sudo systemctl restart docker.koios.service

The first startup runs additive schema migrations (gain/bias on bindings, input rank tracking, per-instance pin layouts). No service file or volume changes are required.

See Updating Koios for general upgrade guidance.

Service Manifest

ServiceNotable Change
WebappCalibration fields, multi-entity connectors, per-instance pin layouts, custom wire routing, wire contract API, structured canvas validation, dedicated event relay process
UICalibration controls, pin layout editor, wire routing, live prediction ring, scan/sample rate linking, stopped-service banner, server-clock anchoring, tab count badges
Predict engineRank-2 model graph support, fresh-value read path for flat models, per-cycle output publish, debounce fix, cleaner binding error diagnostics, upgraded ONNX runtime (loads IR 13 / newer opsets)
DatacollectorGeneric EtherNet/IP tag-grouping fix
Expression evaluatorEvent-driven IN_MEMORY relay, configurable heartbeat
Component enginePin type mismatch detection, multi-entity dispatch, thread-safety hardening
Component builderSDK v3 pin layout API, shared wire contract, expanded AST analyzer, name and path validation
UtilityCalibration schema, input rank, multi-entity connector enum, safe zip extraction helper
All othersUnchanged from v1.0.2