Docs

Rules

A rule watches one object type for a business condition and signals when that condition starts or clears. Reach for rules to track health states like "this invoice is overdue" or "this project is at risk."

A rule does not fetch data, transform rows, or run a process. It names the condition, reacts to object and link changes, and emits a stable triggered/resolved signal that the rest of your app — alerts, attention badges, workflows — can react to.

Define a rule

Write a rule as the state where the object needs attention. Put each definition in rules/ and export it.

TSrules/business-health.ts
import { defineRule } from "@sixb/core"
import { Invoice } from "../ontology/invoice"

export const overdueInvoices = defineRule("invoice.overdue")
  .on(Invoice)
  .where((invoice) => invoice.p.status.eq("overdue"))

This matches when an Invoice has status of "overdue".

PartMeaning
defineRule("invoice.overdue")Names the rule with a unique id
.on(Invoice)The object type the rule watches
.where(...)Describes when the rule matches

The .where(...) callback receives a typed subject built from the object type. Use p for properties and l for links; both are keyed by the type's ids.

Compose conditions

Combine smaller conditions with all, any, and not. This rule flags an at-risk project — one that is active, large, and missing a lead.

TS
import { defineRule } from "@sixb/core"
import { Project } from "../ontology/project"

export const atRiskProjects = defineRule("project.at-risk")
  .on(Project)
  .where((project) =>
    project.all(
      project.p.status.eq("active"),
      project.p.budget.gte(150000),
      project.l.lead.isMissing()
    )
  )

Property predicates check values (p), link predicates check whether a relationship exists (l). You can nest groups — for example, flag invoices that are overdue or large-and-still-sent:

TS
export const collectionRisk = defineRule("invoice.collection-risk")
  .on(Invoice)
  .where((invoice) =>
    invoice.any(
      invoice.p.status.eq("overdue"),
      invoice.all(invoice.p.status.eq("sent"), invoice.p.amount.gte(40000))
    )
  )

Predicates

NeedPredicate
Equal / not equaleq(value), notEq(value)
Compare numbersgt(n), gte(n), lt(n), lte(n)
Property is setisPresent(), isMissing()
Link is setexists(), isMissing()
Combineall(...), any(...), not(...)

eq / notEq take a string, number, boolean, or null. The comparison predicates take a number. isPresent / isMissing / exists take no value.

How matching works

Once registered, Sixb evaluates rules as objects and links change. When a rule starts matching an object, it is triggered; when the object stops matching, it is resolved. Active state is tracked so each object triggers once until it clears.

Evaluation reacts to object/link created, updated, and deleted events for the watched type and any links named in the predicate. See Events for the full domain-event list.

Reacting to the signal

A rule emits rule.triggered and rule.resolved domain events. Consume them by attaching an event schedule: select the occurrence with events.rule(rule).triggered() (or .resolved()) and bind it to a workflow, sync, or pipeline.

TS
import { defineSchedule, events } from "@sixb/core"
import { collectionRisk } from "../rules/business-health"

export const onCollectionRisk = defineSchedule("invoice.collection-risk-triggered")
  .on(events.rule(collectionRisk).triggered())

Attach onCollectionRisk to a workflow with .when(...) to act on it. In an app, subscribe to the same signal live with the client events.rules() builder — see client events.

Register rules

createSixb() discovers exported rule definitions from rules/ automatically:

TXT
your-project/
  ontology/
    invoice.ts
    project.ts
  rules/
    business-health.ts
  sixb.config.ts

To register rules explicitly instead, pass them to createSixb() (note: it is async):

TS
import { createSixb } from "@sixb/core"
import { Invoice } from "./ontology/invoice"
import { Project } from "./ontology/project"
import { overdueInvoices, atRiskProjects } from "./rules/business-health"

const sixb = await createSixb({
  ontologies: [Invoice, Project],
  rules: [overdueInvoices, atRiskProjects],
})

Inspect registered rules at runtime with sixb.getRuleDefinitions() and sixb.getRuleById(ruleId).

Rule vs workflow

Rules decide if something is true; workflows decide what to do next.

NeedUse
Know whether an object needs attentionRule
Emit a triggered / resolved signalRule
Run a multi-step processWorkflow
Fetch source dataSync
Clean or join table dataPipeline

Notes

  • Rule ids must be unique, and each rule is scoped to one object type.
  • Predicates are validated against the resolved ontology at startup. Unknown properties or links, and empty all() / any() groups, are rejected.
  • The .where(...) callback runs once at definition time and produces serializable predicate data; the callback itself is not stored.

Search docs

Search the documentation