---
title: "Component Canvas"
description: "Add component instances, wire inputs and outputs, customize layouts, and monitor live execution on the visual canvas"
source_url: https://ai-ops.com/docs/components/canvas
---

# Component Canvas

The canvas is the visual editor where you build processing logic by placing component instances, connecting their inputs and outputs, and monitoring live execution. Open it from the **Canvas** tab on any environment detail page.

---

## Adding Instances

The **Library Tray** on the left side of the canvas lists all component types from the active library. To add a component:

1. Open the library tray (left sidebar)
2. Find the component type you want (components are organized by category)
3. Drag it onto the canvas

A new instance node appears with the component's default configuration. Each node shows:

- **Header** — component name and icon
- **Input pins** (left side) — fields that receive data
- **Output pins** (right side) — fields that produce data

You can drag nodes to reposition them on the canvas. Nodes snap to a grid for clean alignment.

---

## Configuring an Instance

Double-click a component instance (or right-click and select **Configure**) to open the configuration drawer. It has tabs for:

### Overview

- **Instance Name** — a custom name to identify this instance (e.g., "Room 3 Temp Avg")
- **Node Width** — adjust the visual width of the node on the canvas

### Configuration

Static settings defined by the component. These values don't change at runtime and control how the component behaves. Depending on the component, you may see:

- **Number fields** — with optional min/max bounds and step size
- **Text fields** — with optional validation patterns
- **Toggle switches** — for boolean settings
- **Dropdowns** — for predefined choices

### Wiring

Shows all input and output fields with their current wire connections and live values. Use this tab to see at a glance what data is flowing into and out of the instance.

### Pin Layout

Reorder pins, insert gaps, and hide pins you don't need on this instance. See [Per-Instance Pin Layouts](#per-instance-pin-layouts) below.

### Documentation

If the component type includes documentation, it is rendered here.

---

## Connectors

Connectors are the bridge between the canvas and the rest of Koios. They appear as square nodes on the canvas and come in seven types. Input connectors feed live data into a component; output connectors receive a component's result and write it somewhere.

| Connector | Direction | Source / Sink |
|---|---|---|
| **Tag** | Input or Output | A tag (live value, quality, timestamp, status, error code) |
| **History** | Input only | A tag's historical time-series data, queried on demand |
| **Device** | Input only | A device's live status (running, stopped, failed, error code, last seen) |
| **AI Model** | Input only | A model's live status and current prediction |
| **Binding** | Input only | The live value flowing through a specific model binding |
| **Scan Group** | Input only | A scan group's live status and timing metrics |
| **Component** | Input only | An output from a component instance in a different environment |

Each connector type only exposes the fields that make sense for it. For example, a Device connector lets you wire `status` or `error_code` into a component — but not `value`, because devices don't have one. The connector picker filters the available fields based on the entity you choose.

### Tag Connector

Reads from or writes to a tag.

- **Tag** — which tag to read from or write to
- **Field** — which tag field to use: `value`, `quality`, `timestamp`, `status`, or `error_code`

For **output** tag connectors, only writable tags (output usage) are listed.

### History Connector

Provides on-demand access to a tag's historical data. The connected component receives a history provider that can query the time-series database for trends, rolling statistics, or pattern detection.

- **Tag** — which tag's history to access

### Device, AI Model, Binding, Scan Group Connectors

Each of these reads a curated set of live fields from the named entity. Use them to build components that react to system state — for example, gate control logic on a device's status, or feed a model's current prediction into another component.

- **Entity** — pick the device, model, binding, or scan group
- **Field** — the connector picker shows only the fields valid for that entity

### Component Connector

Reads an output from a component instance in a **different** environment. Used for cross-environment composition — e.g. a fast control loop in one environment feeds a slower analytics environment.

- **Environment** — which environment contains the source component
- **Instance** — which component instance to read from
- **Output Field** — which output field to use

> [!NOTE] Same-environment wiring
> To connect two components in the **same** environment, draw a wire directly between their pins — you don't need a component connector. Component connectors are only needed for cross-environment connections.

---

## Wiring

Wires carry data between component pins and connectors. To create a wire:

1. Click on an output pin (right side of a component or an input connector)
2. Drag to an input pin (left side of a component or an output connector)
3. Release to create the wire

**Rules:**
- Each component input can have at most **one** incoming wire
- Each output connector can have at most **one** incoming wire
- Component outputs can fan out to multiple destinations
- Wires automatically validate type compatibility

### Wire Validation

Type compatibility is checked as you draw the wire and again at save time. If a connection is invalid, the wire paints **red** with a tooltip explaining why — for example, "string output cannot connect to numeric input." Invalid wires are not allowed to save: the offending wire is highlighted directly on the canvas instead of failing with a generic error.

The same contract runs in the component engine at runtime. If a wire ever produces a type mismatch — for example, an upstream component changes type after a library upgrade — the affected instance enters an ERROR state with the offending pin called out in the diagnostics.

Allowed coercions:

- `int` ↔ `float` (numeric widening)
- `bool` → `int` or `float` (truthy promotion)
- Identical types: `str` ↔ `str`, `list` ↔ `list`, `dict` ↔ `dict`

Strings, lists, and dicts cannot be silently coerced to other types.

### Custom Wire Routing

Click any wire to reveal a midpoint handle. Drag it perpendicular to the wire's direction to de-stack overlapping wires or reshape the route for readability. Double-click the wire to reset it to the default path. Routing is saved with the canvas and survives copy/paste.

### Dependency Ordering

When components are wired together, the engine automatically determines the correct execution order using topological sorting. Components whose outputs feed into other components' inputs execute first, ensuring data flows correctly in a single scan cycle.

If a circular dependency is detected (A feeds B, B feeds C, C feeds A), the engine logs a warning and executes the components in a best-effort order. Components in the cycle will see values from the previous scan cycle rather than the current one.

---

## Per-Instance Pin Layouts

Every instance has its own pin layout. The component type ships a default ordering, and you can layer your own customizations on top — reorder, insert gaps for visual grouping, or hide pins you don't need on this particular instance.

Open the **Pin Layout** tab on the instance configuration drawer (or click the pin layout icon on the node) to open the editor:

- **Drag pins** in the input or output column to reorder them
- **Insert a gap** between pins for visual separation
- **Hide a pin** by dragging it to the hidden tray on the right
- **Restore a hidden pin** by dragging it back from the tray
- **Reset to default** to discard the instance's overrides and fall back to the component type's layout

Layouts persist across canvas saves, environment clones, and copy/paste operations. Cross-side drags (e.g., trying to move an input pin to the output column) are rejected with visual feedback.

> [!NOTE] Hiding doesn
> Hiding a pin removes it from the visual node but does not delete any wires connected to it. If you re-show the pin later, the wire is still there. To remove a wire, delete it directly from the canvas or the Wiring tab.

---

## Offline Values

Each input field can have an **offline value** — a fallback used when the input is not wired or when live data is unavailable. Configure offline values in the instance's **Configuration** tab.

You can also click **Save Live to Offline** to capture the current runtime values as the new offline defaults. This is useful for initializing components with known-good values after a period of live operation.

---

## Saving the Canvas

Changes to the canvas (adding/removing instances, moving nodes, creating wires, editing pin layouts, customizing wire routes) are held locally until you click **Save** in the toolbar. The save operation is atomic — all changes are applied together or not at all.

If a save is rejected, the canvas highlights the specific instance, connector, or wire that failed validation rather than showing a generic error.

The toolbar also provides:

| Button | Action |
|--------|--------|
| **Undo / Redo** | Step through recent changes (including arrow-key nudges and selection changes) |
| **Refresh** | Reload the canvas from the server (discards unsaved changes) |
| **Delete** | Remove the selected node or wire |
| **Save** | Persist all changes to the server |

---

## Monitoring Live Values

When the environment is enabled, the canvas shows live values flowing through wires and pins. Input and output fields on each instance display their current values, updating in real time at the environment's scan rate.

Use the **Execution** tab on the environment detail page for performance metrics, and the **Logs** tab to stream per-instance log output for debugging.

---

## What's Next

- [Component Environments](https://ai-ops.com/docs/components/environments.md) — configure scan rates and monitor execution performance
- [Component Libraries](https://ai-ops.com/docs/components/libraries.md) — manage the component types available on the canvas
- [Building Components](https://ai-ops.com/docs/components/building-components.md) — create your own component types
