Open source · MIT · .NET 10

Your agent knows XAF.
It has never seen your app.

One command changes that.

An agent that has read every page of the DevExpress documentation still does not know that your Invoice total is calculated from its lines, that ApproveController refuses to run when the period is closed, or that three columns were hidden in the Model Editor and appear in no C# file at all.

It will confidently invent all three. That gap is not solvable by better prompting — it is solvable by reading the code.

The difference, in one line

Same code.
Two very different answers.

A real attribute from a real XAF entity. Ask an agent what it does with and without the extraction, and the gap stops being abstract.

Order.cs MyApp.Module / BusinessObjects / Order.cs
[DefaultClassOptions]public class Order : XPCustomObject{    [Association("Customer-Orders")]

Without the extraction

“It filters the customer lookup. Customer probably has an active flag, so I'll write IsActive = True.”

Confident. Fluent XAF. Wrong — that property does not exist.

With the extraction

“Filters the Customer lookup to unblocked customers. IsBlocked is a bool on Customer, and this is XAF criteria syntax — neither SQL nor a C# lambda — evaluated by the database.”

Read from your source: the property, its type, and the entity it belongs to.

    [DataSourceCriteria("IsBlocked = False")]    public Customer Customer { get; set; }     [PersistentAlias("Lines.Sum(LineTotal)")]    public decimal Total => /* calculated in the database */}

Where this fits

DevExpress teaches the framework.
This teaches your application.

These compose. Install the official skills for how XAF works, keep the documentation server for the official reference, and add this for the one thing neither of them can know.

Three kinds of knowledge an agent needs about an XAF codebase Two are already solved by DevExpress tooling and drawn in grey. The third — what your own application does — is the gap this project fills, drawn in colour. Three things an agent needs to know · two are already solved How XAF works Controllers, actions, views, validation, security, the model. The framework, in general. DevExpress agent-skills What the docs say Every published page, exact API signatures, official guidance and examples. DevExpress Docs MCP What YOUR app does Your 19 entities. The rule that blocks approval. The columns hidden in the Model Editor. Nothing else can know this XAF Logic Explainer reads your source with Roslyn Install all three. They answer different questions.
An agent with the first two writes flawless XAF against entities you do not have.
Reads

Entities and relationships

Properties, types, associations, aggregation, and the XAF attributes that give them meaning. XPO and EF Core, detected from your using statements.

Reads

Controllers and actions

Every action, its target criteria, and the C# that actually runs when someone presses the button.

Reads

Rules and the Model Editor

Validation with its messages, conditional appearance, calculated properties — and the .xafml customizations that exist in no C# file.

How extraction works Source files are parsed as syntax by Roslyn, never compiled, producing a model that is rendered to agent files, an MCP server, or Markdown. Your source is read, never built *.cs *.xafml Roslyn syntax trees only never compiled Extracted model entities · actions · rules navigation · .xafml AGENTS.md · CLAUDE.md MCP server Markdown · JSON Because nothing is compiled, it works on a branch that does not build — which is often exactly when you need to know what the application does.
No DevExpress licence is needed to run any of this: the analyzer never references a DevExpress assembly.

The part nobody reads

An XAF application keeps
its secrets outside the classes.

Read every business object in an XAF solution and you will still be wrong about it. Some of what the application does is not in C# at all, and the rest is in files nobody opens when they are trying to understand a domain.

Screens that ignore their type

A string that renders as a barcode scanner. The custom editor lives in the platform project, beside the module — so nobody reading the business objects ever meets it, and neither does an agent.

Behaviour in JavaScript

The file the editor cannot work without, in neither C# nor XML. It is why a control breaks when somebody renames an asset, and why nothing in the codebase explains it.

Editors changed at run time

There is no custom class to find: a controller reaches into a built-in editor's component model. Nothing on the entity, and nothing in the Model Editor, mentions it.

Migrations that ran once

A block guarded by CurrentDBVersion ran on somebody's production database and never again. Reading today's code cannot recover it — so an agent asked why a column holds what it holds will invent a reason.

The custom editors section: a barcode scanner property editor, what it renders, the alias XAF matches on, its base type, and the JavaScript file it depends on — followed by a table of built-in editors reconfigured at run time by a controller.
Read from the platform project. The alias constant is declared in the module and resolved across the solution, because reading either project alone resolves nothing.
The migrations section: two version-gated updater blocks, each with the version it upgrades to, the schema phase it ran in, the condition, the methods it calls and the code itself.
Including the comment above the block — usually the only surviving record of why, and the question anyone reading a migration actually has.

The output

An AGENTS.md is read on every request.
So most of it isn't in there.

That file is prepended to every question an agent answers in your repository — its size is a tax paid forever. Seventy kilobytes of entity detail there would crowd out the thing the user actually asked.

So the output is tiered.

What a full dump costs an agent's context on every request Putting all documentation in AGENTS.md consumes most of the context window before the user has asked anything. Tiering leaves that room free. Every request the agent answers in your repository Everything in AGENTS.md the question application documentation · every entity, every handler Paid on every request, forever — before anyone has asked anything. Tiered index room for the question, the files being discussed, and the answer detail · opened only when a question needs it ~11 KB of 72
Roughly to scale, against a modest context budget. The index is the part that changes an answer; the rest is reference material, and reference material can be looked up.

The most valuable part is the smallest. The index opens with ground rules — which ORM this application uses and which APIs therefore do not exist in it, that the inventories are complete so anything absent genuinely is, and that some behavior lives in XML rather than in code.

CLAUDE.md and .github/copilot-instructions.md are written too. Anything you added by hand survives regeneration, and regenerating twice produces identical bytes.

Live, not a snapshot

Or let the agent
ask questions directly.

A generated file is a snapshot. The MCP server is a connection: seven tools your agent calls against the source while you are still changing it, so it cannot go stale.

xaf_overview

What this application is, and the complete list of everything in it.

xaf_entity

Every property, relationship, rule and calculation on one entity.

xaf_controller

What an action does — including the C# that runs when it fires.

xaf_search · xaf_rules · xaf_model · xaf_refresh

Find a business term, list what the app enforces, read the Model Editor, re-read the source.

Ask for something that isn't there, and the answer is the useful one:

There is no entity called 'PurchaseOrder' in this application.
This is the complete list of 19 entities, extracted from the whole source tree: …
If the user expects 'PurchaseOrder' to exist, it has not been created yet.

A bare “not found” invites an agent to assume it looked in the wrong place and invent the type anyway. Extraction reads the whole tree, which is what makes the stronger claim true.

And for the person who inherits it

Most teams have never seen
their own domain model.

It exists as association attributes scattered across twenty files, and the map of it lives in one person's head — which is exactly the knowledge that leaves when they do.

The domain model of a sample XAF application. Hovering an entity dims everything it does not touch, leaving only its own relationships lit.
Real output. Hover an entity and everything it does not touch fades; purple means deleting the parent deletes the child.

xaflogic explain writes one self-contained HTML file — no server, no build step, no request to the network. It opens from an email attachment on a machine with no internet, which is how handovers actually happen.

Alongside the map: every entity and what each property is, every action with the code it runs, validation with the message the user will actually see, and an index of every criteria expression in the application — a dialect that is neither SQL nor C# and is otherwise collected nowhere.

An entity card: every property with its type, which ones are calculated and the expression behind each, and the relationships with the ones whose parent owns the child marked as owned.
Purple is anything computed rather than stored — the properties that have no column and cannot be searched for in the database.
The criteria index: every criteria expression in the application in one table, each with the attribute and entity it came from.
Appearance rules, validation and lookup filters, collected from attributes spread across the source — the working examples an agent needs to write a criteria string that parses.

Optional, for licensees

Tell your code apart
from DevExpress's.

Reading source alone leaves one question unanswerable: is DeleteObjectsViewController something your team wrote, or something DevExpress ships? xaflogic catalog build reads your own installation and answers it.

~850
framework types
50
assemblies read
0
committed to your repo

“This extends built-in behavior”

A controller deriving from DeleteObjectsViewController is changing how deletion works application-wide, not adding a feature beside it.

“This attribute is yours”

An attribute in neither XAF nor .NET was invented by your team — its meaning lives in your codebase and in no documentation anywhere.

Install

Two minutes.

A .NET global tool. No account, no API key, no server.

terminal
$ dotnet tool install -g XafLogicExplainer.Cli # Write the context files at your solution root$ xaflogic agents --project "C:\MySolution\MyApp.Module"  AGENTS.md CLAUDE.md .github\copilot-instructions.md+ 7 detail files in .xaflogic/ # Ask your agent something only this codebase could answer. 

Prefer the agent to query live? Install the plugin:

claude code
/plugin marketplace add peopleworks/XAFLogicExplainer/plugin install xaf-logic-explainer@peopleworks-xaf # Pair it with the official DevExpress skills:/plugin marketplace add DevExpress/agent-skills/plugin install dx-xaf@DevExpress-agent-skills