Assay
View SourceIncremental Dialyzer for modern Elixir tooling. Assay reads Dialyzer settings
directly from your host app's mix.exs, runs the incremental engine, filters
warnings via dialyzer_ignore.exs, and emits multiple output formats suited
for humans, CI, editors, and LLM-driven tools.
Features
- Incremental Dialyzer runs via
mix assay - Watch mode (
mix assay.watch) with debounced re-analysis - JSON/CLI formatters (
text,github,sarif,lsp,ndjson,llm) dialyzer_ignore.exsfiltering with per-warning decorations- Igniter-powered installer (
mix assay.install) that configures apps/ warning_apps in the host project - JSON-RPC daemon (
mix assay.daemon) plus an MCP server (mix assay.mcp) for editor/LSP/agent integrations
Installation
Using Igniter (Recommended)
The easiest way to install Assay is using the Igniter-powered installer. First, add both Assay and Igniter to your dependencies:
def deps do
[
{:assay, "~> 0.3", runtime: false, only: [:dev, :test]},
{:igniter, "~> 0.6", optional: false}
]
endImportant: Igniter must be in your mix.exs dependencies (not optional) for the installer to work.
Then run the installer:
mix deps.get
mix assay.install --yes
The installer will:
- Detect project and dependency apps
- Configure
appsandwarning_appsin yourmix.exs - Create a
.gitignoreentry for_build/assay - Create a
dialyzer_ignore.exsfile - Optionally generate CI workflow files (GitHub Actions or GitLab CI)
Manual Installation
If you prefer not to use Igniter, you can configure Assay manually:
- Add Assay to your dependencies:
def deps do
[
{:assay, "~> 0.3", runtime: false, only: [:dev, :test]}
]
end- Add configuration to your
mix.exs:
def project do
[
# ... other config ...
assay: [
dialyzer: [
apps: :project_plus_deps, # or explicit list
warning_apps: :project # or explicit list
]
]
]
end- Create a
dialyzer_ignore.exsfile (optional):
# dialyzer_ignore.exs
[]- Add
_build/assayto your.gitignore(optional but recommended).
Configuration
Symbolic Selectors
Assay supports symbolic selectors for apps and warning_apps:
:project- All project applications (umbrella: all apps fromMix.Project.apps_paths(), single-app:Mix.Project.config()[:app]):project_plus_deps- Project apps + dependencies + base OTP libraries:current- Current Mix project app only (useful for umbrella projects):current_plus_deps- Current app + dependencies + base OTP libraries
Example Configuration
# In mix.exs
def project do
[
app: :my_app,
assay: [
dialyzer: [
# Analyze project apps + dependencies
apps: :project_plus_deps,
# Only show warnings for project apps
warning_apps: :project
]
]
]
endYou can also mix symbolic selectors with explicit app names:
assay: [
dialyzer: [
apps: [:project_plus_deps, :custom_app],
warning_apps: [:project, :another_app]
]
]Usage
One-off analysis
mix assay
mix assay --print-config
mix assay --format github --format sarif
Exit codes: 0 (clean), 1 (warnings), 2 (error).
Watch mode
mix assay.watch
Re-runs incremental Dialyzer on file changes and streams formatted output.
JSON-RPC daemon
mix assay.daemon
Speaks JSON-RPC over stdio. Supported methods:
assay/analyze– run incremental Dialyzerassay/getStatus,assay/getConfig,assay/setConfigassay/shutdown
MCP server
mix assay.mcp
Implements the Model Context Protocol (initialize, tools/list, tools/call)
and exposes a single tool, assay.analyze, which returns the same structured
diagnostics as the daemon. Requests/responses use the standard MCP/LSP framing:
each JSON payload must be prefixed with Content-Length: <bytes>\r\n\r\n.
Pretty-printing Dialyzer terms
Add erlex to your host project's deps (e.g.
{:erlex, "~> 0.2", optional: true}) and pass --format elixir to mix assay
to render Dialyzer's Erlang detail blocks as Elixir-looking maps/structs (e.g.
%Ecto.Changeset{}) while keeping plain output available when the default
text format is used.
Troubleshooting
macOS: "Too many open files" error
On macOS, Dialyzer's incremental mode opens many files in parallel, which can exceed the default open file limit. If you encounter errors related to file limits on larger projects, increase the limit before running Assay:
ulimit -n 4096 # or higher for very large projects
mix assay
To make this permanent, add it to your shell configuration file (e.g., ~/.zshrc):
ulimit -n 4096
Development
mix test– unit tests (including daemon + MCP simulations)mix credo– linting/style checksmix format– formattermix assay.watch– dogfooding watch mode on the library itself
Status
Assay currently focuses on incremental Dialyzer runs, watch mode, the Igniter installer, and daemon/MCP integrations. Future milestones include richer pass-through Dialyzer flag support, additional output formats, and expanded editor tooling.