Setup · step 1, from your pipeline
Your codebase, drawn from your own pipeline
The scan runs in your own build pipeline (CI), on code that is already checked out there. What reaches us is the map it built — file names, the names of functions and other symbols, how they connect, and what the checks found. Never your source, never a diff, never a patch. There is no column in our database that could hold one, and a build gate fails if somebody adds a place for it.
Your project key
A scan belongs to an organisation, and the key is how your pipeline says which one it is. Signing up creates the organisation — there is nothing else to fill in.
Make an accountInstall it
One package, one dependency of its own. It reads your repository and writes a report; it never runs your code, never installs anything, and never reaches the network except to send the report here.
in your repository
npm i -D mlrepsPublish on every push to main
This is what keeps your dashboard current. It runs on the default branch rather than on pull requests on purpose — a report published from every branch would make this a picture of whichever job finished last, not of your codebase.
.github/workflows/mlreps.yml
name: MLReps on: push: branches: [main] jobs: scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: # Without this the scan reports that every file was never committed. fetch-depth: 0 - uses: actions/setup-node@v4 with: node-version: 24 - run: npm install - run: npx mlreps scan . --publish env: MLREPS_KEY: ${{ secrets.MLREPS_KEY }}Add the key as a repository secret named MLREPS_KEY. A key for publishing, which is what the card in step 1 makes — it cannot send telemetry, so a repository secret that leaks cannot start writing traffic onto your map either. The endpoint is /api/scan/v1/report, and the response to every publish is the diagnostic: what we stored, what we could not read, and what was swept out of it.
And on pull requests, if you want it
A second, separate workflow shows what a change affects on the pull request, as a check. It carries no credential of ours and sends us nothing — the analysis runs on your machine and the result is posted to your repository by your own CI token. It is the stronger arrangement of the two and it costs you the dashboard, which is why both are offered rather than one.
.github/workflows/codebase.yml
name: MLReps on: pull_request: # Without this, GITHUB_TOKEN cannot write a check run and every run ends in a 403. permissions: contents: read checks: write jobs: scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 24 - run: npm install - run: npx mlreps check . env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # On a pull request, GITHUB_SHA is a merge commit that exists nowhere in # the repository — a check run posted against it is invisible. PLATFORM_HEAD_SHA: ${{ github.event.pull_request.head.sha }}Then look at it
Every screen starts with how much of your codebase we could read — because a part we could not read must never look like a part with nothing wrong in it.
Outside GitHub Actions
Nothing above is specific to Actions beyond the check run. On GitLab, Bitbucket, Jenkins or a laptop, set these two and run npx mlreps scan . --publish.
environment
MLREPS_KEY=<your project key>
MLREPS_ENDPOINT=https://www.mlreps.comAdd --dry-run to see exactly what would be sent without sending it. A checkout with no remote is refused rather than guessed at — a scan has to be filed under a repository name, and a folder name is not one.
What the CLI reads
Each language is read by the engine itself or through its own language server, found on PATH on the machine that runs the scan. Without its server a language is shown as unread, never as clean.
| Language | What the CLI needs | Who calls what | GitHub App |
|---|---|---|---|
| TypeScript and JavaScript | Built in | Yes | Reads it |
| Python | Fetches pyright itself | Yes | Reads it |
| PHP | Fetches intelephense itself | No | Reads it |
| Java | Download jdtls, set MLREPS_JDTLS_HOME (and a JDK 25 on JAVA_HOME) | Yes | Reads it |
| Ruby | gem install ruby-lsp (Ruby 3+) | No | Not yet |
| C and C++ | Install clangd (LLVM, or Xcode command-line tools) | Yes | Not yet |
| Dart | Install the Dart SDK (puts dart on PATH) | Yes | Not yet |
| Swift | Install the Swift toolchain / Xcode (sourcekit-lsp); build the project for its index | Yes | Not yet |
| Kotlin | Download kotlin-language-server; set MLREPS_KOTLIN_JAVA_HOME to a JDK 17-21 | No | Reads it |
| Rust | Install rust-analyzer and the Rust toolchain (rustup component add rust-analyzer) | Yes | Reads it |
| C# | dotnet tool install --global csharp-ls | Symbols only | Not yet |
Run npx mlreps doctor in your repository (or CI) and it lists, per language, whether its server is found, will be fetched automatically, or is the one line to install by hand. Where a reader is weaker — it cannot tell who calls what, or sees only the names a file defines — every screen says so rather than hiding it.