# Kiwi: a C++ rewrite of the Cassowary constraint solver

> Kiwi is a from-scratch C++ implementation of the Cassowary algorithm for incremental linear constraint solving, with hand-written Python bindings published as kiwisolver. It is aimed at applications that need to keep a layout or set of relationships continuously satisfiable while the user drags things around.

**nucleic/kiwi** — Efficient C++ implementation of the Cassowary constraint solving algorithm

- Repository: https://github.com/nucleic/kiwi
- Website: https://kiwisolver.readthedocs.io/en/latest/
- Stars: 781 · Forks: 111
- Language: C++
- License: NOASSERTION
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/nucleic-kiwi

## An incremental solver written from the paper, not from the original code

Kiwi solves linear constraint systems incrementally, using the Cassowary algorithm described in the seminal Cassowary paper. What makes the project worth looking at is that it is a fresh implementation rather than a refactoring of the original C++ solver. The project documentation is explicit on this point, and it frames the result in numbers: Kiwi is described as ranging from 10x to 500x faster than the original Cassowary solver, with typical use cases gaining a 40x improvement and memory savings consistently above 5x. Those are the project's own measurements of its own code, so treat them as a claim by the authors rather than an independent result.

The problem it solves is the kind that shows up in user interface code. You have variables, you have relationships between them, and the relationships have priorities. When the user drags a window edge, the layout constraints need to be re-solved and the result should keep the important relationships intact while the less important ones give way. Solving from scratch each time is wasteful, and a solver that can absorb a changed constraint and produce an updated solution is what makes that interaction smooth.

The audience is C++ developers building layout or constraint driven interfaces, and Python developers who want the same solver through bindings. The project ships both, plus documentation hosted on readthedocs under the kiwisolver name.

The repository layout reflects that split. The `kiwi/` directory holds the C++ library, `py/` holds the binding sources, `benchmarks/` exists for performance work, `tests/` holds the C++ test suite, and `docs/` plus `releasenotes.rst` hold the documentation and release history.

## The API is variables, constraints and one explicit update step

The C++ API is small enough to read in one sitting. You create a solver, create variables with names, add constraints built from expressions, and then ask the solver to update the variable values.

The documented example defines two variables, adds two constraints expressed as equations, and calls `updateVariables()` before reading any value. That last call is the mechanism worth understanding: the solver does not push values back into your variables at the moment a constraint is added. You add constraints, and then you explicitly ask for the variables to be updated. Reading `x.value()` after that call returns the current solution.

The class structure is visible in the binding sources listed in setup.py. The extension module compiles py/src/kiwisolver.cpp alongside constraint.cpp, expression.cpp, solver.cpp, strength.cpp, term.cpp and variable.cpp. Reading that list tells you the shape of the library: a solver owns variables and constraints, a constraint holds expressions, an expression is built from terms, a term combines a variable with a coefficient, and strength is a separate first-class concept rather than a number buried in the constraint.

That last point is the substance of the Cassowary approach as the project implements it. Constraints do not all carry equal weight, so strength is modelled explicitly. The presence of strength.cpp as its own translation unit, and of a simplex implementation alongside the solver, points to an implementation that handles both the priority ordering and the search for a solution that satisfies the constraints as well as possible.

Because the API is small, the best source of further examples is the test suite. The project documentation points at SimplexTest.cpp and SolverTest.cpp as places to see more usage patterns.

## Wiring Kiwi into a CMake build with FetchContent

The documented way to consume the C++ library is CMake's FetchContent, which downloads the repository at a pinned tag and builds it as part of your project. The README gives the snippet to place in your CMakeLists.txt:

```cmake
include(FetchContent)

FetchContent_Declare(
    kiwi
    GIT_REPOSITORY https://github.com/nucleic/kiwi
    GIT_TAG        {release name}
)
FetchContent_MakeAvailable(kiwi)

target_link_libraries(your_target PRIVATE kiwi::kiwi)
```

You replace the placeholder with the release tag you want, and the last line links the imported target `kiwi::kiwi` into your own target. The notable part is that `GIT_TAG` is meant to be a release name rather than a branch, so the fetch is pinned to a known version rather than tracking the moving main branch.

A minimal program then looks like this:

```cpp
#include <kiwi/kiwi.h>
#include <iostream>

int main() {
    // initialize the solver
    kiwi::Solver solver;
    // initialize the variables
    kiwi::Variable x = kiwi::Variable("x");
    kiwi::Variable y = kiwi::Variable("y");
    solver.addConstraint(x + y == 10);
    solver.addConstraint(x - y == 4);
    // solve the system of equations
    solver.updateVariables();
    std::cout << "x: " << x.value() << ", y: " << y.value() << std::endl;
    // Output: x: 7, y: 3
    return 0;
}
```

The two constraints here are equalities over expressions of variables, and the comments in the example mark the three phases: initialize, add constraints, update. The expected output line is given in the source, so a correct build prints x: 7, y: 3.

The build itself needs a C++ toolchain and a CMake project. Kiwi also ships a lint_requirements.txt file and a pre-commit-config.yaml at the top level, and continuous integration is configured in the .github directory with badges for CI and documentation builds, plus a codecov configuration for coverage reporting.

## The Python bindings need a compiler and the cppy build layer

The Python side is published as a separate distribution named kiwisolver, which is the name in the packaging metadata and the name used in the documentation. It requires Python 3.10 or newer, and the classifiers list CPython, PyPy and GraalPy as supported implementations across Python versions 3.10 through 3.15.

This is not a pure Python package. setup.py builds a single C++ extension module named `kiwisolver._cext` from seven source files under py/src, and it uses a custom build command from a package called cppy. The script is explicit about the failure mode: it tries to import `CppyBuildExt` and, if that import fails, raises a RuntimeError telling you that the setup required dependency cppy is missing and that installing through pip as recommended avoids the issue. The build system requirements in pyproject.toml pin setuptools, with a different upper bound for CPython builds than for other implementations.

The practical consequence is that installing the Python bindings means compiling a C++ extension with a toolchain on the machine. On a workstation with a compiler this is routine. In a slim container image, on a platform without a prebuilt wheel, or in an environment where you are not permitted to install build tooling, it is a real obstacle. The documentation does not describe a pure Python fallback path.

The upside of that choice is that the Python layer is not a wrapper around a subprocess or a ctypes shim over a shared library. The extension is compiled from the same sources that back the C++ library, and the file names map one to one onto the core classes: solver, constraint, expression, term, variable and strength. The result is a binding that calls into the implementation rather than emulating it.

Versioning is handled in two places. The package version is dynamic and pulled from elsewhere in the build configuration, and a comment in setup.py notes that the version must be updated in kiwi/version.h before a release, unless the changes do not touch the solver.

## The licence needs reading directly, and releases come in steady steps

The licence status of this project is slightly muddled in the metadata, and it is worth resolving before you ship it. The packaging metadata in pyproject.toml carries a copyright header for 2013 to 2026, the Nucleic Development Team, and states that the software is distributed under the terms of the Modified BSD License, with the full text in the LICENSE file. The classifier list agrees, including License :: OSI Approved :: BSD License. GitHub's own classification of the repository, however, shows it as a custom licence that GitHub cannot categorise, which is a sign that the actual LICENSE text is a modified variant rather than the standard BSD text unchanged.

For a commercial product, that distinction can matter. A modified BSD licence may add or remove clauses relative to the standard text, and the only reliable source is the LICENSE file shipped with the distribution. That is a question for whoever handles licensing in your organisation, not something to resolve from a summary.

On the release side, the project publishes numbered versions on a regular cadence. The recent releases are 1.5.1 on 2026-08-28, 1.5.0 on 2026-03-09 and 1.4.9 on 2025-08-10. Those three dates are roughly five to seven months apart, so the pace is steady but not rapid. The repository is not archived and the last push was on 2026-10-16, which is more recent than the last tagged release, so work is landing on main between releases.

The changelog lives in releasenotes.rst, linked from the project URLs in the packaging metadata. Documentation is built through readthedocs, with a .readthedocs.yaml configuration and a documentation build workflow in CI.

## When Kiwi is the wrong tool

The clearest case against Kiwi is the build requirement on the Python side. If your team wants a solver they can install from a wheel on any machine, and you have no appetite to carry a C++ toolchain into your build or your container image, the bindings are a liability rather than a benefit. The setup.py script exists precisely to give you a clear error when the cppy dependency is missing, which tells you how often that situation arises.

The second case is when you do not actually need constraint solving. Cassowary is the right tool for relations between quantities with priorities that must hold continuously, such as layout constraints. It is not a general optimiser, and the project documentation does not present it as one. If what you want is a numeric optimisation over a large search space, a constraint solver of this kind is the wrong shape of tool, and the fact that the library models strength explicitly does not change that.

The third case is a team that would rather not own a dependency with a custom licence text. The licence ambiguity described earlier is a small cost in an internal tool and a larger one in a product you distribute, and it can be resolved by reading the LICENSE file, but it cannot be resolved by the metadata alone.

There is also a fair comparison with the original C++ solver, and it is the comparison the project itself makes. The original implementation is the one described in the seminal paper, and Kiwi exists because its authors wanted a lightweight, fast implementation rather than a refactor of that code. The difference in approach is therefore generational rather than incremental: a clean-room implementation of a published algorithm against the code that first shipped it. If you need behaviour that matches the original solver exactly, including its quirks, and you have no performance requirement driving the change, the original remains a reasonable choice.

## Conclusion

Kiwi is worth adopting when your application maintains a layout that must stay consistent under continuous edits, because the solver is incremental and the C++ path avoids a Python round trip. It is a poor fit if you want a solver you can install and use in a few minutes, since the Python bindings need a C++ toolchain and the `cppy` build requirement, and the licensing status deserves a look because the packaging metadata names the Modified BSD License while GitHub classifies the repository licence as custom. Before committing, read the LICENSE file directly, check the build matrix for your compiler, and run the solver tests in the repository, SimplexTest.cpp and SolverTest.cpp, against your own constraint set.

## FAQ

### What is Kiwi and what algorithm does it implement?

Kiwi is a C++ implementation of the Cassowary constraint solving algorithm, written from the ground up rather than refactored from the original C++ solver. It also ships hand-rolled Python bindings published as the kiwisolver package.

### How do I add Kiwi to a CMake project?

The project documentation shows using FetchContent to declare the kiwi repository with a GIT_TAG set to the release name, calling FetchContent_MakeAvailable, and linking the target with `target_link_libraries(your_target PRIVATE kiwi::kiwi)`.

### How do I use the Kiwi solver in C++?

Create a `kiwi::Solver`, create `kiwi::Variable` objects, add constraints such as `solver.addConstraint(x + y == 10)`, and then call `solver.updateVariables()` before reading values with `x.value()`. The documented example prints x: 7, y: 3.

### What Python version does the kiwisolver package require?

The packaging metadata sets requires-python to 3.10 or newer, and the classifiers cover CPython, PyPy and GraalPy across Python 3.10 through 3.15.

### Why does installing the kiwisolver Python package fail with a cppy error?

The package builds a C++ extension module named kiwisolver._cext and needs the cppy build layer. The setup script raises a RuntimeError telling you that the cppy setup dependency is missing and that installing through pip as recommended avoids the issue.

### What licence does Kiwi use?

The packaging metadata states that the software is distributed under the terms of the Modified BSD License, with the full text in the LICENSE file, and the classifier list marks it as a BSD licence. GitHub classifies the repository licence as a custom one, so read the LICENSE file directly for the exact terms.

## Sources

- [Issues](https://github.com/nucleic/kiwi/issues)
- [nucleic/kiwi on GitHub](https://github.com/nucleic/kiwi)
- [Project website](https://kiwisolver.readthedocs.io/en/latest/)
- [README](https://github.com/nucleic/kiwi/blob/main/README.md)
- [Releases](https://github.com/nucleic/kiwi/releases)

---

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