Skip to content

Quickstart

See it work first

With uv installed, one command runs the demo with no API key and nothing to install or configure:

uvx --from "mylonite[demo]" mylonite demo

On every pull request, CI builds Mylonite from source and runs this command against that build on Python 3.14, on Linux and Windows, in an 80-column terminal. To keep Mylonite installed instead, use pip as below.

Install

Requires Python 3.11–3.14. The mylonite CLI is on PyPI:

pip install mylonite                 # the CLI that scans your app
pip install "mylonite[demo]"         # + the reference app, for `mylonite demo`

Then, with no API key and nothing to configure:

mylonite demo

That replays a recorded run against the bundled reference app's vulnerable and guarded builds. It shows a kept finding with its suggested fix, then the regression test generated for it failing on the vulnerable build and passing on the guarded one, then the scan table for every weakness class. It is the fastest way to see what the tool does. See demo for exactly what "replay" means and how it differs from a live scan.

The [demo] extra adds the reference target (mcp-kitchen-sink), which is a separate package: a plain pip install mylonite never pulls the deliberately-vulnerable reference agent. The extra pins it exactly, because the demo's recorded fixtures are keyed on that package's tool schemas.

To hack on Mylonite or the reference target, use a development checkout with two editable installs (the mylonite package, then the reference target):

On Linux / macOS (bash):

git clone https://github.com/Abidemialade/mylonite.git
cd mylonite
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
pip install -e ./reference_targets/mcp_kitchen_sink

On Windows (PowerShell):

git clone https://github.com/Abidemialade/mylonite.git
cd mylonite
python -m venv .venv
.venv\Scripts\Activate.ps1
pip install -e ".[dev]"
pip install -e ./reference_targets/mcp_kitchen_sink

Contributors should also run pre-commit install after installing.

Choose a model

demo replays a recording and needs no model. Every other live command (scan, validate, gate, ablate) needs one picked — there is no default provider or model. Set it once so you don't have to repeat it on every command:

export MYLONITE_MODEL=anthropic/claude-haiku-4-5-20251001   # needs ANTHROPIC_API_KEY
export ANTHROPIC_API_KEY=sk-ant-...

The full provider table, and how to hand over a key, is on Choose a model.

Any LiteLLM provider works the same way: a provider/model prefix (e.g. --model openai/gpt-4o) plus that provider's own key env var — --model and mylonite.yaml's model: key both work instead of the environment variable, same precedence as everywhere else in the CLI. No key at all? Run a local model instead: --model ollama_chat/llama3.2:3b with Ollama running. With none of the three set, every live command stops before touching a target, naming the approved providers and exiting 4 — see "No model chosen at all?" in the CLI reference for the exact message. This key pays for Mylonite's own planner, customiser and judge calls, never for a call your app's own agent made.

Commands that work today

mylonite version
mylonite scan reference:vulnerable
mylonite scan mcp:fetch --authorize fetch
mylonite gate reference:vulnerable                 # scan -> test -> validate, the full pipeline
mylonite report .mylonite/scans/<dir> --sarif out.sarif --json finding.json
  • mylonite scan <target> — run the live exploit-finding loop. On an MCP target, Mylonite drives your tools itself with its own agent (the planner), reading your system prompt and tool descriptions — it is not your app's own model or framework making the calls. Needs the model and key from Choose a model above. Targets: reference:vulnerable / reference:guarded (the in-process reference app builds), and the bundled MCP (Model Context Protocol) stdio families mcp:filesystem:<sandbox>, mcp:fetch, mcp:github:<owner/repo> — these require --authorize naming the family itself (fetch above) or, for mcp:filesystem/mcp:github, the scope after the second colon (see the responsible-use policy) plus the family's runtime: uv for mcp:fetch (spawns via uvx), Node.js for mcp:filesystem / mcp:github (spawn via npx). Add --dry-run to enumerate seeds without an API key.
  • mylonite gate <target> — the whole pipeline (scan → generate → validate → optional PR) in one command; only a kept test makes it through. See CI gating.
  • mylonite report <dir> — render a scan/validation as a terminal panel, --sarif (GitHub code scanning), or --json bundle. See Reading the results.

The full flow: scan → generate → validate

The end-to-end pipeline works today. Scan a target for a weakness, emit a regression test from the finding, then validate that the test is meaningful through the differential oracle.

On Linux / macOS (bash):

mylonite scan reference:vulnerable
mylonite generate --latest
mylonite validate .mylonite/generated/indirect_injection_note_body_direct

On Windows (PowerShell):

mylonite scan reference:vulnerable
mylonite generate --latest
mylonite validate .mylonite\generated\indirect_injection_note_body_direct
  • mylonite scan reference:vulnerable — runs the live exploit-finding loop against the in-process vulnerable build and writes exploit_*.json artefacts under .mylonite/scans/<ts>/. Live — needs an API key (see below).
  • mylonite generate --latest — offline and deterministic (no LLM call). Reads the newest scan's exploit, emits a testkit-based pytest regression test, and prints the exact mylonite validate <dir> command to run next. The test is stamped UNVALIDATED until validate keeps it. --latest picks the newest scan; pass an explicit exploit_*.json or scan dir instead if you prefer.
  • mylonite validate <dir> — runs the DifferentialValidator (the validation engine). Live — it makes real LLM calls against the model you chose in Choose a model, so it needs that provider's API key; it states the work it will run up front and reports the LLM calls and tokens it used at the end. It runs the finding's own attack against both reference builds across a 5-run flakiness filter and reports kept plus the mutation score. Exits 0 when the test is kept and 5 when it is cleanly rejected.

generate is the only offline command here; scan and validate both make live LLM calls. Whether the committed regression test that generate emits replays offline at the CI gate depends on the target: for the bundled reference:* builds it replays offline (no API key needed there); for a real, custom target (--target-file) there is no recorded twin to replay, so the emitted test re-drives your actual app live, gated behind MYLONITE_LIVE_TARGET=1 (the CI workflow sets it for you) — see The validation engine and CI gating.

Gate it (CI) and read the results

Turn a finding into a committed regression test and a gating PR with one command, then render it in whatever format your pipeline consumes:

mylonite gate --target-file app.yaml --authorize my-app --open-pr   # against YOUR app
mylonite report .mylonite/generated/<dir> --sarif out.sarif     # GitHub code scanning
mylonite report .mylonite/generated/<dir> --json finding.json   # dashboards / SIEM / bots

Where to go next