Incremental 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.
- 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
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.5", 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 --yesThe 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)
If you prefer not to use Igniter, you can configure Assay manually:
- Add Assay to your dependencies:
def deps do
[
{:assay, "~> 0.5", 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).
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
# 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]
]
]mix assay
mix assay --print-config
mix assay --format github --format sarif
mix assay --no-compile # skip compilation (project must already be compiled)Exit codes: 0 (clean), 1 (warnings), 2 (error).
mix assay.watchRe-runs incremental Dialyzer on file changes and streams formatted output.
mix assay.daemonSpeaks JSON-RPC over stdio. Supported methods:
assay/analyze– run incremental Dialyzerassay/getStatus,assay/getConfig,assay/setConfigassay/shutdown
mix assay.mcpImplements 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.
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.
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 assayTo make this permanent, add it to your shell configuration file (e.g., ~/.zshrc):
ulimit -n 4096mix test– unit tests (including daemon + MCP simulations)mix credo– linting/style checksmix format– formattermix assay.watch– dogfooding watch mode on the library itself
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.