
Watch your Coverage
Zero-dependency Elixir coverage tool built for AI-assisted development. Wraps Erlang's :cover with smart defaults, function-level ignores, and a structured markdown report designed to be consumed directly by AI coding agents.
Why Six
Erlang's :cover counts every executable line - including defmodule, use, alias, and other boilerplate that nobody considers "untested code." It also has no concept of ignoring specific functions or code blocks, and its output is designed for humans reading a terminal, not agents reading a file.
Six fixes all of that: smart defaults that exclude structural declarations, @six :ignore for function-level exclusions, comment directives for block-level control, and a structured markdown report at .six/coverage.md that tells an AI agent exactly which functions have untested branches - with source snippets and context. Zero dependencies beyond OTP.
Installation
# mix.exs
def project do
[
app: :my_app,
test_coverage: [tool: Six],
# ...
]
end
def cli do
[preferred_envs: [six: :test, "six.detail": :test, "six.html": :test]]
end
defp deps do
[{:six, "~> 0.1", only: :test}]
endUsage
# Run tests with coverage (terminal table + agent report)
mix test --cover
# Or use the mix task directly
mix six
mix six --threshold 90
mix six --minimum-coverage 85
mix six --skip generated/ --skip _pb.ex
# Source-level detail view
mix six.detail
mix six.detail --filter auth
# HTML report
mix six.html
mix six.html --open
This produces two things:
- A terminal summary table (sorted worst-first)
.six/coverage.md- a structured report an AI agent can read and act on
Guides
- Reading the Output - understanding the terminal table, columns, and colors
- Threshold vs Minimum Coverage - reporting targets vs enforcement floors
- AI Integration - the agent report, Claude Code slash command, and coverage-driven test writing
- GitHub Actions - CI setup, failing on low coverage, and partitioned suites
- Custom Formatters - implementing the
Six.Formatterbehaviour
Ignoring code
Three mechanisms, from automatic to explicit:
Default pattern filters
Lines matching these patterns are automatically excluded from coverage - no configuration needed:
defmodule, defprotocol, defimpl, defrecord, defdelegate, defstruct, defexception, @moduledoc, @doc, @impl, @behaviour, @callback, use, import, alias, require, plug, end
Function-level attribute
Add use Six to a module and tag functions with @six :ignore:
defmodule MyApp.CoverBridge do
use Six
@six :ignore
def start_cover do
# Can't be tested during a coverage run
:cover.start()
end
def normal_function do
# This is still covered
:ok
end
enduse Six at the top of a file signals that the module has coverage exclusions - you know to look for @six :ignore tags. The attribute applies to the immediately following def/defp/defmacro/defmacrop, even with @doc or @impl in between.
Comment directives
For quick one-offs where you don't need use Six:
# six:ignore:next
def admin_only, do: System.halt(1)
# six:ignore:start
def debug_dump do
# Everything in this block is excluded
end
# six:ignore:stopDirective comments must be standalone comment lines. Six will not treat strings, heredocs, docs, or trailing inline comments that happen to contain six:ignore:* as coverage directives.
Configuration
# config/test.exs
config :six,
# Additional patterns to ignore (beyond defaults)
ignore_patterns: [
~r/^\s*@type\s/,
~r/^\s*defoverridable\s/
],
# Set to false to ONLY use your patterns, not the built-in defaults
default_patterns: true,
# Fail CI if coverage drops below this
minimum_coverage: 85.0,
# File patterns to skip entirely
skip_files: [
~r/lib\/my_app\/generated\//,
~r/_pb\.ex$/
],
# Output directory (default: .six)
output_dir: ".six",
# Formatters to run (default: terminal + agent)
formatters: [Six.Formatters.Terminal, Six.Formatters.Agent, Six.Formatters.HTML]At runtime you can also override:
mix six --threshold 90
mix six --minimum-coverage 85
mix six --skip generated/ --skip _pb.ex
Merging partitioned coverage
For CI setups that split tests across machines:
# Each partition exports its coverage data:
MIX_TEST_PARTITION=1 mix test --cover --export-coverage p1
MIX_TEST_PARTITION=2 mix test --cover --export-coverage p2
# Merge and generate report:
mix six --import-cover cover
Acknowledgments
Six is built on top of Erlang's :cover and is inspired by ExCoveralls and Coverex - thank you!
License
Copyright (c) 2026 Thomas Athanas
Licensed under the MIT License.