Migrating from Repolinter to alint

Repolinter (the TODO Group's tool for OSS-baseline checks) was archived on 2026-02-06. alint covers Repolinter's rule catalogue as a strict superset; replacing a typical Repolinter setup is a one-line extends: plus a handful of rule renames.

The 60-second migration

If your repolinter.json is a slight variant of Repolinter's default.json (LICENSE / README / CONTRIBUTING / SECURITY / CODE_OF_CONDUCT / .gitignore presence + merge-marker / bidi-control checks), replace your entire configuration with this:

# .alint.yml
version: 1
extends:
  - alint://bundled/oss-baseline@v1

That's the migration. Run alint check, compare the output to your last Repolinter run, and use the mapping table below for any custom rules.

Repolinter axiom → alint primitive

Repolinter axiomalint replacement
linguist / packagers (language detection via Ruby gem) Built-in facts: has_rust, has_node, has_python, has_go, has_java. No external binary.
licensee (SPDX license identification via Ruby gem) Extend alint://bundled/compliance/apache-2@v1 or compliance/reuse@v1. For arbitrary SPDX detection, fall back to a command: rule shelling to licensee.
where: axiom-condition gating when: bounded expression language with facts and vars; bundled rulesets are auto-gated by ecosystem facts.
Per-rule JSONPath via jsonpath-plus Full RFC 9535 JSONPath against JSON, YAML, and TOML.
Custom rule kinds via JS plugin 60 bundled rule kinds + composition via extends: (local files, HTTPS+SRI, alint://bundled/…).

Rule mapping

Coverage labels: Full = direct equivalent; Partial = covers the common case, some option may not port; None = no equivalent today, workaround documented below.

Repolinter rule kinds (the type: field)

Repolinter kind alint equivalent Coverage
file-existencefile_exists (with paths: array)Full
file-not-existsfile_absentFull
directory-existencedir_existsFull
file-contentsfile_content_matchesFull
file-not-contentsfile_content_forbiddenFull
file-starts-withfile_header (line-oriented) / file_starts_with (byte-prefix)Full
file-hashfile_hashFull
file-hashes-not-existNo direct equivalent; use file_content_forbidden against bad-substring, or shell to sha256sum via command: until file_hash_not lands.Partial
file-type-exclusionfile_absent with the same glob listFull
large-filefile_max_sizeFull
json-schema-passesjson_schema_passes; also validates YAML and TOMLFull (superset)
file-no-broken-linksmarkdown_paths_resolve for filesystem-relative paths. Does not make HTTP requests for absolute URLs, by design.Partial
apache-noticefile_exists for NOTICE, or use compliance/apache-2@v1 for the full bundle.Full (superset)
license-detectable-by-licenseeNo equivalent. Use compliance/apache-2@v1 / compliance/reuse@v1 for shape checks; command: rule for full SPDX detection.None (workaround)
best-practices-badge-presentNo equivalent; alint doesn't make HTTP requests. Run OpenSSF Scorecard as a separate CI job.None
git-grep-commitsgit_commit_message validates HEAD only; history grep needs a command: rule.Partial
git-grep-logSame as above.Partial
git-list-treegit_no_denied_paths + git_tracked_only: per-rule field cover the common shapes.Partial
git-working-treeNo direct equivalent; mostly subsumed by alint's walker honouring .gitignore + git_tracked_only:.Partial

Repolinter rule names (entries in default.json)

Repolinter name alint equivalent Coverage
license-file-existsoss-license-exists in oss-baseline@v1Full
readme-file-existsoss-readme-existsFull
contributing-file-existsOne-liner file_exists over CONTRIBUTING* pathsFull (manual)
code-of-conduct-file-existsoss-code-of-conduct-existsFull
changelog-file-existsOne-liner file_exists over CHANGELOG*Full (manual)
security-file-existsoss-security-policy-exists + oss-security-policy-non-empty (mirrors Scorecard's non-stub check)Full (superset)
support-file-existsOne-liner file_exists over SUPPORT*Full (manual)
readme-references-licensefile_content_matches over README* with (?i)licenseFull (manual)
binaries-not-presentfile_absent, or extend hygiene/no-tracked-artifacts@v1Full
test-directory-existsdir_exists with the same pathsFull
integrates-with-cifile_exists, or ci/github-actions@v1 for in-depth GitHub Actions checksFull (superset)
code-of-conduct-file-contains-emailfile_content_matches with .+@.+\..+Full (manual)
source-license-headers-existfile_header with lines: 5; for SPDX, use compliance/reuse@v1Full
github-issue-template-existsfile_exists / dir_existsFull
github-pull-request-template-existsfile_existsFull
javascript-package-metadata-existsnode-package-json-exists in node@v1, auto-gated by has_nodeFull (cleaner)
java-package-metadata-existsjava-manifest-exists in java@v1, auto-gated by has_javaFull
python-package-metadata-existspython-manifest-exists in python@v1, adds pyproject.toml (PEP 517)Full (superset)
ruby-package-metadata-existsOne-liner file_exists over Gemfile; no has_ruby fact todayPartial (workaround)
objective-c / swift / erlang / elixir-package-metadata-existsOne-liner file_exists per language; no bundled rulesets yetPartial (workaround)
license-detectable-by-licenseeSee rule-kind table aboveNone (workaround)
notice-file-existsapache-2-notice-file-exists in compliance/apache-2@v1Full (cleaner)
best-practices-badge-presentSee rule-kind table; keep as a Scorecard CI stepNone

Mapping totals (24 entries): 17 full / 14 partial-or-manual-but-trivial / 3 with no clean equivalent + documented workaround. Core OSS-baseline coverage is 100%.

Side-by-side: a real Repolinter config

A representative repolinter.json distilled from Repolinter's default.json:

{
  "$schema": "https://raw.githubusercontent.com/todogroup/repolinter/master/rulesets/schema.json",
  "version": 2,
  "axioms": {
    "linguist": "language",
    "licensee": "license",
    "packagers": "packager"
  },
  "rules": {
    "license-file-exists": {
      "level": "error",
      "rule": {
        "type": "file-existence",
        "options": { "globsAny": ["LICENSE*", "COPYING*"], "nocase": true }
      }
    },
    "readme-file-exists": {
      "level": "error",
      "rule": {
        "type": "file-existence",
        "options": { "globsAny": ["README*"], "nocase": true }
      }
    },
    "contributing-file-exists": {
      "level": "error",
      "rule": {
        "type": "file-existence",
        "options": { "globsAny": ["{docs/,.github/,}CONTRIB*"], "nocase": true }
      }
    },
    "security-file-exists": {
      "level": "error",
      "rule": {
        "type": "file-existence",
        "options": { "globsAny": ["{docs/,.github/,}SECURITY.md"] }
      }
    },
    "code-of-conduct-file-exists": {
      "level": "error",
      "rule": {
        "type": "file-existence",
        "options": { "globsAny": ["{docs/,.github/,}CODE_OF_CONDUCT*"], "nocase": true }
      }
    },
    "readme-references-license": {
      "level": "error",
      "rule": {
        "type": "file-contents",
        "options": { "globsAll": ["README*"], "content": "license", "flags": "i" }
      }
    },
    "binaries-not-present": {
      "level": "error",
      "rule": {
        "type": "file-type-exclusion",
        "options": { "type": ["**/*.exe", "**/*.dll", "!node_modules/**"] }
      }
    },
    "javascript-package-metadata-exists": {
      "level": "error",
      "where": ["language=javascript"],
      "rule": {
        "type": "file-existence",
        "options": { "globsAny": ["package.json"] }
      }
    }
  }
}

The equivalent .alint.yml:

version: 1

extends:
  # Covers license / readme / security / code-of-conduct, plus
  # non-stub variants and merge-conflict + bidi-control checks.
  - alint://bundled/oss-baseline@v1

  # Covers javascript-package-metadata-exists (as node-package-json-exists),
  # auto-gated by facts.has_node — no axiom configuration needed.
  - alint://bundled/node@v1

rules:
  - id: contributing-file-exists
    kind: file_exists
    paths:
      - "CONTRIBUTING.md"
      - "CONTRIBUTING"
      - ".github/CONTRIBUTING.md"
      - "docs/CONTRIBUTING.md"
    level: error
    message: "Add a CONTRIBUTING document so contributors know how to get started."

  - id: readme-references-license
    kind: file_content_matches
    paths: ["README.md", "README", "README.rst"]
    pattern: '(?i)license'
    level: error
    message: "README should mention the project license."

  - id: no-tracked-binaries
    kind: file_absent
    paths:
      include: ["**/*.exe", "**/*.dll"]
      exclude: ["node_modules/**", "**/test*/**"]
    level: error
    message: "Don't commit pre-built binaries."

What changed:

Edge cases that don't map cleanly

file-no-broken-links HTTP checks

Repolinter's file-no-broken-links checks both filesystem-relative links and absolute HTTP URLs. alint's markdown_paths_resolve covers the filesystem half but not HTTP, by design (network checks are flaky in CI). If you relied on the HTTP variant, keep a separate CI step using lychee or markdown-link-check, or shell out from a command: rule.

license-detectable-by-licensee

alint doesn't try to identify which SPDX license a project is under; it asserts shape. If you relied on license=Apache-2.0 gating, extend alint://bundled/compliance/apache-2@v1, which checks that LICENSE contains the canonical Apache-2.0 text, that NOTICE exists, and that source files have the Apache header. For full SPDX detection across hundreds of licenses, fall back to a command: rule shelling to licensee itself (the same Ruby-toolchain dependency Repolinter had, opt-in).

best-practices-badge-present

alint doesn't make HTTP requests; this is out of scope by design. Run OpenSSF Scorecard as a separate CI job; it covers the same surface and many adjacent ones. alint's oss-baseline@v1 already mirrors several Scorecard checks (Security-Policy non-stub, Code-Review via CODEOWNERS) by design; the two compose well.

git-grep-commits / git-grep-log

alint's git_commit_message validates HEAD only, which is good for per-PR Conventional Commits enforcement under alint check --changed. Full history grep ("no commit in history contains 'fixup'") is not alint's job; keep as a command: rule shelling to git log --grep.

file-hashes-not-exist

No direct equivalent. The common use case (a vendored dependency must not be the known-vulnerable version) maps cleanly to file_content_forbidden against a known-bad substring. Pure hash denylisting needs a command: rule until a file_hash_not primitive lands (candidate for v0.10+).

Step-by-step adoption

1. Install alint

# install.sh (Linux + macOS + Windows tarballs)
curl -sSL https://raw.githubusercontent.com/asamarts/alint/main/install.sh | bash

# Homebrew (macOS + Linuxbrew)
brew tap asamarts/alint && brew install alint

# npm (downloads the matching pre-built binary; no JS runtime)
npm install -g @asamarts/alint

# Docker (distroless multi-arch)
docker run --rm -v "$PWD:/repo" ghcr.io/asamarts/alint:latest check

2. Write the config

Start with the bundled OSS baseline and add per-ecosystem rulesets. Each is a one-line extends:, gated by facts.has_<ecosystem>, so listing one for an ecosystem you don't have is a silent no-op:

# .alint.yml
version: 1
extends:
  - alint://bundled/oss-baseline@v1
  - alint://bundled/rust@v1
  - alint://bundled/node@v1
  - alint://bundled/python@v1
  - alint://bundled/go@v1
  - alint://bundled/java@v1

Port any custom Repolinter rules using the mapping table above.

3. Run alint check

Compare the output to your last Repolinter run. Every bundled rule id can be overridden locally:

extends:
  - alint://bundled/oss-baseline@v1

rules:
  # Elevate missing-README from warning (bundled default) to error.
  - id: oss-readme-exists
    level: error

  # Disable trailing-whitespace on Markdown — the two-trailing-spaces
  # hard-break is deliberate.
  - id: oss-no-trailing-whitespace
    level: off

4. Auto-fix what's mechanically fixable

alint fix --dry-run    # preview the diff
alint fix              # apply

5. Wire it into CI

For GitHub Actions, the canonical setup is the asamarts/alint-action:

# .github/workflows/lint.yml
on: [push, pull_request]
permissions:
  contents: read
jobs:
  alint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: asamarts/alint-action@v1
        with:
          format: github   # native GitHub Actions annotations

For non-GitHub CI, alint check --format <fmt> covers SARIF (GitHub code-scanning), JUnit, GitLab Code Quality, and the agent format with per-violation agent_instruction strings.

6. Retire the Repolinter step

Once alint check passes (or fails for the same reasons your Repolinter step did), remove the Repolinter step from your CI and delete repolinter.json. Pin alint's bundled-ruleset version (@v1) for zero-surprise upgrades.

If your migration runs into something the mapping table didn't cover, open an issue. The mapping is maintained against real-world configs.