clojure -J-Dguardrails.mode=:all -J-Dguardrails.enabled ... # or clojure -J-Dguardrails.mode=:pro ... # ONLY static analysis, no runtime enforcement
A static analysis tool for Clojure/ClojureScript that performs compile-time type checking and validation based on Guardrails specs. Catch type errors and spec violations during development without having to run the code.
Status: ALPHA quality. Mostly API Stable.
Documentation and nice-factors still in progress (e.g. it’s a little rough around the edges)
I was originally going to call this copilot for Guardrails when I started tinkering with this in 2020, and now obviously someone else tool that name, so I’ve renamed this project. Any stray references to copilot in this project should be read as "guardrails analyzer" instead. |
I’m still working on the work flow. So bear with me.
You have to first start a daemon which acts as the communication server.
If you clone this project, and run make Daemon.jar
.
That is an uberjard (java -jar Daemon.jar
), but you must currently run it from your home directory.
This has to be running for the checker to be able to communicate with the IDE.
Download a release from https://github.com/fulcrologic/guardrails-intellij-plugin (releases) and install it from disk
You must be using Guardrails, of course. Also, you MUST put Guardrails in either ":all" or ":pro" mode, or it won’t emit the analysis data that the analyzer needs!
You do this by adding JVM args to startup:
clojure -J-Dguardrails.mode=:all -J-Dguardrails.enabled ... # or clojure -J-Dguardrails.mode=:pro ... # ONLY static analysis, no runtime enforcement
If you add this library to your project’s development deps, you can start the checker in a REPL. Note that the checker has to reload nses as it runs to make sure it has the latest runnable specs, so you may or may not want to actually do work in that REPL. I’ve got internal code for starting the checker, but I need to finish the polish/docs.
It won’t be able to check until the code is loaded, so you should probably load your top-level entry point ns before you start the checker. That way you’ll know it’s basically ready. |
(require '[com.fulcrologic.guardrails-analyzer.checkers.clojure :as cc])
;; List the source dirs you want to be able to run checks on
(cc/start {:src-dirs ["src/dev" "src/main"]})
Now you can trigger IntelliJ commands (add kb shortcuts) for guardrails actions like "Check Namespace". E.g. press your shortcut for Run Action (i.e. CMD-SHIFT-A) and type "Check Namespace".
See ~/.guardrails/logs for logs.
Guardrails Analyzer provides REPL and IDE-integrated static analysis for Clojure code that uses Guardrails' >defn
macro and inline gspec syntax.
It analyzes your code at development-time, providing real-time feedback on type errors, spec violations, and potential issues.
The base idea is to use generators (Clojure spec or Malli) to generate data and flow it through a simulation of your code, tracking what happens, and warning when something looks fishy. Because that requires running your specs, it means we have to run a process that has your code in it, as well as the checker.
This goes beyond pure static analysis (like clj-kondo) in that it is able to find a LOT more possible problems with your actual algorithm data flow. When used with IntelliJ you can even see the flowed values on bindings in let to see what’s going on!
In order to facilitate communication between this checker and editors this project includes a daemon that runs as both an IntelliJ and LSP server.
An IntellJ Plugin already exists, and is published as a separate project.
Static Type Checking: Validates function arguments and return values against Guardrails specs without running code
Path-Based Analysis: Tracks execution paths through conditional branches for precise error reporting
IDE Integration: Language Server Protocol (LSP) support for real-time feedback in your editor
Sample-Based Validation: Uses spec generators to create test data and validate type correctness
Zero Runtime Overhead: All analysis happens at development time
Comprehensive Coverage: Supports control flow (if
, when
, cond
), higher-order functions, macros, and more
(>defn calculate-discount
[price :- number?
customer-type :- keyword?]
[number? keyword? => number?]
(if (= customer-type :premium)
(* price 0.9)
price))
The analyzer:
Parses the gspec: [number? keyword? ⇒ number?]
Generates sample values using spec generators
Traces execution through conditional branches
Validates that all paths conform to the return spec
Reports errors with specific path information
If you accidentally return a non-number on any path, you’ll get an error like:
The Return spec is number?, but it is possible to return a value like :invalid when (= customer-type :premium) → else
The analyzer tracks execution paths through your code to provide precise error reporting:
Determined Conditions: Pure predicates like (even? x)
partition samples by branch
Path Tracking: Each execution path maintains its own samples and bindings
Precise Errors: Know exactly which conditions lead to spec violations
Control Flow Support: if
, when
, cond
, and
, or
, cond→
, some→
, and more
See PATH_BASED_ANALYSIS_COMPLETE.md
for comprehensive documentation.
Analyzer (src/main/com/fulcrologic/guardrails-analyzer/analysis/
)
Multi-method dispatch system for different expression types
Function, macro, literal, and higher-order function analysis
Destructuring and conditional handling
Artifacts System (artifacts.cljc
)
Central data structure definitions using clojure.spec
Environment tracking for bindings, problems, and analysis state
Path management and sample partitioning
Checker (checker.cljc
)
Main entry point for editor integration
Gathers problems and bindings after analysis
Formats output for IDE/LSP consumption
Daemon (src/daemon/
)
Language Server Protocol implementation
HTTP server and WebSocket communication
Real-time feedback to editors/IDEs
UI Formatters (src/main/com/fulcrologic/guardrails-analyzer/ui/
)
Human-readable error messages
Binding information display
Path-based error formatting
Editor → Daemon → Checker → Analyzer → Type Checker → Formatter → Daemon → Editor
Clojure CLI tools
Node.js (for ClojureScript builds)
Java 21+
This project has a close relationship with the Guardrails library:
Guardrails provides the >defn
macro and inline gspec syntax
Guardrails Analyzer performs static analysis on code using those specs
Changes may require coordinated updates in both repositories
Core library function specs are defined in analysis/fdefs/
See the ai/
directory and root-level markdown files for detailed documentation:
CLAUDE.md
- Comprehensive project overview and architecture guide
ai/running-tests.md
- Testing guidelines
Copyright 2025, Fulcrologic, LLC All Rights Reserved
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
Ctrl+k | Jump to recent docs |
← | Move to previous article |
→ | Move to next article |
Ctrl+/ | Jump to the search field |