# Mago: a Rust toolchain for PHP linting, formatting and static analysis

> Mago bundles a linter, formatter and static analyzer into one Rust binary for PHP projects. Here is what the repository documents, what it leaves open, and who should think twice before switching.

**carthage-software/mago** — Mago is a toolchain for PHP that aims to provide a set of tools to help developers write better code.

- Repository: https://github.com/carthage-software/mago
- Website: http://mago.carthage.software/
- Stars: 3,479 · Forks: 188
- Language: Rust
- License: Apache-2.0
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/carthage-software-mago

## What Mago replaces, and for whom

A typical PHP codebase runs three separate tools: a code style fixer, a linter or code sniffer, and a static analyzer. Each has its own config file, its own cache, and its own startup cost. Mago's pitch is to collapse that set into one binary written in Rust, with a unified CLI and library interface, as its Cargo.toml description puts it. The README lists lint, static analysis, automated fixes, formatting, semantic checks and AST visualization as the feature set.

The audience is PHP teams already comfortable with the idea of a Rust-based toolchain. The README names OXC as a major inspiration for building a high-performance toolchain in Rust, and Clippy for its linting approach. If your team has adopted Rust tooling elsewhere, the mental model transfers. If your team's workflow is built entirely around PHP-CS-Fixer rule names and PHPStan baselines, the transfer is not free: Mago's own rule set and configuration keys are what you would be learning, and the repository's mago.toml at the root is the only configuration example visible here.

## Parser, linter and analyzer in one pass

The repository layout shows the architecture more clearly than the README does. There is a crates/ directory holding the workspace members, a corpus/ directory and a cases/ directory, and a crates/syntax/fuzz target excluded from the workspace. The topics list on the repository names the individual pieces: lexer, parser, formatter, linter, type-checker, code-analyzer. So the data flow is the conventional one for this class of tool: source text goes through a lexer and parser to produce an AST, and the AST feeds the formatter, the lint rules and the type checker. The README's AST visualization feature is the same pipeline exposed for inspection.

That single pipeline is the reason the tools can share configuration and cache. It is also the reason a parser bug is not confined to one tool. In a setup with separate tools, a formatting bug and an analysis bug are independent failures. Here they share an upstream representation. The crates/syntax/fuzz entry in the workspace exclude list suggests the project treats parser robustness as something to fuzz, which is the right instinct for a shared front end, though the repository does not state how often that fuzz target runs.

## Installing Mago and running a first lint

The README gives a shell script as the most common installation method on macOS and Linux. It pipes a remote script into bash, so read it before running it if that pattern concerns you.

```bash
curl --proto '=https' --tlsv1.2 -sSf https://carthage.software/mago.sh | bash
```

The same script accepts a version pin, which is what you want in CI. The README shows this exact form for 1.50.0:

```bash
curl --proto '=https' --tlsv1.2 -sSf https://carthage.software/mago.sh | bash -s -- --version=1.50.0
```

After installation the README points to the Getting Started guide on mago.carthage.software for project configuration. The repository root contains a mago.toml, which is the configuration file the tool reads; the README itself does not reproduce its keys, so the guide is the place to look for the schema. For other channels, the README names Homebrew, Composer and Cargo and defers to the installation guide rather than listing the commands. The Dockerfile in the repository is minimal: it copies a prebuilt mago binary into an Alpine image and sets it as the entrypoint, so it assumes you already have the binary rather than building it inside the image.

## Where the documentation runs out

The README is a landing page, not a manual. It states the feature categories and links out. It does not document rollback, it does not describe how configuration merges across a monorepo, and it does not say what happens when a lint rule is removed or renamed between releases. Given that the releases move quickly, with 1.48.1, 1.49.0 and 1.50.0 all landing in September 2026, rule churn is a realistic concern for anyone pinning behavior.

The more consequential gap is static analysis parity. The README acknowledges PHPStan and Psalm as foundational work and describes Mago as a unified and faster alternative, but it does not publish a mapping between Mago's analyzer and the checks those tools perform. PHPStan's ecosystem includes community extensions and stub files for frameworks; nothing in the README says Mago has an equivalent extension mechanism. If your analysis depends on framework-specific stubs, that is the first thing to verify, and the README will not answer it. The installation guide is the only place that might.

## Mago compared with PHPStan and PHP-CS-Fixer

The difference is scope, not just speed. PHPStan is a static analyzer and nothing else; it does not format your code and does not fix style. PHP-CS-Fixer is a style tool; it does not type-check. Running both means two configs, two caches, and two CI steps. Mago's approach is to put the formatter, the linter and the analyzer behind one CLI, which the README frames as a unified and faster alternative to the tools it thanks.

The trade is depth against breadth. A single-purpose tool can go deep on its one job, and PHPStan has had years to build out its type inference and its extension ecosystem. A unified tool has to be good enough at three jobs at once. Mago's topics list a type-checker, so the ambition is there, but the README does not claim check-for-check parity with PHPStan. Teams with a large PHPStan baseline and custom extensions are the ones most likely to feel that gap. Teams whose static analysis needs are modest, and who mainly want style and lint enforcement in one fast step, are the ones the unified model suits.

## Licensing, release cadence and upgrade cost

Mago is dual-licensed under MIT or Apache-2.0, at your option, per the README and the Cargo.toml license field. Both are permissive, so embedding the binary in a proprietary build or shipping it in a container image does not by itself create source-disclosure obligations. That is a licensing observation, not legal advice; the Apache-2.0 patent grant is the practical difference between the two options, and your legal team is the right place to settle which one you take.

The upgrade cost is driven by cadence. Three releases shipped between 2026-09-11 and 2026-09-21, and the last push to the default branch was on 2026-09-21. A project moving that fast will occasionally change rule behavior or configuration keys. Pinning the version in CI, which the install script supports via --version, is the straightforward mitigation. The README does not publish a changelog or a deprecation policy, so the release notes on the repository are where you would look before bumping. Running from a pinned version and reviewing release notes before each bump is the whole of the upgrade discipline the README supports.

## Conclusion

Adopt Mago if you want one fast Rust binary covering lint, format and static analysis, and you are willing to validate rule coverage yourself against the code you actually ship. Do not adopt it as a drop-in PHPStan replacement if your type-checking depends on extensions and stubs that Mago does not document. Before committing, run mago lint and mago format on a representative module and diff the output, then read the installation guide for the update path.

## FAQ

### Is Mago a PHP linter, a formatter, or a static analyzer?

It is all three. The README describes Mago as a PHP linter, formatter and static analyzer written in Rust, and lists lint, static analysis, automated fixes, formatting and semantic checks as separate features behind one CLI.

### How do I install Mago on macOS or Linux?

The README gives a shell script as the most common method, and shows a version-pinned variant using --version=1.50.0. It also names Homebrew, Composer and Cargo as other channels and points to the installation guide for those.

### How does Mago compare with PHPStan?

The README acknowledges PHPStan as foundational work and positions Mago as a unified and faster alternative, but it does not publish a mapping between Mago's analyzer and PHPStan's checks. PHPStan is a static analyzer only, while Mago also covers formatting and linting.

### What license is Mago released under?

Mago is dual-licensed under your choice of the MIT License or the Apache License, Version 2.0, according to the README and the license field in Cargo.toml.

## Sources

- [carthage-software/mago on GitHub](https://github.com/carthage-software/mago)
- [License: Apache-2.0](https://github.com/carthage-software/mago/blob/main/LICENSE)
- [Project website](http://mago.carthage.software/)
- [README](https://github.com/carthage-software/mago/blob/main/README.md)
- [Releases](https://github.com/carthage-software/mago/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/carthage-software-mago
