Forms

InvocationRuleBuilder

Render and edit conditional automation rules composed of conditions and actions.

import { InvocationRuleBuilder } from '@lostgradient/cinder/invocation-rule-builder';
automationrules
01

Overview

A presentation component for building and reviewing conditional automation rules. Each rule is composed of one or more conditions (field / operator / value) and one or more actions (a target agent or service). Cinder renders the UI and reports every edit through a callback — it owns no rule execution, persistence, or validation semantics.

Ownership boundary

Cinder does not execute, validate, or persist rules. The consumer provides the complete rule model through the rules prop and handles every change emitted by onchange. Cinder is responsible only for rendering the controls with correct accessible names and emitting pure (non-mutating) change descriptors.

Usage

svelte
<script lang="ts">
  import { InvocationRuleBuilder } from '@lostgradient/cinder/invocation-rule-builder';
  import type {
    InvocationRule,
    InvocationRuleChange,
    InvocationRuleOption,
  } from '@lostgradient/cinder/invocation-rule-builder';

  let rules = $state<InvocationRule[]>([]);

  const fieldOptions: InvocationRuleOption[] = [
    { value: 'path', label: 'Path' },
    { value: 'label', label: 'Label' },
    { value: 'author', label: 'Author' },
  ];

  const operatorOptions: InvocationRuleOption[] = [
    { value: 'matches', label: 'matches' },
    { value: 'is', label: 'is' },
    { value: 'is-not', label: 'is not' },
  ];

  const actionOptions: InvocationRuleOption[] = [
    { value: 'security-review', label: 'Security Review Agent' },
    { value: 'code-review', label: 'Code Review Agent' },
  ];

  function handleChange(nextRules: InvocationRule[], change: InvocationRuleChange): void {
    rules = nextRules;
    // Persist or validate here — cinder does not do this for you.
  }
</script>

<InvocationRuleBuilder
  {rules}
  onchange={handleChange}
  {fieldOptions}
  {operatorOptions}
  {actionOptions}
  label="PR routing rules"
/>

Data model

ts
type InvocationRule = {
  id: string;
  label: string;
  conditions: InvocationRuleCondition[];
  actions: InvocationRuleAction[];
};

type InvocationRuleCondition = {
  id: string;
  field: string; // consumer-defined, e.g. "path"
  operator: string; // consumer-defined, e.g. "matches"
  value: string; // consumer-defined, e.g. "src/**"
};

type InvocationRuleAction = {
  id: string;
  target: string; // consumer-defined, e.g. "security-review"
};

A rule fires when ALL of its conditions match (implicit AND). Boolean grouping, OR logic, and nested condition trees are out of scope for this component.

Modes

Pass readonly={true} to render a read-only summary instead of editable controls. Schema-driven usage is read-only because callbacks are not representable in JSON Schema. Runtime consumers can render editable controls by passing onchange and leaving readonly false.

Conditions-only mode

Pass mode="conditions" to render conditions without actions — for example, a saved-search or alert-filter builder that has nothing to invoke. In this mode:

  • Action controls are hidden entirely. Rules never render or emit action descriptors (add-action, remove-action, update-action), and any actions on incoming rules are stripped from emitted rules. In the TypeScript props, operatorOptions, actionOptions, and addActionLabel are typed never in conditions-only mode, so passing them is a compile-time error. (The schema-driven surface and the runtime are more lenient — they treat those props as optional and simply ignore them in conditions-only mode, which is why the generated props table below lists them as optional.)
  • The operator set is fixed to eq (equals), gt (greater than), lt (less than), gte (greater than or equal), and lte (less than or equal). Cinder supplies these five with default labels.
  • The field control is a free-text combobox. fieldOptions remain typeahead suggestions and provide type metadata, but a user can press Enter or leave the field after typing a key that is not in the list.
  • The value control for each condition is inferred from the matching fieldOptions entry's optional type: a numeric text input for 'number', a checkbox for 'boolean', a <select> populated from that option's options for 'enum', and a plain text input for 'string' or an omitted type.
svelte
<script lang="ts">
  import { InvocationRuleBuilder } from '@lostgradient/cinder/invocation-rule-builder';
  import type {
    InvocationRule,
    InvocationRuleChange,
    InvocationRuleOption,
  } from '@lostgradient/cinder/invocation-rule-builder';

  let rules = $state<InvocationRule[]>([]);

  const fieldOptions: InvocationRuleOption[] = [
    { value: 'retry-count', label: 'Retry count', type: 'number' },
    { value: 'is-flaky', label: 'Flaky', type: 'boolean' },
    {
      value: 'severity',
      label: 'Severity',
      type: 'enum',
      options: [
        { value: 'low', label: 'Low' },
        { value: 'high', label: 'High' },
      ],
    },
  ];

  function handleChange(nextRules: InvocationRule[], _change: InvocationRuleChange): void {
    rules = nextRules;
  }
</script>

<InvocationRuleBuilder
  {rules}
  onchange={handleChange}
  {fieldOptions}
  mode="conditions"
  label="Alert filter conditions"
/>

A rule created in this mode still has an actions array on its data shape (so InvocationRule stays a single type across modes), but it is always empty and the UI provides no way to populate it.

Accessibility

Each condition's field selector, operator selector, value input, and remove button carry accessible labels that identify which condition and rule they belong to (e.g. "Field for condition 2 of Rule 1"). Each action's target selector and remove button are similarly labeled. Rule reorder buttons are labeled "Move Rule 1 up" and "Move Rule 1 down". Add buttons describe their destination rule. A live region announces add, remove, and move events to screen reader users.

In readonly mode all controls are replaced by visible text, so no interaction is possible and keyboard navigation follows the natural document order.

Focus management on remove: when a condition or action row is removed, focus moves to the preceding row's remove button, or to the "Add condition" / "Add action" button if the removed row was the last one.

The component uses semantic HTML: the root is a section with an aria-label, condition and action lists use role="list" with aria-labelledby pointing to the "Conditions" / "Actions" section heading, and each row uses role="listitem". In conditions-only modes, each field combobox keeps the per-condition accessible name (for example, "Field for condition 2 of Rule 1").

Live preview
02

When to use

Use when
  • Building a UI for configuring which agents or services run based on event conditions.
  • You only need conditions (no actions) — pass mode="conditions" for a constrained operator set and typed value inputs.
  • Your data is one flat implicit-AND conditions list — pass mode="flat-conditions" without rule-group metadata.
Avoid when
  • You need to execute, validate, or persist rules — cinder owns none of that logic.
03

Examples

PR review routing rules

Configure which code review agents run based on pull request conditions such as changed paths, labels, and author membership.

Conditions-only mode

Build alert-filter conditions with typed value inputs and a fixed comparison-operator set — no action targets, for cases like saved searches or alert filters that have nothing to invoke.

Flat AND-only conditions

Edit one controlled conditions array directly, without rule names, ordering, actions, or a way to add another group.

Readonly rule summary

Display configured automation rules in a non-editable summary view, suitable for review or confirmation screens.

04

Props

Props for invocation-rule-builder
Name Type Default Required Bindable Description
rules unknown []
conditions unknown []
onchange unknown req
fieldOptions InvocationRuleOption[] req Options for the condition field selector. Consumer-provided list of fields that a condition can test, e.g. "path", "label", "author".
operatorOptions unknown req
actionOptions unknown req
mode unknown 'full'
readonly unknown false
addRuleLabel unknown 'Add rule'
addConditionLabel text 'Add condition' Label for the "Add condition" button. Defaults to "Add condition".
addActionLabel unknown 'Add action'
label text Accessible label for the entire rule builder region.