u/dafzu

I built a rule engine, and I need feedback
▲ 34 r/golang

I built a rule engine, and I need feedback

Well...this fun experiment took about 5 months of my free time (no AI slop i promise). I got interested in rule engines early this year so i started building one in Go to fit my exact needs. I'm posting this because i've been staring at it alone for too long and I would really like some outside eyes to help with direction. I think it's in a good state now to share with you all.

I'm not sure how to write this post so maybe the best approach is to show an example and work through it:

signal GiveAward(pid, award)

// add more here: emojis, curly quotes, etc.
const MARKERS = ["—"]

rule SlopFilter {
    text = strings::lower(input.text)

    out score = len(arrays::filter(MARKERS, |m| strings::contains(text, m)))
    out slop  = score > 0

    emit GiveAward(input.id, "bravo") when !slop
}

What you see above is a basic nodora ruleset. A rule is a pure function: the same input always yields the same output. Evaluating a rule gives you back two things: outputs (facts about the input) and signals (things that should happen next). Notice that the rule does not constrain the output shape. The output can be any value (see the out keyword), not just a boolean decision. The input-output contract between the rules and consumers is up to you to define.

A signal is a named event the rule can fire off, like "give this post an award" or "flag for review" type thing. An asynchronous side effect of the rule. Declaring it doesn't do anything, it just says this signal exists and takes these arguments. The engine decides through emit statement when to fire it, which you can listen for.

Using the nodora CLI, we can compile this example with:

$ nodora compile -f ./example.ruleset

Then go through evaluation:

$ echo '{"id":1,"text":"This is a great post"}' | nodora eval -f ./example.json --stdin

which outputs:

{"outputs":{"score":0,"slop":false},"emitted_signals":[{"name":"GiveAward","args":[1,"bravo"]}]}

We can act on a signal with:

$ echo '{"id":1,"text":"This is a great post"}' | nodora eval -f ./example.json -e GiveAward="echo giving {2} award to post with id {1}" --stdin

{"outputs":{"score":0,"slop":false},"emitted_signals":[{"name":"GiveAward","args":[1,"bravo"]}]}
giving bravo award to post with id 1

If we put an em dash in the text and evaluate again:

$ echo '{"id":1,"text":"This is a great post — really."}' | nodora eval -f ./example.json --stdin

{"outputs":{"score":1,"slop":true},"emitted_signals":[]}

There is a lot more to it, you can read the full docs at nodora.org/docs. The engine is fully open-source (github repo).

Note: In most cases you probably won't use the CLI for evaluation. Its mainly there for quick testing. You'd usually embed the engine directly into your go project, or use one of the language bindings: js (wasm) and rust (working on others)

I'd love to hear your overall thoughts and feel free to ask anything :)

u/dafzu — 3 days ago