Automation is dangerous. It scales mistakes as efficiently as it scales success. That's why we built the Rules Engine with a simple philosophy: suggest first, apply only with permission, log everything.
Why Rules?
With Views, we can ask questions of our financial data. But questions are passiveβthey don't change anything. Rules are active. They watch for conditions and take action.
Real-world use cases:
- "Categorize all Amazon purchases as Shopping"
- "Mark recurring bills as reconciled automatically"
- "Tag large purchases over $500 for review"
- "Rename payees from 'SQ *' to 'Square'"
Rules Consume Views
The key insight: Rules don't define their own queries. They use Views.
Rule: "Auto-categorize Amazon"
βββ triggerViewId: "uncategorized-transactions"
βββ conditions: [{ field: "payee", operator: "contains", value: "amazon" }]
βββ actions: [{ type: "setCategory", categoryId: "cat_shopping" }]
βββ applyMode: "suggest"This separation is powerful:
- Views are reusable β One "Uncategorized Transactions" view can trigger many rules
- Rules are focused β Each rule does one thing well
- Debugging is easy β Run the trigger view to see what transactions will match
Suggest-First by Default
Every rule has an applyMode:
suggest (DEFAULT)
Creates a pending suggestion that you can approve or reject. Changes don't happen until you say so. This is safe automation.
auto
Applies changes immediately. No approval required. Powerful but dangerous. Must be explicitly enabled per rule.
We chose suggest-first because trust is earned. A new rule should prove itself before it gets autonomy. You can always upgrade a rule to auto-apply after you've seen it work correctly.
Allowed Actions (Initial Set)
Rules can only perform predefined, declarative actions:
setCategory // Assign a category to a transaction setPayee // Update the payee name addMetadata // Add key-value metadata markReconciled // Mark transaction as verified splitTransaction // Split into multiple allocations (future)
Notably absent: no scripts, no loops, no arbitrary code. Rules are data structures, not programs. This makes them safe to store, share, and audit.
Audit Everything
Every rule action creates an audit log entry:
{
ruleId: "rule_abc123",
ruleName: "Auto-categorize Amazon",
action: "apply",
transactionIds: ["tx_1", "tx_2", "tx_3"],
changes: [
{ transactionId: "tx_1", field: "categoryId", oldValue: null, newValue: "cat_shopping" },
{ transactionId: "tx_2", field: "categoryId", oldValue: null, newValue: "cat_shopping" }
],
triggeredAt: 1703318400000,
appliedAt: 1703318400123,
appliedBy: "auto"
}The audit log enables:
- Debugging β See exactly what a rule did and when
- Accountability β Know which rule modified which transactions
- Future: Revert β Roll back changes if a rule misbehaves
The RuleEngine
Like the QueryEngine for Views, the RuleEngine is the only executor of rules:
1. Execute trigger View via QueryEngine
2. Apply additional conditions to filter results
3. Calculate proposed changes for each transaction
4. Create suggestion (suggest mode) or apply via LedgerService (auto mode)
5. Log everything to audit log
The RuleEngine is deterministic. Same rule + same data = same results.
What We Built Today
- Rule Primitive β Data-first rule definition with trigger view, conditions, and actions
- RuleEngine β Deterministic executor that uses Views and LedgerService
- Suggest Mode β Default safe mode that requires human approval
- Auto Mode β Opt-in immediate execution for trusted rules
- Audit Log β Append-only record of all rule actions
- Rules UI β Create, edit, enable/disable, preview, and execute rules
Why This Matters
Rules are the bridge between data and action. They let you automate the tedious parts of financial management while keeping control over the important decisions.
By building on Views, we get composability. By defaulting to suggestions, we get safety. By logging everything, we get trust.
Automation should make your life easier, not scarier. That's the goal.
β The Accelerate Finance Team