Elixir Project Guardrails
Enforce Elixir-specific project standards including mix manifest presence, Elixir version requirement, lockfile commit, test directory layout, Credo/Dialyzer configuration, and umbrella app detection.
elixir to your lunar-config.yml:uses: github://earthly/lunar-lib/policies/elixir@v1.0.5
Included Guardrails
This policy includes 6 guardrails that enforce standards for your devex build and ci.
mix-project-exists
Ensures the project has a mix.exs file. Required for all Elixir projects managed with Mix.
elixir-version-constraint-set
Ensures the project declares an Elixir version requirement
(e.g., elixir: "~> 1.15") in mix.exs. Pinning a minimum Elixir
version prevents drift and surprises on build machines.
dependencies-locked
Ensures mix.lock is committed for reproducible dependency resolution. Without a lockfile, builds can pull different Hex versions over time.
test-directory-exists
Ensures a test/ directory exists. An explicit test dir is the
conventional layout for ExUnit. Skips on non-Elixir projects when
.lang.elixir is absent.
credo-or-dialyzer-configured
Ensures Credo or Dialyzer is configured. Credo is detected via
.credo.exs. Dialyzer is detected via {:dialyxir, ...} dep, a
dialyzer/0 block in mix.exs, or a mix dialyzer command
observed in CI. Static analysis catches bugs and enforces
consistent idiomatic Elixir.
umbrella-app-detected
Reports whether the project is an umbrella application. Informational — passes if the project is NOT an umbrella or if umbrella structure is correctly detected.
How Guardrails Fit into Lunar
Lunar guardrails define your engineering standards as code. They evaluate data collected by integrations and produce pass/fail checks with actionable feedback.
Policies support gradual enforcement—from silent scoring to blocking PRs or deployments—letting you roll out standards at your own pace without disrupting existing workflows.
Learn How Lunar Works →Required Integrations
This policy evaluates data gathered by one or more of the following integration(s).
Make sure to enable them in your lunar-config.yml.
Configuration
Configure this policy in your lunar-config.yml.
Inputs
| Input | Required | Default | Description |
|---|
Documentation
View on GitHubElixir Project Guardrails
Enforce Elixir-specific project standards including mix manifest presence, Elixir version pinning, lockfile commit, test layout, Credo/Dialyzer configuration, and umbrella detection.
Overview
This policy validates Elixir projects against best practices for mix project layout, version pinning, dependency reproducibility, testing conventions, and static analysis. All checks skip gracefully on non-Elixir projects (i.e., .lang.elixir missing).
Policies
This plugin provides the following policies (use include to select a subset):
| Policy | Description | Failure Meaning |
|---|---|---|
mix-project-exists |
Validates mix.exs exists | Project lacks a mix manifest |
elixir-version-constraint-set |
Validates elixir: "~> X.Y" in mix.exs |
Missing Elixir version requirement |
dependencies-locked |
Validates mix.lock exists | Missing dependency lockfile |
test-directory-exists |
Validates test/ directory |
No tests committed |
credo-or-dialyzer-configured |
Validates Credo or Dialyzer config | No static analysis configured |
umbrella-app-detected |
Reports umbrella app layout | — (informational) |
Required Data
This policy reads from the following Component JSON paths:
| Path | Type | Provided By |
|---|---|---|
.lang.elixir |
object | elixir collector |
.lang.elixir.mix_exs_exists |
boolean | elixir collector |
.lang.elixir.mix_lock_exists |
boolean | elixir collector |
.lang.elixir.elixir_requirement |
string | elixir collector |
.lang.elixir.test_directory_exists |
boolean | elixir collector |
.lang.elixir.credo_configured |
boolean | elixir collector |
.lang.elixir.dialyzer_configured |
boolean | elixir collector |
.lang.elixir.cicd.cmds |
array | elixir collector (additional signal for Dialyzer — mix dialyzer invocations) |
.lang.elixir.umbrella |
object | elixir collector |
Installation
Add to your lunar-config.yml:
policies:
- uses: github://earthly/lunar-lib/policies/elixir@main
on: ["domain:your-domain"] # replace with your own domain or tags
enforcement: report-pr
# include: [mix-project-exists, dependencies-locked] # Only run specific checks
Examples
Passing Example
{
"lang": {
"elixir": {
"mix_exs_exists": true,
"mix_lock_exists": true,
"elixir_requirement": "~> 1.15",
"test_directory_exists": true,
"credo_configured": true,
"dialyzer_configured": false,
"umbrella": { "is_umbrella": false }
}
}
}
Failing Example
{
"lang": {
"elixir": {
"mix_exs_exists": true,
"mix_lock_exists": false,
"elixir_requirement": "",
"test_directory_exists": false,
"credo_configured": false,
"dialyzer_configured": false,
"umbrella": { "is_umbrella": false }
}
}
}
Failure messages:
"mix.lock not found. Run 'mix deps.get' and commit mix.lock for reproducible builds.""Elixir version requirement missing in mix.exs. Add 'elixir: \"~> 1.15\"' to the project/0 block.""test/ directory not found. Create a test/ directory and add ExUnit tests.""Neither Credo (.credo.exs) nor Dialyzer detected. Add {:credo, ...} or {:dialyxir, ...} to deps for static analysis."
Remediation
mix-project-exists
- Run
mix new <project-name>to initialize a new Elixir project - Ensure
mix.exsis at the project root
elixir-version-constraint-set
- Open
mix.exsand find theproject/0function - Add or update
elixir: "~> 1.15"(or desired minimum) to the keyword list - Example:
def project do [ app: :my_app, version: "0.1.0", elixir: "~> 1.15", ... ] end
dependencies-locked
- Run
mix deps.getto fetch dependencies - Commit the resulting
mix.lockto version control - Ensure
mix.lockis not in.gitignore
test-directory-exists
- Create a
test/directory:mkdir test - Add a test helper:
touch test/test_helper.exswithExUnit.start() - Add at least one test file under
test/
credo-or-dialyzer-configured
- Add Credo:
{:credo, "~> 1.7", only: [:dev, :test], runtime: false}to deps - Run
mix credo.gen.configto create.credo.exs - Or add Dialyzer:
{:dialyxir, "~> 1.4", only: [:dev], runtime: false}to deps - Run
mix dialyzerto generate PLTs. The policy also passes ifmix dialyzeris observed running in CI even without a local config block — wiring it into your pipeline counts.
umbrella-app-detected
Informational — no remediation needed. This check surfaces whether the project is structured as an umbrella app.
Open Source
This policy is open source and available on GitHub. Contribute improvements, report issues, or fork it for your own use.
Common Use Cases
Explore how individual guardrails work with specific integrations.
Ready to Automate Your Standards?
See how Lunar can turn your AGENTS.md, engineering wiki, compliance docs, or postmortem action items into automated guardrails with our 200+ built-in guardrails.