Component Builder SDK
koios-component-builder is the SDK and command-line tool for building
component libraries. A component is a reusable block of logic with typed
inputs and outputs that Koios wires together and executes at a configurable
scan rate.
This page is the author's reference. For using components once they are installed, see Components and The Component Canvas.
Installation
Requires Python 3.12 or newer.
Your first component
Group components into a library:
Then package it:
That writes a .kcl package into dist/, ready to upload. See
Component Libraries.
How a component runs
Each execution cycle does four things:
- Input and configuration values are set on the component
setup()runs, once, before the first executionexecute()runs with the current input values- Output values are sent wherever they are wired
You write setup() and execute(). Koios handles wiring and data flow.
Doing expensive work once
Override setup() for anything that should not repeat every cycle — loading a
model, building a registry, parsing configuration. Every field value is
available by the time it runs.
If setup() raises, the instance is marked failed and retried next cycle.
For something shared across every instance of a class rather than per instance, guard at class level instead:
Fields
Inputs and outputs
Supported types are float, int, bool, str, list, and dict.
Configuration
Configuration fields are set when an operator creates the instance and stay constant while it runs. They appear as controls on the component node.
Files
FileConfig gives the operator an upload control. At runtime your component
receives a handle, not a raw path, pointing at the file uploaded for that
instance. Each instance has its own file, and uploads are versioned, so an
operator can swap a model and revert.
Load the file in setup() rather than execute(). Koios re-runs setup()
after an operator replaces the file, so a swap takes effect without a restart.
required decides what happens when nothing is uploaded, so you never write
that check yourself:
The handle exposes path, name, suffix, size_bytes, content_type,
sha256, uploaded_at, and version, plus read_bytes(), read_text(),
open(), and exists(). Reading through the handle instead of the open
builtin keeps your component out of the security audit's file-I/O tier.
Koios enforces your constraints on the server, so the declaration holds no
matter what uploads the file. Extension is the reliable gate; MIME type only
filters the file dialog, since a browser can claim anything and .onnx is in
no MIME registry. max_bytes is optional — omit it and a platform ceiling
applies. A value above that ceiling is clamped to it, so a field can lower the
cap but never raise it. Files are never executed; they are handed to the
component that asked for them.
See Files for components.
Historical data
A HistoryInput reads recorded values from historical storage. It must be
wired to a history connector on the canvas.
The returned frame has timestamp and value columns.
Appearance
Icons take any Tabler icon name in kebab-case; constants include SUM,
CALCULATOR, CHART_LINE, GAUGE, THERMOMETER, FILTER, WAVE_SINE,
TOGGLE_LEFT, ALERT_TRIANGLE, and TRANSFORM. Categories include MATH,
STATISTICS, LOGIC, ANALYSIS, TRANSFORM, FILTER, CONTROL, and
MONITORING, and custom strings are accepted.
Arranging pins
Pins follow class-body order by default. Where grouping matters — setpoints
together, tuning constants together, status outputs apart — declare the
arrangement in Meta and insert gaps. It ships in the package, so every
instance starts from the same layout, and an operator can still adjust one
instance.
Gap(size=1) inserts a spacer measured in pin heights. Names are validated
when the class is created, so a typo raises on import rather than at runtime.
Pins you leave out of a layout are appended in declaration order, so adding a
pin does not force a layout edit.
Dependencies
A library can declare third-party packages. The builder resolves them against the platform manifest to work out what is already available.
Tools that are not Python packages
platform-packages lists Python distributions only. Some libraries shell out
to a solver instead, installed as a system package — those never appear in that
listing, and declaring them as a dependency will not work.
pyomo itself is not pre-installed, so declare it as a dependency. For a
solver that ships as a wheel and needs no system package, highspy bundles
like any other package and is generally faster on larger problems.
Building a stack bundle
A stack is a named, isolated set of packages that component environments can attach to. It exists for dependencies that conflict with the platform's own — a library capping a package below the version the platform ships, for example.
Wheels can be uploaded individually, or exported here as a single .kps
bundle:
Wheels are downloaded for the target platforms — linux amd64 and arm64 by default — never copied from your local environment, so a bundle built on a Mac installs on the server. Packages the platform already provides are pinned during resolution and then left out.
Every target platform must resolve. A package with no wheel for one
architecture fails the whole export rather than producing a bundle that
installs on one and silently claims both. Either pass --platform for the
architecture you deploy on, or pin the package to a version publishing wheels
for both. The same applies if the platforms resolve to different versions:
the manifest records one version per package, so the export names them and
stops.
Requirements files may include others with -r other.txt; other option lines
are rejected. Every export ends by listing what it withheld and why.
No Koios distribution is ever bundled — those are the packages the engine loads your components with, and a stack carrying its own copy replaces them at import time and the worker cannot start. Naming one in a requirements file stops the export.
Package format
Security audit
Every export runs a static analysis of your source and sorts what it finds into three tiers.
Denied are patterns with no legitimate use in a component: imports such as
os, subprocess, socket, threading, pickle, ctypes and sys; the
eval, exec, compile and __import__ builtins; and sandbox-escape
attributes like __subclasses__, __builtins__, __code__ and __globals__.
Reviewed are patterns that are often legitimate: pathlib, io and csv,
calls to open, and third-party packages outside the platform allow-list.
The audit exits 1 when anything is denied, which makes it usable as a build
step.
Custom policies
Overrides work in both directions: move something to a looser tier or a stricter one, and it is removed from any conflicting tier automatically.
If a component genuinely needs a flagged pattern — loading a model from disk in
setup(), say — prefer pathlib or io, which are reviewed rather than
denied. For the rare case that needs a denied import, --allow-unsafe still
produces the package, but the manifest records that the audit did not pass and
the library is marked accordingly when uploaded.
Command reference
Testing locally
Components run outside Koios, so you can exercise one directly:
