microsoft/OAT: a rules engine for inspecting C# objects
Object Analysis Toolkit is a C# library for analyzing objects using Rules.
At a glance
- What is it?
- Object Analysis Toolkit applies Rule objects with boolean expressions and Clauses to arbitrary C# objects, and returns the rules that matched. It suits .NET developers who need declarative, data-driven checks over object graphs rather than hand-written if statements.
- Who is it for?
- Adopt microsoft/OAT if you have C# objects and want the checks over them expressed as data (a Rule with an Expression and a list of Clauses) instead of compiled conditionals, and if you are willing to write a custom Operation delegate for anything the built-in operations do not cover.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 47 days ago.
- What is it written in?
- Mainly C#, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What problem microsoft/OAT solves, and for whom
The README describes OAT as a rules driven metaprogramming engine for arbitrary C# objects. That phrasing is precise about the scope. The library does not know anything about your domain types. It takes an object and a set of Rule objects and decides which rules apply to that object.
The audience is .NET developers who keep writing the same shape of code: a growing set of conditional checks over properties and nested properties of some object, where the checks change often enough that recompiling is annoying. OAT moves those checks out of C# control flow and into Rule objects with a boolean Expression and a list of Clauses. A Clause names an Operation and a Field, and the README says the field can be any property, subproperty or field of the object, with `SomeFieldOfTarget.SomeObject.SomeProperty` given as the form.
That is the trade. You gain rules that are data and can be authored, stored and shipped separately from the code that runs them. You lose the compiler's help. A misspelled field path in a Rule is not a build error. Whether the library surfaces it as an error or as a silent non-match is not stated in the README, and that gap matters when rules come from outside your repository.
How Analyze, Clauses and Captures fit together
A Rule carries a target object, an int Severity, a string boolean Expression, and a List of Clauses. The Clauses are applied to the targeted object. Each Clause performs a specified Operation on a specified Field. The Expression is what combines clause outcomes into a verdict, which is why the README calls it a boolean expression rather than a filter.
The entry point is the Analyzer. `analyzer.Analyze(rules, target)` returns the rules that apply. `analyzer.GetCaptures(rules, target)` returns captured clause results. Capturing is the second half of the design: a Clause can capture the result of its operation so that value travels back with the applied Rule. Without captures you learn only which rules fired. With them you can also learn what the clause saw, which is usually what you need to explain a verdict to someone.
The extension points are delegates. The README says the Operation set can be expanded with delegates, and that the object types supported by existing operations can also be expanded with delegates. So the built-in operations are a starting set, not a closed set. The wiki is where the delegate documentation lives, per the README's Delegates page reference.
One structural detail worth noting: the Severity is an int, not an enum. That leaves the meaning of the scale entirely to the caller. Nothing in the README assigns semantics to particular values, so a team adopting OAT has to define its own severity convention and enforce it in review.
Installing microsoft/OAT from NuGet and running a first analysis
OAT ships as a library on NuGet under the package name Microsoft.CST.OAT. The README points to the package page at nuget.org/packages/Microsoft.CST.OAT as the place to get it.
The README states that using C# scripts in rules additionally requires Microsoft.CST.OAT.Scripting, linked at nuget.org/packages/Microsoft.CST.OAT.Scripting.
With the package referenced, the README's basic usage is short. You supply a target object and a set of rules, construct an Analyzer, and call Analyze:
object target;
IEnumerable<Rule> rules;
var analyzer = new Analyzer();
var rulesWhichApply = analyzer.Analyze(rules,target);What you get back is the subset of `rules` that apply to `target`. The README does not show how a Rule is constructed in code, so the next step is the wiki's Authoring Rules page, which the README points to for that. If you also need the values the clauses observed, swap the call for the capture form:
object target;
IEnumerable<Rule> rules;
var analyzer = new Analyzer();
var res = analyzer.GetCaptures(rules, target);The README presents this as the second supported entry point, not as a variant of Analyze. Treat them as two different questions: which rules match, and what did the matching clauses see.
There is also OAT Blazor, which the README describes as an experimental WebAssembly app that runs in your browser and lets you author rules and test them in a sandbox using objects instantiated from an assembly you provide. The word experimental is the README's, and it is the right word to carry into a decision about using it in a pipeline.
Where microsoft/OAT stops being the right tool
The library is a C# library. Rules are C# objects. If the rules need to be authored or evaluated by a Java service, a Python script or a browser page that is not the Blazor app, there is no documented path in the README for that. The README does not describe a rule file format, a JSON schema, or a serialization contract for Rule objects. It describes the Rule class and points at the API docs and the wiki. Teams that assume a portable rule format will discover that assumption is theirs, not the project's.
Field paths are strings. The README's example, `SomeFieldOfTarget.SomeObject.SomeProperty`, is resolved at analysis time rather than compile time. Renaming a property in the target class does not break the build, and nothing in the README says the analyzer will complain loudly when a path no longer resolves. In a codebase where rules are checked in alongside the types they target, that is a refactoring hazard you have to manage with tests.
The scripting path is a separate package, and the README does not name the script language it accepts. It says you need Microsoft.CST.OAT.Scripting to enable using C# scripts in rules, which implies C#, but it does not state the execution model, the sandboxing, or the limits. If your rules come from untrusted authors, the README gives you nothing to reason about on that front.
Finally, the repository has OAT.Benchmarks and OAT.Tests directories, so performance and correctness work exists in the tree, but the README publishes no throughput or latency figures. If you are planning to run OAT over a large object set per request, you are measuring that yourself.
OAT against a plain predicate and against a general rules engine
The obvious alternative is not another library at all. It is `Func<T, bool>`. A list of predicates over a typed object is faster to write, gets full compiler checking, and needs no package. What it cannot do is travel as data. The moment the checks need to be edited by someone who is not shipping a build, or stored next to a configuration, predicates stop fitting and OAT starts to.
A second comparison is a general-purpose rules engine built around a rule language, where conditions are parsed from text and evaluated by an interpreter. The difference in approach is where the type information lives. A general engine typically evaluates against a dictionary or a dynamic value model, so the rule language has to describe types itself. OAT goes the other way: the target is a real C# object and the Field path is resolved against it, with delegates available to extend both the operations and the object types they support. That keeps the host language's type system in play for anything you write in C#, at the cost of being usable only from C#.
A third comparison is writing your own small evaluator over an expression string. That is what OAT is, plus the Clause and Capture machinery, the severity field, the delegate extension points, and the wiki and API documentation. The question to ask is whether you would end up rebuilding those parts. If the answer is no, OAT is a reasonable dependency. If the answer is yes, you probably want the smaller thing.
Licence, contribution terms and the cost of upgrading
OAT is MIT licensed, with the licence text in LICENSE.txt at the repository root. MIT is permissive: it allows use, modification and redistribution with the copyright notice and permission notice retained. That is the licence position as recorded in the repository, and it is the only licence statement here. Nothing in this article is legal advice, and the Microsoft Privacy Statement linked from the README governs usage of the application rather than the library's licence terms.
Contributions run through Microsoft's Contributor License Agreement process. The README states that most contributions require agreeing to a CLA, that a bot checks pull requests automatically, and that you only need to do it once across all repos using that CLA. A project adopting OAT and patching it locally should know that upstreaming a fix carries that step.
On maintenance, there is no last push date and no release information to work from, so there is nothing to support a claim about how frequently the project is updated, and none is made. For upgrade cost, the practical exposure is the rule set rather than the package version. Because field paths are strings and no schema is documented, a change in the target object model is what forces rule edits, and the OAT.Tests directory in the repository is the place to look for how the project itself exercises that surface. Teams should pin the Microsoft.CST.OAT version they have validated and re-run their own rule tests when the target types change, since the library cannot do that check for them.
Editorial conclusion
Adopt microsoft/OAT if you have C# objects and want the checks over them expressed as data (a Rule with an Expression and a list of Clauses) instead of compiled conditionals, and if you are willing to write a custom Operation delegate for anything the built-in operations do not cover. Do not adopt it if you need a documented, versioned rule schema for non-C# consumers, or if you need scripting in rules: that path requires the separate Microsoft.CST.OAT.Scripting package and the README does not state which script language it accepts. Before committing, verify three things: that the built-in Operation set covers the field types you actually inspect, that the NuGet package Microsoft.CST.OAT resolves for your target framework, and that your rules survive a round trip through the serialization you plan to store them in, which the README does not describe.
Frequently asked questions
What is microsoft/OAT?
Object Analysis Toolkit is a C# library that applies Rule objects to arbitrary C# objects, where each Rule has a target, an int Severity, a boolean Expression and a list of Clauses. The README calls it a rules driven metaprogramming engine.
How do I get microsoft/OAT?
It is available as a library on NuGet as Microsoft.CST.OAT. The README notes that using C# scripts in rules additionally requires the Microsoft.CST.OAT.Scripting package.
What is the difference between Analyze and GetCaptures in microsoft/OAT?
Analyze returns the rules that apply to the target object. GetCaptures returns captured clause results, which the README describes as clauses capturing the result of their operation to be returned with the applied Rule.
Can I extend the operations microsoft/OAT supports?
Yes. The README states that the Operation set can be expanded with delegates, and that the object types supported by existing operations can also be expanded with delegates. The wiki has a page documenting each delegate.
What licence does microsoft/OAT use?
The repository records MIT, with LICENSE.txt at the root. Contributions are handled through Microsoft's Contributor License Agreement process, which the README says a bot checks on pull requests.