Guides
Each guide covers one task in depth, with compiled code, the real output it produced, and the edge cases you'll meet in production. New to RuleWright? Start with Get started or a tutorial.
Writing rules
ConditionsEvery operator, groups, field paths and nulls.
Actions and outputsSet, add, append and remove, and how outputs merge.
Computed valuesArithmetic, text and null handling on either side.
Scoped paramsName an expression once, reference it anywhere in scope.
Collections
Any, All, None, $ and count.
Rule setsPriority, else branches, disabling and stopping early.
Decision tablesRows and columns, first and collect.
Extending
Custom functionsThe built-in catalog, delegates, classes and discovery.
Value functionsRegistered computations, called from expressions.
Custom actionsYour own action types over the running outputs.
JSON adaptersSystem.Text.Json or Newtonsoft.Json, with the same results.
Build rules in C#The immutable domain model, with no JSON at all.
Running in production
Validate documentsEvery error, with a JSON pointer, without throwing.
Trace why a rule firedPer-condition results, short circuits and skips.
Host and reload rulesLifetimes, dependency injection and hot reload.
Discover the vocabularyWhat a rule editor may offer, read at run time.
Accept rules you didn't writeRegex time limits, projections and size bounds.
The facts these guides use
Every guide evaluates the same small model. Facts.Vip() is Aroha, a 34-year-old gold VIP in New Zealand with a three-line order. Facts.Newcomer() is Ben, 17, with no country on file and a single small order.
public sealed class Checkout
{
public Customer Customer { get; set; } = new();
public Order Order { get; set; } = new();
}
public sealed class Customer
{
public string Name { get; set; } = "";
public int Age { get; set; }
public string Tier { get; set; } = "standard";
public bool IsVip { get; set; }
public int LoyaltyYears { get; set; }
public string? Country { get; set; }
public string? Email { get; set; }
}
public sealed class Order
{
public decimal Total { get; set; }
public int ItemCount { get; set; }
public decimal Weight { get; set; }
public string? Coupon { get; set; }
public DateTime PlacedOn { get; set; }
public List<OrderLine> Lines { get; set; } = new();
public List<string> Tags { get; set; } = new();
}
public sealed class OrderLine
{
public string Sku { get; set; } = "";
public string Category { get; set; } = "";
public int Quantity { get; set; }
public decimal Price { get; set; }
}
/// <summary>Ready-made facts, so each sample shows only the part it is about.</summary>
internal static class Facts
{
/// <summary>A loyal adult VIP with a three-line order placed on a Saturday.</summary>
public static Checkout Vip() => new()
{
Customer = new Customer { Name = "Aroha", Age = 34, Tier = "gold", IsVip = true, LoyaltyYears = 6, Country = "NZ", Email = "aroha@example.com" },
Order = new Order
{
Total = 240m,
ItemCount = 4,
Weight = 2.5m,
PlacedOn = new DateTime(2026, 9, 19, 10, 30, 0, DateTimeKind.Utc),
Lines =
{
new OrderLine { Sku = "TEA-01", Category = "grocery", Quantity = 2, Price = 45m },
new OrderLine { Sku = "WINE-12", Category = "alcohol", Quantity = 1, Price = 60m },
new OrderLine { Sku = "MUG-07", Category = "homeware", Quantity = 1, Price = 90m },
},
Tags = { "gift", "priority" },
},
};
/// <summary>A first-time teenage customer with one small order placed on a Tuesday.</summary>
public static Checkout Newcomer() => new()
{
Customer = new Customer { Name = "Ben", Age = 17, Tier = "standard", LoyaltyYears = 0, Country = null, Email = "not-an-email" },
Order = new Order
{
Total = 35m,
ItemCount = 1,
Weight = 0.4m,
PlacedOn = new DateTime(2026, 9, 22, 14, 0, 0, DateTimeKind.Utc),
Lines = { new OrderLine { Sku = "PEN-02", Category = "stationery", Quantity = 1, Price = 35m } },
},
};
}
Unless a guide says otherwise, engine is built as in Your first rule, with UseJsonReader(new SystemTextJsonReader()).