Hamburger Cross Icon
Elixir Project Guardrails - Lunar Policy for Devex Build And Ci

Elixir Project Guardrails

Policy Beta Devex Build And Ci

Enforce Elixir-specific project standards including mix manifest presence, Elixir version requirement, lockfile commit, test directory layout, Credo/Dialyzer configuration, and umbrella app detection.

Add 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.

Guardrail

mix-project-exists

Ensures the project has a mix.exs file. Required for all Elixir projects managed with Mix.

mix.exs elixir project mix manifest
View Guardrail
Guardrail

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.

elixir version version requirement mix.exs
View Guardrail
Guardrail

dependencies-locked

Ensures mix.lock is committed for reproducible dependency resolution. Without a lockfile, builds can pull different Hex versions over time.

mix.lock lockfile reproducibility hex
View Guardrail
Guardrail

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.

test/ exunit testing test layout
View Guardrail
Guardrail

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.

credo dialyzer dialyxir static analysis code quality
View Guardrail
Guardrail

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.

umbrella apps monorepo elixir umbrella
View Guardrail

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
1
Integrations Gather Data
Collectors extract metadata from code, CI pipelines, tool outputs, and scans
2
{ } Centralized as JSON
All data merged into each component's unified metadata document
3
Guardrails Enforce Standards This Policy
Real-time feedback in PRs and AI workflows

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 GitHub

Elixir 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

  1. Run mix new <project-name> to initialize a new Elixir project
  2. Ensure mix.exs is at the project root

elixir-version-constraint-set

  1. Open mix.exs and find the project/0 function
  2. Add or update elixir: "~> 1.15" (or desired minimum) to the keyword list
  3. Example:
    def project do
      [
        app: :my_app,
        version: "0.1.0",
        elixir: "~> 1.15",
        ...
      ]
    end
    

dependencies-locked

  1. Run mix deps.get to fetch dependencies
  2. Commit the resulting mix.lock to version control
  3. Ensure mix.lock is not in .gitignore

test-directory-exists

  1. Create a test/ directory: mkdir test
  2. Add a test helper: touch test/test_helper.exs with ExUnit.start()
  3. Add at least one test file under test/

credo-or-dialyzer-configured

  1. Add Credo: {:credo, "~> 1.7", only: [:dev, :test], runtime: false} to deps
  2. Run mix credo.gen.config to create .credo.exs
  3. Or add Dialyzer: {:dialyxir, "~> 1.4", only: [:dev], runtime: false} to deps
  4. Run mix dialyzer to generate PLTs. The policy also passes if mix dialyzer is 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.

View Repository

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.

Works with any process
check AI agent rules & prompt files
check Post-mortem action items
check Security & compliance policies
check Testing & quality requirements
Automate Now
Paste your AGENTS.md or manual process doc and get guardrails in minutes
Book a Demo