A toolbox of reusable mise lint task scripts. Pick the ones you need — each task is independent and can be adopted on its own.
Available tasks:
| Task | Tool |
|---|---|
lint:super-linter |
Super-Linter |
lint:links |
lychee |
lint:renovate-deps |
Renovate dependency tracking |
Flint relies on two tools that each play a distinct role:
mise is a polyglot dev tool manager and task runner. In the context of flint, mise serves two purposes:
-
Installing tools. mise's
[tools]section pins exact versions of the linters each task needs (e.g.,lychee,node,"npm:renovate"). Runningmise installgives every developer and CI runner the same versions, so local runs are consistent with CI. -
Running tasks. mise downloads task scripts from this repository via HTTP, wires them into your project as local commands (
mise run lint,mise run fix), and passes flags and environment variables through to each script. You don't need to clone flint — mise fetches the scripts directly from GitHub URLs pinned in yourmise.toml.
Renovate is an automated dependency update bot.
Extending the flint Renovate preset
(default.json) is essential for any repository that uses flint — without it,
SHA-pinned flint URLs and _VERSION variables in mise.toml would never get
updated. The preset ships custom managers that detect these patterns and open
PRs to bump both flint itself and the tools it runs
(e.g., Super-Linter, lychee).
Optionally, the lint:renovate-deps task adds a second
layer: it runs Renovate locally to detect which dependencies Renovate is
tracking, compares this against a committed snapshot, and fails if they
diverge — catching cases where a dependency silently falls off Renovate's
radar.
main.
The main branch may contain breaking changes.
See CHANGELOG.md for version history.
Add whichever tasks you need as HTTP remote tasks in your mise.toml,
pinned to the commit SHA of a release tag with a version comment:
# Pick the tasks you need from flint (https://github.com/grafana/flint)
[tasks."lint:super-linter"]
description = "Run Super-Linter on the repository"
file = "https://raw.githubusercontent.com/grafana/flint/30090d5540807f330a94420ad11b57ba93eaaa84/tasks/lint/super-linter.sh" # v0.3.0
[tasks."lint:links"]
description = "Check for broken links in changed files + all local links"
file = "https://raw.githubusercontent.com/grafana/flint/30090d5540807f330a94420ad11b57ba93eaaa84/tasks/lint/links.sh" # v0.3.0
[tasks."lint:renovate-deps"]
description = "Verify renovate-tracked-deps.json is up to date"
file = "https://raw.githubusercontent.com/grafana/flint/30090d5540807f330a94420ad11b57ba93eaaa84/tasks/lint/renovate-deps.py" # v0.3.0The SHA pin ensures the URL is immutable (tag-based URLs can change
if a tag is force-pushed), and the # v0.3.0 comment tells Renovate
which version is currently pinned.
Then wire up top-level lint and fix tasks that reference whichever tasks
you adopted (add any project-specific subtasks to the depends list):
[tasks.lint]
description = "Run all lints"
depends = ["lint:super-linter", "lint:links", "lint:renovate-deps"]
[tasks.fix]
description = "Auto-fix lint issues and regenerate tracked deps"
run = "AUTOFIX=true mise run lint"See grafana/docker-otel-lgtm for a real-world example of a repository using flint. Its CONTRIBUTING.md describes the developer workflow, and its mise.toml shows how the tasks are wired up.
Runs Super-Linter via Docker or Podman. Auto-detects the container runtime (prefers Podman, falls back to Docker) and handles SELinux bind-mount flags on Fedora.
mise fetches this script from the SHA-pinned URL in mise.toml
and runs it as mise run lint:super-linter. The
SUPER_LINTER_VERSION environment variable (set in mise.toml)
controls which Super-Linter image is pulled. Renovate, via the
flint preset, opens PRs to bump both the flint script URL and the
SUPER_LINTER_VERSION value when new versions are available.
Slim vs full image: Super-Linter publishes a slim image
(slim-v8.4.0) that is ~2 GB smaller than the full image. The slim
image excludes Rust, .NET/C#, PowerShell, and ARM template linters.
Flint defaults to the slim image. To use the full image instead, set
SUPER_LINTER_VERSION to the non-prefixed tag (e.g.
v8.4.0@sha256:...) and update the Renovate depName comment
accordingly (drop the versioning override so Renovate uses standard
Docker versioning).
Flags:
| Flag | Description |
|---|---|
--autofix |
Enable autofix mode (enables FIX_* vars from the env file) |
When autofix is not enabled, all FIX_* lines are filtered out of
the env file before running Super-Linter.
Environment variables:
| Variable | Default | Required | Description |
|---|---|---|---|
SUPER_LINTER_VERSION |
— | yes | Super-Linter image tag (e.g. slim-v8.4.0@sha256:... for slim, v8.4.0@sha256:... for full) |
SUPER_LINTER_ENV_FILE |
.github/config/super-linter.env |
no | Path to the Super-Linter env file |
Checks links with lychee. By default, it runs two checks: all links (local + remote) in modified files and local file links in all files. This keeps CI fast while catching both broken remote links in changed content and broken internal links across the whole repository.
mise fetches this script and runs it as mise run lint:links.
Lychee is installed via mise's [tools] section — add
lychee = "<version>" to your mise.toml. Renovate, via the
flint preset, opens PRs to bump the flint script URL when a new
version is available.
Flags:
| Flag | Description |
|---|---|
--full |
Check all links (local + remote) in all files (single run) |
--base <ref> |
Base branch to compare against (default: origin/$GITHUB_BASE_REF or origin/main) |
--head <ref> |
Head commit to compare against (default: $GITHUB_HEAD_SHA or HEAD) |
--lychee-args <args> |
Extra arguments to pass to lychee |
<file>... |
Files to check (default: .; only used with --full) |
When running in default mode, if a config change is detected
(matching LYCHEE_CONFIG_CHANGE_PATTERN), the script falls back
to --full behavior.
Environment variables:
| Variable | Default | Description |
|---|---|---|
LYCHEE_CONFIG |
.github/config/lychee.toml |
Path to the lychee config file |
LYCHEE_CONFIG_CHANGE_PATTERN |
^(\.github/config/lychee\.toml|\.mise/tasks/lint/.*|mise\.toml)$ |
Regular expression for files whose change triggers a full link check |
Examples:
mise run lint:links # All links in modified + local links in all files (default)
mise run lint:links --full # All links in all filesVerifies .github/renovate-tracked-deps.json is up to date by
running Renovate locally and parsing its debug logs.
mise fetches this script and runs it as mise run lint:renovate-deps.
The Renovate CLI is installed via mise's [tools] section — add
node = "<version>" and "npm:renovate" = "<version>" to your
mise.toml. Renovate plays a dual role here: the flint preset
keeps the script URL up to date, while the script itself runs Renovate
locally in --platform=local mode to discover which dependencies
Renovate is tracking and compares them against a committed snapshot.
Flags:
| Flag | Description |
|---|---|
--autofix |
Automatically regenerate and update the committed file |
Environment variables:
| Variable | Default | Description |
|---|---|---|
RENOVATE_TRACKED_DEPS_EXCLUDE |
unset | Comma-separated Renovate managers to exclude (e.g. github-actions,github-runners) |
Renovate silently stops tracking a dependency when it can no longer parse the version reference (typo in a comment annotation, unsupported syntax, moved file, etc.). When that happens, the dependency freezes in place with no PR and no dashboard entry — it simply disappears from Renovate's radar.
The Dependency Dashboard catches known dependencies that are pending or in error, but it cannot show you a dependency that Renovate no longer sees at all. This linter closes that gap by keeping a committed snapshot of every dependency Renovate tracks and failing CI when the two diverge.
The lint:renovate-deps task runs Renovate locally in
--platform=local mode, parses its debug log for the
packageFiles with updates message, and generates a dependency
list (grouped by file and manager). It then diffs this against the
committed .github/renovate-tracked-deps.json:
- If they match → linter passes
- If they differ → linter fails with a unified diff showing which dependencies were added or removed
- With
--autofixflag (orAUTOFIX=trueenv var) → automatically regenerates and updates the committed file
-
A dependency disappears (e.g., someone removes a
# renovate:comment or changes a file that Renovate was matching) → CI fails, showing the removed dependency in the diff. The author can then decide whether the removal was intentional or accidental. -
A new dependency is added → CI fails because the committed snapshot is stale. Run
mise run fix(orAUTOFIX=true mise run lint:renovate-deps) to regenerate and update the file, then commit. -
Routine regeneration → After any change to
renovate.json5, Dockerfiles,go.mod,package.json, or other files Renovate scans, the linter will detect the change and require regeneration.
Lint scripts that support fixing accept an --autofix flag. Autofix
can also be enabled via the AUTOFIX=true environment variable, which
is how the fix meta-task propagates it through the dependency chain.
Check mode (default):
mise run lint # Check all linters, fail on issues
mise run lint:super-linter # Check code style, fail on issues
mise run lint:renovate-deps # Verify tracked deps, fail if out of dateFix mode:
mise run fix # Auto-fix all fixable issues
# Or run individual linters:
mise run lint:super-linter --autofix # Apply code fixes
mise run lint:renovate-deps --autofix # Regenerate tracked depsLinters that don't support autofix (like lychee link checker)
silently ignore the AUTOFIX environment variable.
Flint provides a Renovate shareable preset with custom managers that automatically update:
- SHA-pinned flint versions in
mise.toml(raw.githubusercontent.comURLs with commit SHA and version comment) _VERSIONvariables inmise.toml(e.g.,SUPER_LINTER_VERSION)
Add this to your renovate.json5:
{
extends: ["github>grafana/flint"],
}Each task expects certain config files that your repository must provide. You only need the files for the tasks you adopt:
lint:super-linter— Super-Linter env file (.github/config/super-linter.env) to select which validators to enable and whichFIX_*vars to set, plus any linter config files (.golangci.yaml,.markdownlint.yaml,.yaml-lint.yml,.editorconfig, etc.)lint:links— Lychee config (.github/config/lychee.toml) for exclusions, timeouts, remappingslint:renovate-deps— Renovate config (.github/renovate.json5) and committed snapshot (.github/renovate-tracked-deps.json)
This project uses Semantic Versioning. Breaking changes will be documented in CHANGELOG.md and will result in a major version bump.
Always pin to a specific commit SHA in your mise.toml file
URLs with a version comment (e.g., # v0.3.0). Never reference
main directly as it may contain unreleased breaking changes. To
find the commit SHA for a release tag, run
git rev-parse v0.3.0.
Releases are automated via
Release Please.
When conventional commits land on main, Release Please opens
(or updates) a release PR with a changelog.
Note: CI checks don't trigger automatically on release-please PRs because they are created with
GITHUB_TOKEN. To run CI, either click Update branch or close and reopen the PR.