Kubernetes API Reference

This document provides the working reference for the TinySystems Custom Resource Definitions (CRDs) you interact with most: TinyNode and TinyModule. For the full generated CRD reference (including TinyFlow, TinyProject, TinyScenario and TinyWidgetPage) see the generated API docs.

Source of truth: api/v1alpha1/tinynode_types.go, api/v1alpha1/tinymodule_types.go in the SDK (github.com/tiny-systems/module).

TinyNode

Represents an instance of a component in a flow.

apiVersion/kind

apiVersion: operator.tinysystems.io/v1alpha1
kind: TinyNode

Spec

spec:
  module: string            # Module name - container image repo + tag (required)
  component: string         # Component name within the module (required)

  ports:                    # Port configurations (data mapping lives here)
    - from: string          # Sender's full port name (config depends on sender)
      port: string          # This node's port name (required)
      schema: <bytes>       # JSON schema of the port (base64-encoded bytes)
      configuration: <bytes># JSON data of the port's configuration (base64-encoded bytes)
      flowID: string

  edges:                    # Outgoing connections
    - id: string            # Edge id (required)
      port: string          # This node's source port name (required)
      to: string            # Other node's full port name, "node:port" (required)
      flowID: string        # (required)
      retryPolicy:          # Optional per-edge retry policy
        maxAttempts: int    # 1-10; 1 = no retry (default)
        initialDelayMs: int # Initial backoff, default 1s
        backoffCoefficient: string # Multiplier per attempt, default "2.0"
        maxDelayMs: int     # Cap on a single attempt's delay, default 30s
        nonRetryableErrorCodes: [string] # Error codes that skip retry
        timeoutMs: int      # Per-attempt handler timeout; 0 = transport default

Note: edge data mapping is not stored on the edge. The receiving node stores it in spec.ports[] as a TinyNodePortConfig whose from field names the sending node's port.

Status

status:
  observedGeneration: int64 # Most recent generation observed by the controller
  module:                   # Resolved module
    name: string
    version: string
    sdkVersion: string      # SDK version the module was built with
  component:                # Component metadata
    description: string
    info: string
    tags: [string]
  ports:                    # Port definitions published by the component
    - name: string
      label: string
      position: int         # 0=Top, 1=Right, 2=Bottom, 3=Left
      source: boolean       # true = output port
      schema: <bytes>       # JSON Schema (base64-encoded bytes)
      configuration: <bytes># Current configuration (base64-encoded bytes)
  status: string            # Free-form status message
  metadata: {}              # map[string]string — component state propagation
  error: boolean            # true when the node is in error
  lastUpdateTime: string    # RFC3339 timestamp

Example

apiVersion: operator.tinysystems.io/v1alpha1
kind: TinyNode
metadata:
  name: myproject.common.router-abc12
  namespace: tinysystems
  labels:
    tinysystems.io/flow-name: "flow-123"
    tinysystems.io/project-name: "myproject"
    tinysystems.io/module-version-major: "common-v1"
spec:
  module: ghcr.io/tiny-systems/common-module:v1.5.0
  component: router
  edges:
    - id: "edge-1"
      port: "out_success"
      to: "myproject.common.process-def34:input"
      flowID: "flow-123"
    - id: "edge-2"
      port: "out_default"
      to: "myproject.common.errorhandler-ghi56:input"
      flowID: "flow-123"
      retryPolicy:
        maxAttempts: 3
        initialDelayMs: 1000
        backoffCoefficient: "2.0"

TinyModule

Represents a deployed module in the cluster.

apiVersion/kind

apiVersion: operator.tinysystems.io/v1alpha1
kind: TinyModule

Spec

spec:
  image: string              # Container image

Status

status:
  addr: string               # Listen address of the module server
  name: string               # Module name
  version: string            # Module version
  sdkVersion: string         # SDK version the module was built with
  components:                # Available components
    - name: string
      description: string
      info: string
      tags: [string]
      ports:                 # Component-level port metadata (pre-install discovery)
        - name: string
          label: string
          source: boolean    # true = output port
          position: int      # 0=Top, 1=Right, 2=Bottom, 3=Left
          schema: <bytes>    # JSON schema (base64-encoded bytes)

Example

apiVersion: operator.tinysystems.io/v1alpha1
kind: TinyModule
metadata:
  name: common-module-v1
  namespace: tinysystems
spec:
  image: ghcr.io/tiny-systems/common-module:v1.5.0
status:
  addr: ":50051"
  name: ghcr.io/tiny-systems/common-module
  version: "1.5.0"
  sdkVersion: "0.13.59"
  components:
    - name: router
      description: "Route messages based on conditions"
      info: "Evaluates conditions and routes to the matching output port."
      tags: ["routing", "control-flow"]

External Triggers

There is no TinySignal CRD. External systems trigger node ports by publishing directly to the runtime over NATS via the SDK's wire package:

import "github.com/tiny-systems/module/pkg/wire"

// Send data to a node's port; returns the node's synchronous reply.
reply, err := wire.Publish(ctx, nc, targetNode, port, data, wire.Options{})

The platform's tooling (MCP send_signal, dashboards, schedulers) uses this path.


Field Reference Tables

TinyNode.spec

FieldTypeRequiredDescription
modulestringYesModule name — container image repo + tag
componentstringYesComponent name within the module
portsTinyNodePortConfigNoPort configurations (data mapping)
edgesTinyNodeEdgeNoOutgoing connections

TinyNode.spec.edges (TinyNodeEdge)

FieldTypeRequiredDescription
idstringYesEdge id
portstringYesThis node's source port name
tostringYesOther node's full port name (node:port)
flowIDstringYesFlow the edge belongs to
retryPolicyEdgeRetryPolicyNoPer-edge retry policy

EdgeRetryPolicy

FieldTypeDefaultDescription
maxAttemptsint1Max total dispatch attempts (1-10); 1 = no retry
initialDelayMsint1000Initial backoff between attempts
backoffCoefficientstring"2.0"Multiplier applied to the delay each attempt
maxDelayMsint30000Cap on a single attempt's delay
nonRetryableErrorCodesstringCodes (from pkg/errors.NonRetryable) that skip retry, e.g. quota_exceeded, unauthorized, content_filter, validation
timeoutMsint0Per-attempt handler timeout; 0 = transport default (5 min for NATS transports)

Only failures a component marked transient (module.Retryable) are re-dispatched; unmarked errors surface immediately regardless of maxAttempts.

TinyNode.spec.ports (TinyNodePortConfig)

FieldTypeRequiredDescription
fromstringNoSender's full port name (settings depend on a sender)
portstringYesThis node's port name
schemabytesNoJSON schema of the port
configurationbytesNoJSON data of the port's configuration
flowIDstringNoFlow the configuration belongs to

TinyNode.status

FieldTypeDescription
observedGenerationint64Most recent generation observed by the controller
moduleTinyNodeModuleStatus{name, version, sdkVersion}
componentTinyNodeComponentStatus{description, info, tags}
portsTinyNodePortStatus{name, label, position (int 0-3), source, schema, configuration}
statusstringFree-form status message
metadatamapstringstringComponent state propagation
errorbooleanTrue when the node is in error
lastUpdateTimeTimeLast status update

TinyModule.spec

FieldTypeRequiredDescription
imagestringYesContainer image reference

TinyModule.status

FieldTypeDescription
addrstringListen address of the module server
namestringModule name
versionstringModule version
sdkVersionstringSDK version the module was built with
componentsTinyModuleComponentStatus{name, description, info, tags, ports}

Labels and Annotations

All keys use the tinysystems.io/ prefix (constants in api/v1alpha1/tinynode_types.go).

Labels

LabelConstantDescription
tinysystems.io/flow-nameFlowNameLabelFlow the node belongs to
tinysystems.io/project-nameProjectNameLabelProject the resource belongs to
tinysystems.io/node-nameNodeNameLabelNode name (attaching related resources to nodes)
tinysystems.io/module-version-majorModuleNameMajorLabelModule major version
tinysystems.io/dashboardDashboardLabelDashboard association
tinysystems.io/execution-modeExecutionModeLabeldurable = async ack-on-emit execution surviving pod death

Annotations

AnnotationConstantDescription
tinysystems.io/page-namePageTitleAnnotationWidget page title
tinysystems.io/page-sort-idxPageSortIdxAnnotationWidget page sort index
tinysystems.io/project-nameProjectNameAnnotationProject name
tinysystems.io/flow-descriptionFlowDescriptionAnnotationFlow description
tinysystems.io/node-handlesNodeHandlesAnnotationNode handles
tinysystems.io/shared-with-flowsSharedWithFlowsAnnotationFlows a shared node is visible in
tinysystems.io/component-pos-xComponentPosXAnnotationEditor X coordinate
tinysystems.io/component-pos-yComponentPosYAnnotationEditor Y coordinate
tinysystems.io/component-pos-spinComponentPosSpinAnnotationEditor rotation
tinysystems.io/node-labelNodeLabelAnnotationUser-facing node label
tinysystems.io/node-commentNodeCommentAnnotationUser comment on the node
tinysystems.io/ingress-hostname-suffixIngressHostNameSuffixAnnotationSuffix for auto-generated ingress hostnames
tinysystems.io/scenario-nameScenarioNameAnnotationScenario association

RBAC Requirements

Minimum Permissions

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: tinysystems-controller
rules:
  - apiGroups: ["operator.tinysystems.io"]
    resources: ["tinynodes", "tinymodules", "tinyflows", "tinyprojects", "tinyscenarios", "tinywidgetpages"]
    verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
  - apiGroups: ["operator.tinysystems.io"]
    resources: ["tinynodes/status", "tinymodules/status"]
    verbs: ["get", "update", "patch"]