The open-source rules engine for IATA Modern Airline Retailing — Offer Management, Order Management, ancillary pricing, eligibility, taxation. Airlines design and automate their business processes as JSON rule graphs and run them anywhere, with sub-millisecond evaluation and zero proprietary dependencies.
Floor numbers from a benchmark you can run yourself in five minutes. Designed to clear the IATA MAR latency bar by 70× at single-node scale and scale further by sharding.
Modern Airline Retailing is built on rules: who is eligible for what, at what price, in which fare family, with which taxes, under which conditions. Today those rules live inside expensive proprietary engines — locked, opaque, and built for the legacy PNR/EMD world. RuleForge is the open alternative: a runtime that airlines own, read line by line, and extend on their own clock.
MIT-licensed, on GitHub, runs on a laptop or a single VM. No vendor lock-in, no per-evaluation pricing, no audit risk. The rules and the engine that runs them belong to the airline. Read the code, fork it, contribute back.
Rules consume and produce JSON in the exact shape of IATA Offers, Orders, Services, and Bundles. Filter on $.passengers[*].type, mutate $.bundles[0].products[], look up tax rates by $.journey.origin. No ORM, no shred-and-rebuild, no schema drift.
Eligibility, tier bonuses, ancillary fees, fare conditions, taxation, surcharge stacks — every business rule becomes an authored JSON graph that anyone with the right admin app can version, review, and publish. Code-deploys for code; rule-deploys for rules.
~70µs p50 for a typical 8-node rule. 73,000 evaluations/sec on 16 workers. Rule snapshots are immutable per version; the engine resolves endpoint → ruleId → version → snapshot with all three steps cached. Production mode skips trace and duration overhead entirely.
Self-contained binaries for Windows, Linux, macOS — no .NET install needed on the target machine. Drop on a VM, ship in a container, or co-locate alongside DocumentForge as a sidecar where the cold-path is 2.5ms instead of 1500ms across the public internet.
Add ?debug=true and the engine returns a per-node trace plus wall-clock duration. Every rule is a versioned snapshot in DocumentForge. Approval workflows, audit logs, environment pinning — all built on data the airline already owns.
Self-contained binary. No .NET install needed. Drop on a laptop, evaluate the bundled fixtures against four worked scenarios, and see real numbers in under five minutes.
RuleForge is a .NET library at heart, but ships as two self-contained binaries — ruleforge-cli for one-shot evaluation and ruleforge-api for HTTP service. Pick the tab that matches your stack — every example evaluates the bundled rule-bag-policy@7 against a sample request and returns the same envelope.
using System.Text.Json; using RuleForge.Core; using RuleForge.Core.Loader; using RuleForge.Core.Graph; // Point at the bundled fixture pack — no DocumentForge required var rules = new LocalFileRuleSource("./fixtures/rules"); var refs = new LocalFileReferenceSetSource("./fixtures/refs"); var runner = new RuleRunner(); // Resolve and evaluate var rule = await rules.GetByEndpointAsync("/v1/ancillary/bag-policy", HttpMethodKind.POST); var request = JsonDocument.Parse(""" { "pnr": "MKP800", "cabin": "Y", "orig": "LHR", "dest": "DXB", "bagPieces": 3, "markup": 0.15, "pax": [{ "id": "p1", "type": "ADT" }] } """); var envelope = await runner.RunAsync(rule!, request.RootElement, new RuleRunner.Options(Debug: true, ReferenceSetSource: refs)); Console.WriteLine(envelope.Decision); // "apply" Console.WriteLine(envelope.Result); // { code: "BAG", fee: 517.5, currency: "AED", pieces: 3 }
# Start the HTTP engine RULEFORGE_FIXTURES_DIR=./fixtures/rules \ RULEFORGE_REFS_DIR=./fixtures/refs \ ./ruleforge-api --urls http://localhost:5050 # Evaluate curl -X POST "http://localhost:5050/v1/ancillary/bag-policy?debug=true" \ -H "Content-Type: application/json" \ -d '{ "pnr": "MKP800", "cabin": "Y", "orig": "LHR", "dest": "DXB", "bagPieces": 3, "markup": 0.15, "pax": [{ "id": "p1", "type": "ADT" }] }' # Returns: { ruleId, ruleVersion, decision, evaluatedAt, result, trace }
// Any HTTP client works — here HttpClient (JDK 11+) var http = HttpClient.newHttpClient(); var body = """ { "pnr": "MKP800", "cabin": "Y", "orig": "LHR", "dest": "DXB", "bagPieces": 3, "markup": 0.15, "pax": [{ "id": "p1", "type": "ADT" }] } """; var req = HttpRequest.newBuilder() .uri(URI.create("http://localhost:5050/v1/ancillary/bag-policy?debug=true")) .header("Content-Type", "application/json") .POST(BodyPublishers.ofString(body)) .build(); var resp = http.send(req, BodyHandlers.ofString()); System.out.println(resp.body());
import httpx resp = httpx.post( "http://localhost:5050/v1/ancillary/bag-policy", params={"debug": "true"}, json={ "pnr": "MKP800", "cabin": "Y", "orig": "LHR", "dest": "DXB", "bagPieces": 3, "markup": 0.15, "pax": [{"id": "p1", "type": "ADT"}], }, ) envelope = resp.json() print(envelope["decision"], envelope["result"])
// Node 20+ — global fetch, no dependencies const resp = await fetch( "http://localhost:5050/v1/ancillary/bag-policy?debug=true", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ pnr: "MKP800", cabin: "Y", orig: "LHR", dest: "DXB", bagPieces: 3, markup: 0.15, pax: [{ id: "p1", type: "ADT" }], }), } ); const envelope = await resp.json(); console.log(envelope.decision, envelope.result);
Every evaluation produces the same envelope shape: a ruleId, the evaluated version, a decision (apply | skip | error), the rule-specific result, and an optional trace. The decision tells the caller what to do; the result is the rule's payload.
// POST /v1/ancillary/bag-policy?debug=true { "ruleId": "rule-bag-policy", "ruleVersion": 7, "decision": "apply", "evaluatedAt": "2026-04-30T10:14:04.614Z", "result": { "code": "BAG", "weightKg": 23, "currency": "AED", "fee": 517.5, "pieces": 3 }, "trace": [/* per-node, only in debug mode */], "durationMs": 47 }
Three layers make RuleForge rules self-describing — no separate SDK, no external doc, no drift between editor and engine. Anyone with the binary can build new rules and have them validated against the same contract the engine enforces at runtime.
Run ruleforge-cli schemas --out ./schemas. The output is generated from the live C# runtime types via JsonSchemaExporter — they are the contract. Validate authored rules with any off-the-shelf JSON Schema validator (ajv, jsonschema, NJsonSchema). If it passes, the engine accepts it.
inputSchemaOpen any rule JSON and the inputSchema field declares exactly what request body the engine will accept. Use it to render forms, codegen client types, or drive contract tests downstream — without ever calling the engine.
Copy the closest one as your starting point. rule-bag-policy · rule-tier-bonus · rule-pnr-taxes · rule-seat-assignments. All valid, runnable JSON — the canonical examples for filter / lookup / iteration / sub-rule patterns.
Why RuleForge for IATA Modern Airline Retailing. Eligibility, ancillary pricing, taxation, fare conditions — and the business case for owning the engine.
Download the binary, evaluate four pre-built scenarios from basic to advanced, drive the engine from Postman. Five minutes end-to-end.
Tech specs for engineers: rule schema, every node category, evaluators, iteration, sub-rules, storage, CLI, deployment.
run, publish, mirror, bench), two source backends (DocumentForge HTTP + local file), self-contained binaries for five platforms, and end-to-end live demos. Production-ready for sub-millisecond rule evaluation; pair with whatever rule editor your team prefers.