Introducing Clara Rules Explorer

Analyzing and Visualizing the Session Dependency Graph

Jun 23, 2026

Introduction

Maintaining and understanding large production rule systems built with Clara Rules can be a challenge. Tracing the dependencies and relationships between rules and queries is important to keeping the system maintainable. It is useful to be able to trace this rulebase dependency graph statically. Additionally, it is useful to overlay an active working memory state directly onto that graph.

I have created a project to address this concern called Clara Rules Explorer. This is an experimental tool composed of a Clojure HTTP server layer and a SvelteKit UI designed to introspect rulebase structures, map dependency links, and visualize runtime working memory state. You can try a live interactive static demo of the tool at metasimple.org/clara-rules-explorer.


The Architecture

The project is structured into two main components:

  1. Introspection Server (server/):
  1. Visual Explorer UI (ui/):

Introspection Challenge: RHS Opaqueness

In Clara Rules, the Left-Hand Side (LHS) of a rule is highly structured. The Clara compiler parses the LHS conditions to construct the Alpha and Beta join nodes of the Rete network. This structured layout makes it straightforward to inspect what fact types a rule matches or joins.

However, the Right-Hand Side (RHS) is unstructured. It is arbitrary Clojure code executed when a rule fires:

(defrule process-customer-status
  [Customer (= ?id id) (= :premium tier)]
  [?order <- Order (= ?id customer-id) (= :pending status)]
  =>
  (insert! (map->Discount {:order-id (:id ?order) :percentage 10}))
  (retract! ?order))

To a static analysis tool, the Clojure expression inside the RHS is just an unstructured list of forms. Because Clojure is dynamic, determining exactly what fact types a rule’s RHS might insert or retract is statically undecidable. We might see (insert! x) where x is a variable bound elsewhere, or the insertion might happen inside nested helper functions.

Without knowing what fact types are inserted or retracted by the RHS of each rule, we cannot determine the dependency links between rules. We cannot answer the important question: Which rules produce the facts that satisfy this other rule’s conditions?


Bridging the Gap with Out-of-Band Annotations

Clara Rules Explorer introduces an out-of-band annotation system that lets you declare the missing metadata. The server combines this metadata with static compiler analysis to construct a complete dependency graph.

Annotations can be declared in two ways:

Path A: In-Code Rule :props Map

You can attach metadata directly to the rule definition using custom :props keys:

(defrule process-customer-status
  {:clara-rules/insert-types [my.app.Discount]
   :clara-rules/retract-types [my.app.Order]
   :clara-rules/notes "Processes premium order discounts."}
  [Customer (= ?id id) (= :premium tier)]
  [?order <- Order (= ?id customer-id) (= :pending status)]
  =>
  (insert! (map->Discount {:order-id (:id ?order) :percentage 10}))
  (retract! ?order))

Note: I typically advise against explicit retractions in favor of letting the Truth Maintenance System (TMS) keep working memory state logically consistent automatically; see my previous post for more details.

Path B: Sidecar EDN File

If you cannot or do not want to modify existing production rule files, you can define annotations in a sidecar EDN file. This is loaded by the HTTP server at startup and can be reloaded at runtime:

{"my.app/process-customer-status"
 {:clara-rules/insert-types [my.app.Discount]
  :clara-rules/retract-types [my.app.Order]
  :clara-rules/notes "Processes premium order discounts."}}

The server resolves these annotations using clara.server.tools.graph.annotations/resolve-annotations, merges them with any existing :props metadata, and exposes them via the /v1/analysis and /v1/rules/:fq-name endpoints.


Mapping Working Memory State

While introspecting the static rulebase structure is useful on its own, connecting it to the active working memory state provides far more value. At runtime, we need to see what facts currently reside in working memory and trace how those active instances map back to the Rete network.

The Clojure server’s clara.server.tools.graph.memory namespace handles analyzing and snapshotting the session memory. When a session is active, it runs an inspection and groups facts by their types, mapping them to their:

This bridges the gap between static topology and runtime execution, letting you trace how a specific fact propagated through the Rete network.


The UI and Graceful Fallbacks

A central design goal for both the analysis server and the explorer UI is that they must remain functional even when a rulebase is only partially annotated. The server tracks rules whose RHS appears to call insert! or retract! but lack matching annotations, flagging them as :unresolved via the /v1/analysis endpoint:

{
  "rule": "my.app/process-customer-status",
  "reason": "RHS likely contains insertion/retraction calls but no :clara-rules/insert-types or :clara-rules/retract-types declared.",
  "hint": "Add :clara-rules/insert-types to the rule's properties map or a sidecar annotation file."
}

In the UI, these rules are flagged with warning badges, prompting the rule author to track down what is missing and declare the necessary metadata.


Future Directions: Automating Metadata

Manually maintaining annotations can become a chore. The out-of-band annotation design is specifically intended to act as an integration layer for automated metadata generation:

  1. Deterministic Rulebase Analysis: Future updates to the server-layer (or to the clara-rules compiler itself) could incorporate macro-expansion analysis or static code tracing to automatically infer the types of simple insertions.
  2. Agentic Code Analysis: For complex or dynamic rules where deterministic tools fall short, we can employ modern LLM coding agents to analyze the Clojure rules, inspect their RHS forms, and write the sidecar EDN annotations.

Conclusion

By combining static rulebase network analysis with a flexible, out-of-band annotation system, Clara Rules Explorer makes it possible to visualize the complex web of rule and query dependencies and active working memory.

The project is available on GitHub at mrrodriguez/clara-rules-explorer, and a live interactive static demo is hosted at metasimple.org/clara-rules-explorer. It is in an experimental state, but the core patterns for visual dependency tracing and runtime introspection are already showing promising results.