Native Elixir linting with Credo-compatible behavior, written in Rust.
qredo runs Credo checks without the BEAM: a rule-kernel library, a
7-stage pipeline runner (selection, scope, priority, suppression, exit
status) and a qredo CLI that reads your project's .credo.exs and
prints issues with OR-combined exit codes, like mix credo.
Status: early. 120 rule kernels exist and the admitted compatibility
corpora pass; the CLI serves static configs with all 81 documented
rule-specific parameters and all five general parameters validated by schema,
including explicit nil values that select Credo defaults, and fails closed
with an explicit reason on anything else. See
ROADMAP.
Add qredo from Hex as a development dependency:
defp deps do
[
{:qredo, "~> 0.1.1", only: [:dev, :test], runtime: false}
]
endThen run it through Mix; the first invocation downloads and SHA-256 verifies the native executable for the current platform:
mix deps.get
mix qredo --strictSet QREDO_BUILD=source or run mix qredo.install --source to compile with
the pinned Rust toolchain instead. QREDO_BINARY_PATH selects an existing
binary, and QREDO_OFFLINE=1 prevents downloads.
Requires Rust 1.91.1 (pinned in rust-toolchain.toml) and no Elixir
installation for linting itself:
cargo install --path crates/qredoqredo [PATH] [--config-file FILE] [--config-name NAME] [--strict] [--min-priority N] [--mute-exit-status] [--only CHECK,...] [--ignore CHECK,...] [--format text|json] [--stale]qredo apps/my_app --strict
qredo --only IoInspect,Dbg --format json
qredo --stale # reuse cached results for unchanged filesFiles come from the config's files.included (defaulting to lib/ and
test/), minus files.excluded; build directories are never
descended into. On an unsupported configuration qredo prints the
reason and exits 2 instead of running partial analysis.
qredo suggest --stale (and list --stale) reuse cached results for
unchanged files: per-file issues are keyed by content hash, consistency
votes by per-file counts, and the global majority is recomputed from
merged counts without re-parsing cached files. The cache lives under
~/.cache/qredo/ (or $XDG_CACHE_HOME/qredo), keyed by project root
plus a fingerprint over tool version, config bytes, environment snapshot,
check list, selection and minimum priority. Any mismatch — or a flipped
consistency majority — fails open to a full run, so --stale output
always matches a fresh run.
use qredo::check_kernel;
let findings = check_kernel(
"Credo.Check.Readability.TrailingBlankLine",
"defmodule Example do\nend",
).unwrap();
assert_eq!(findings[0].line, 2);Full-pipeline runs go through integration::execute, which serves
supported configs and reports an explicit Fallback reason otherwise.
scripts/check # rustfmt, Clippy (-D warnings), testsEvery push to main runs the complete quality gate, builds five native targets
on two runners, and replaces the dev GitHub prerelease. Development asset
names include the exact Git commit consumed by a Mix git dependency.
Publishing a non-prerelease GitHub release such as v0.1.1 verifies that its
tag matches both VERSION and crates/qredo/Cargo.toml, promotes the tested
artifacts from that commit's successful push build, uploads them with
SHA256SUMS, marks the release latest, and publishes the matching Mix package
to Hex. Stable releases do not compile the native targets a second time. The
repository must define a HEX_API_KEY Actions secret with package publishing
permission.
See AGENTS.md for the contribution workflow, ARCHITECTURE.md for the design and compatibility for provenance.
MIT. Compatibility corpora derived from Credo's test suite keep their
upstream MIT license and attribution; see
compatibility. The upstream
directory additionally carries Credo's own LICENSE file.