CatalystIn Progress

Rules that watch your product data and act on it

Write a rule once: when this happens and these conditions hold, do that. Catalyst checks it on a schedule or when an event arrives, lets you backtest it against past data, and asks for a two-factor check before a rule that moves money goes live.
Catalyst · src/rules.rs
use catalyst::generated::{
    CatalystActionSubjectMode, CatalystRuleFirePolicy, CatalystRuleMatchMode,
};
use catalyst::rules::{create, ActionSpec, ConditionSpec, CreateRule, TriggerSpec};
use serde_json::json;

// The rule starts as a Draft. Backtest it, then go live.
let rule_id = create(
    &valence,
    CreateRule {
        organization_id: "org-1".into(),
        name: "Trim winners".into(),
        created_by: "user-a".into(),
        timezone: "America/Los_Angeles".into(),
        tag_ids: Vec::new(),
        subject_selector_json: json!({"mode": "One", "ids": ["acct-1"]}),
        match_mode: CatalystRuleMatchMode::All,
        fire_policy: CatalystRuleFirePolicy::Everytime,
        cooldown_secs: None,
        max_fires_per_day: Some(3),
        trigger: TriggerSpec {
            kind_id: "chronon.schedule".into(),
            params: json!({"freq": "monthly"}),
        },
        conditions: vec![ConditionSpec {
            kind_id: "finance.balance_gte".into(),
            params: json!({"account_id": "acct-1", "amount": 100}),
            sort: 0,
            group: None,
            group_match_mode: None,
        }],
        actions: vec![ActionSpec {
            kind_id: "finance.transfer.initiate".into(),
            params: json!({"source_account_id": "acct-1", "dest_account_id": "acct-2"}),
            sort: 0,
            subject_mode: CatalystActionSubjectMode::Matched,
        }],
    },
)
.await?;
Ships inNot in a template yet

Why it exists

Every product grows a pile of small automations: alert me when a balance drops, restock when inventory runs low. Catalyst gives them one shape, one way to test them, and one place to pause them.

Status today

Rules and backtests work today. Scheduled and event-driven wakeups are still being wired through Chronon and Photon.
Rules and condition groups
Implemented
Combine a trigger, conditions and actions. Group conditions one level deep, such as A AND (B OR C).
Fire policy
Implemented
Set a cooldown, a daily cap, or fire once. A rule pauses itself after repeated failures.
Backtest
Implemented
Replay a rule over past data and see when it would have fired before it goes live.
Run now and live evaluation
Implemented
Evaluate a live rule when it wakes, or run it on demand and see the result in its history.
Go live with step-up
Implemented
Rules that move money or touch a live broker need a recent two-factor check before they go live.
Scheduled and event wakes
In Progress
Chronon schedules and Photon events can wake a rule. Going live doesn't install those wakes yet.
Product packs
Planned
Ready-made triggers, conditions, and actions from many Unified Field products: send a notification as an action, ask a Tachyon agent to judge content as a condition, or fire a rule when a Magnon task is created or a Polaron team is formed.

Code sample

Taken from the getting-started docs. See all code samples on Resources.
Catalyst ruleCatalyst
A scheduled rule with one condition and one action
use catalyst::generated::{
    CatalystActionSubjectMode, CatalystRuleFirePolicy, CatalystRuleMatchMode,
};
use catalyst::rules::{create, ActionSpec, ConditionSpec, CreateRule, TriggerSpec};
use serde_json::json;

// The rule starts as a Draft. Backtest it, then go live.
let rule_id = create(
    &valence,
    CreateRule {
        organization_id: "org-1".into(),
        name: "Trim winners".into(),
        created_by: "user-a".into(),
        timezone: "America/Los_Angeles".into(),
        tag_ids: Vec::new(),
        subject_selector_json: json!({"mode": "One", "ids": ["acct-1"]}),
        match_mode: CatalystRuleMatchMode::All,
        fire_policy: CatalystRuleFirePolicy::Everytime,
        cooldown_secs: None,
        max_fires_per_day: Some(3),
        trigger: TriggerSpec {
            kind_id: "chronon.schedule".into(),
            params: json!({"freq": "monthly"}),
        },
        conditions: vec![ConditionSpec {
            kind_id: "finance.balance_gte".into(),
            params: json!({"account_id": "acct-1", "amount": 100}),
            sort: 0,
            group: None,
            group_match_mode: None,
        }],
        actions: vec![ActionSpec {
            kind_id: "finance.transfer.initiate".into(),
            params: json!({"source_account_id": "acct-1", "dest_account_id": "acct-2"}),
            sort: 0,
            subject_mode: CatalystActionSubjectMode::Matched,
        }],
    },
)
.await?;