# Fixit, a Python linter whose rules live inside your own repository

> Fixit is Instagram's LibCST based linting framework for Python, built around in-repo rules, hierarchical configuration and suggested changes that can be accepted automatically. It suits teams that want their own checks to travel with the code, but the project still classifies itself as alpha and the published command line documentation is thin.

**Instagram/Fixit** — Advanced Python linting framework with auto-fixes and hierarchical configuration that makes it easy to write custom in-repo lint rules.

- Repository: https://github.com/Instagram/Fixit
- Website: https://fixit.rtfd.io/en/latest/
- Stars: 715 · Forks: 72
- Language: Python
- License: NOASSERTION
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/instagram-fixit

## Fixit reads Python through LibCST rather than the standard ast module

The single most consequential dependency in pyproject.toml is libcst, listed at version 0.3.18 or newer. That library keeps a concrete syntax tree, so a Fixit rule sees formatting, comment placement and the actual nesting of a statement instead of a stripped down syntax tree. The project description calls Fixit an advanced Python linting framework with auto-fixes and hierarchical configuration, and the project README frames the goal as making it quick to write new lint rules and offer suggested changes for any errors found. A conventional checker that works on the standard ast module can report a location, and at best a line number, but a LibCST based rule can return a replacement node and have the framework re-render the file. The dependency list also includes moreorless at 0.4.0 or newer, a component of the kind used to present a before and after view of a rewritten file. Together these two packages are what allow a rule to answer with an edit rather than a message, and they are why the docs say changes can be accepted automatically or presented to the user for consideration.

## Hierarchical configuration lets a child repository narrow what the parent enforces

Configuration is one of the three features the project description leads with, and it is the feature that most affects how a team adopts the tool. The reserved configuration table in pyproject.toml is named [tool.fixit], which places the settings next to the source they govern instead of in a separate global file. The visible portion of that table is cut short in the copy of the file available here, so the individual keys and the exact inheritance rules are not readable, and it would be wrong to promise which parent value wins over a child value without seeing them. What the structure does show is a hierarchy: a setting can be stated once at a high level and narrowed where a subtree needs different behaviour, which matters for monorepos where a shared configuration file and a per package override have to coexist. The published documentation points to a user guide for the details, and the 2.0 release notes referenced there describe a rebuild of the project around better configuration and support for custom lint rules.

## Installing Fixit means accepting a floor of Python 3.10 and a pinned click

Fixit is published on PyPI as fixit, and the packaging metadata defines the console script entry point that the command line is built on. The dependency block below is the one recorded in pyproject.toml, and it fixes the runtime floor for the project at Python 3.10 or newer, with the tomli backport pulled in only for interpreters older than 3.11.

```toml
requires-python = ">=3.10"
dependencies = [
    "click >= 8.0, < 8.2",
    "libcst >= 0.3.18",
    "moreorless >= 0.4.0",
    "packaging >= 21",
    "tomli >= 2.0; python_version < '3.11'",
    "trailrunner >= 1.2",
]
```

Two of those lines carry the operational weight. The click range is closed on both ends, so a team that pins its own click version in a shared environment can collide with the linter. The libcst floor is where the tree aware behaviour begins; a lower pin means losing the concrete syntax tree that the whole design rests on.

## The fixit command is registered through a standard console script

The command line is not a custom binary. It is an entry point declared in the same packaging metadata, which means an ordinary Python install exposes a command named fixit, and the same name is what a CI job or a pre-commit hook would call.

```toml
[project.scripts]
fixit = "fixit.cli:main"
```

The visible slice of the published README leaves the quickstart section empty, so the exact subcommands and flags are not stated there, and the project documentation site is the place where the command reference lives. What can be confirmed from the packaging file is the entry point target and the surrounding tooling. Fixit also ships an optional language server extra, which installs a pygls based server, and a pretty extra that pulls in rich for formatted terminal output. Neither extra is required by the core install, so a team can start with the base dependency set and add the language server only if it wants editor feedback.

## Suggested changes and automatic acceptance are two different modes

The workflow is described in terms of choices: a rule finds an error, Fixit offers a suggested change, and the change is either accepted automatically or presented to the user. That split is the practical difference between running the linter in a pre-commit hook and running it in a continuous integration job. A hook that rewrites files on the spot turns a check into an editor, and the repository itself reflects that, since the top level of the tree contains a .pre-commit-config.yaml and a .pre-commit-hooks.yaml alongside a makefile and a scripts directory. In continuous integration the same rule set is more likely to run in report mode, where the diff of each proposed edit is printed and the run fails, leaving a human to apply the changes. The dependency on moreorless, and the optional rich extra for terminal formatting, both point at the report path being a first class output rather than a by-product of the check.

## Rules written in the repository instead of installed as plugin packages

The clearest differentiator is where the logic lives. The project description says Fixit makes it easy to write custom in-repo lint rules, and the examples directory in the tree contains three example locations, examples/basic, examples/noop.py and examples/teambread. The difference in approach against a plugin style linter is one of ownership. A check distributed as an installed package has to be released, versioned and published before any team can use it, and a rule that only makes sense for one codebase has nowhere natural to live. A rule that lives in the repository sits in the same version control, in the same review process, and in the same test run as the code it inspects. Fixit also carries its own .flake8 file at the top level and lists flake8 and flake8-bugbear among its development dependencies, so the project checks itself with a different linter than the one it distributes. For a team whose rules encode internal conventions rather than general style, that ownership model is the reason to look at Fixit at all.

## An alpha classifier and a licence label that GitHub cannot classify

Two items in the packaging metadata deserve a second look before adoption. The classifier list marks the project as Development Status :: 3 - Alpha, which is the project's own statement about its stability. The last push was on 2026-07-01, and the two most recent releases are v2.2.0 on 2025-11-04 and v2.2.1 on 2025-11-12, so the repository is not archived and has had commits more recently than its last tagged release. Versions are declared as dynamic in pyproject.toml and the build system relies on hatchling together with hatch-vcs, so the version is derived from the repository rather than written into the file. On the licence, the project documentation states that Fixit is MIT licensed and the classifiers include the MIT licence identifier, but the licence field points at a LICENSE file that the hosting service could not classify. The safe reading is to open that file and confirm the terms yourself, and to treat the MIT wording as a claim to verify rather than a settled fact.

## Where Fixit is the wrong tool

There are cases where reaching for Fixit costs more than it saves. The first is a codebase that already depends on a mature plugin ecosystem for style and error checks, since a second linter introduces a second source of findings, a second configuration surface and a second thing to keep current. The second is an environment pinned below Python 3.10, because the packaging metadata sets the floor at 3.10 and offers no fallback for older interpreters. The third is a team that needs language server diagnostics inside an editor: the lsp extra is optional, so the default install gives no editor integration at all, and adopting the extra means running a pygls server in the development environment. There are also gaps a reader should not gloss over. The quickstart section of the README is empty, the CLI flags are not enumerated in the published text, and no rollback procedure is described anywhere in the available documentation, so an auto-fix mode applied in a pre-commit hook is a behaviour you would want to trial on a branch before enabling it broadly.

## Conclusion

Adopt Fixit when a team wants to ship repository specific checks and accept suggested rewrites from a LibCST backed tool, and stay on a plugin style linter when a shared ecosystem matters more than local rule authorship. Before installing anything, read the LICENSE file that pyproject.toml points at, since the project licence is described as a custom one while the docs call it MIT, and confirm that the fixit console script exposes the flags your CI already expects.

## FAQ

### What is Fixit and what is it built on?

Fixit is a Python linting framework from Instagram that provides auto-fixes, custom local lint rules and hierarchical configuration. It is built on LibCST, so rules work on a concrete syntax tree and can return replacements rather than only locations.

### How do I install Fixit and what Python version does it need?

Fixit is published on PyPI as fixit and requires Python 3.10 or newer, with tomli pulled in automatically for interpreters older than 3.11. Installing the package exposes a console script named fixit, declared in pyproject.toml as fixit = "fixit.cli:main".

### Does Fixit support automatic fixes and rules kept inside my own repository?

Yes. The project documentation states that rules can offer suggested changes which are then accepted automatically or presented to the user for consideration, and the project description highlights custom in-repo lint rules as a core feature. The examples directory ships several example rule locations.

### How is Fixit licensed?

The project documentation states that Fixit is MIT licensed and the packaging classifiers list the MIT licence identifier, but the pyproject.toml licence field points at a LICENSE file described as a custom licence the hosting service could not classify. Read that file to confirm the terms yourself.

### Is Fixit actively maintained?

The repository is not archived and the last push was on 2026-07-01. The most recent releases are v2.2.0 on 2025-11-04 and v2.2.1 on 2025-11-12, and the packaging metadata still classifies the project as Development Status :: 3 - Alpha.

## Sources

- [Instagram/Fixit on GitHub](https://github.com/Instagram/Fixit)
- [Issues](https://github.com/Instagram/Fixit/issues)
- [Project website](https://fixit.rtfd.io/en/latest/)
- [README](https://github.com/Instagram/Fixit/blob/main/README.md)
- [Releases](https://github.com/Instagram/Fixit/releases)

---

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