uber/piranha: a polyglot refactoring tool for stale feature flags
A tool for refactoring code related to feature flag APIs
At a glance
- What is it?
- PolyglotPiranha rewrites source code that still refers to feature flags you have already decided on. It is built for teams with flag APIs in Java, JavaScript, Swift or Objective-C, and its rule model is the part worth understanding before you adopt it.
- Who is it for?
- Adopt PolyglotPiranha if your feature flag API is one of the supported languages and you can express the cleanup as tree-sitter queries with a rule graph. Do not adopt it if you expect a switch that reads your flag service and deletes dead branches, or if you need a language outside the set Uber uses.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Activity is slowing. The repository last received commits 6 months ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 28, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The stale flag problem PolyglotPiranha was built to remove
Feature flags are meant to be temporary. The README describes what happens when they are not: code that refers to a flag stays in the tree after the rollout or experiment is over, and the project calls these stale flags. The stated drawbacks are code clutter that raises maintenance cost, interference between flags (for example nesting under a flag that is always false), unused code in the source and the binary, and bugs.
The intended user is not a single developer cleaning one file. It is a team that has decided a flag is finished and now has to apply that decision across a codebase. At Uber the tool is described as mostly used to clean up stale flags, and the README says the input is the name of the flag plus the expected behaviour, with the flag-related APIs listed in a properties file. That framing matters: the tool does not discover which flags are stale. You tell it.
How the rule graph and tree-sitter queries drive a rewrite
The mechanism is structural find and replace over a concrete syntax tree, not a regex pass. A Rule carries a name, a query, a replace_node, a replacement string and an is_seed_rule flag. In the README example the query is cs :[x].isLocEnabled(), where cs marks concrete syntax and :[x] is a capture. The replacement is the literal true, so the call site is replaced by a boolean.
Rules are wired together in a RuleGraph. An OutgoingEdges entry names a source rule, a list of target rules and a scope, and in the example the scope is parent. That edge is what makes the tool more than a search-and-replace script: after the seed rule fires, the graph can hand control to another rule that cleans up the shape left behind. The README points at boolean_literal_cleanup as a rule already defined for Java under src/cleanup_rules, so the example does not have to spell out the second step.
The consequence for a reader is that correctness lives in the query and the graph, not in the CLI flags. If your flag check is written in a form your query does not match, nothing happens, and nothing tells you that nothing happened unless you inspect the output. The repository ships a tree-sitter playground at uber.github.io/piranha/tree-sitter-playground for testing grammars and queries, which is the honest signal that query authoring is where the work sits.
Installing PolyglotPiranha as a Python library or a Rust CLI
There are two entry points. The Python package installs from PyPI and is the shorter path to a working example:
pip install polyglot-piranhaThe package is named polyglot-piranha on PyPI while the import name is polyglot_piranha, and pyproject.toml requires Python 3.8 or later. The command-line interface is not on PyPI. The README's steps are to install Rust, clone the repository, enter it, and build:
git clone https://github.com/uber/piranha.git
cd piranha
cargo build --releaseThe README notes that macOS users may need cargo build --release --no-default-features, and that the binary lands under target/release.
For a first real use, the README's own example is the smallest complete program. It defines one rule that replaces a call to isLocEnabled() with true, then chains to an existing Java cleanup rule through a parent-scoped edge:
from polyglot_piranha import execute_piranha, PiranhaArguments, Rule, RuleGraph, OutgoingEdges
r1 = Rule(
name="replace_method",
query="cs :[x].isLocEnabled()",
replace_node="*",
replace="true",
is_seed_rule=True,
)
edge = OutgoingEdges("replace_method", to=["boolean_literal_cleanup"], scope="parent")The arguments object takes the code_snippet, the language string ("java" in the example) and the rule graph, and execute_piranha returns a summary whose first element has a content field. The README prints that content to see the transformed code. Expect the output to be the rewritten snippet, not a diff or a report of skipped matches.
Where PolyglotPiranha stops: language coverage and silent misses
The README is unusually direct about scope: the project supports only languages used at Uber, and it says new languages likely will not be added in this repository. Forks are named as the route to other languages. So if your flag API is in a language outside the supported set, this is the wrong tool and no amount of rule writing fixes it.
Two further limits follow from the design. First, the tool is not a flag inventory. It takes a flag name and expected behaviour as input, so it cannot tell you which flags are safe to remove. Second, a query that does not match produces no error. A refactor that silently changes nothing looks the same as a refactor that found nothing to change, and the README does not document a dry-run mode or a rollback path. You should treat the generated code as a patch to review, and keep the change under version control so a bad rewrite is revertable at the repository level rather than by the tool.
There is also a maintenance caveat in the README itself: Piranha uses grammar repositories with custom patches, and while those patches are being upstreamed there may be discrepancies between the grammars in this repository and the upstream tree-sitter grammars. That is the kind of detail that decides whether a query behaves the same after an upgrade.
PolyglotPiranha compared with codemods and Comby-style rewriting
The natural alternative is a general structural rewrite tool such as Comby, or a language-specific codemod framework like jscodeshift for JavaScript. The difference is in what is built in. A codemod framework gives you a parser and a traversal API and leaves the flag semantics entirely to you; you write the visitor that recognises a flag check and the logic that decides what the branch collapses to. PolyglotPiranha ships that second half as rules. The README refers to cleanup rules already defined for Java under src/cleanup_rules, and the demo directory contains feature_flag_cleanup and feature_flag_cleanup_using_py_api alongside find_replace and match_only examples, so the flag-specific behaviour is part of the distribution rather than something each team rewrites.
The trade is coverage. jscodeshift is JavaScript and TypeScript only but is maintained by a large ecosystem; PolyglotPiranha spans several languages with one rule format but declares that it will not grow to languages outside Uber's set. If your codebase is one language with a mature codemod ecosystem, the general tool may cost you less. If you have the same flag API expressed in Java, JavaScript and Swift and want one mental model for the cleanup, the rule graph is the reason to pick this.
Release cadence, licence and the cost of staying current
The workspace version in Cargo.toml is 0.4.8, matching the most recent release, v0.4.8, published on 2026-04-02. The previous two releases are v0.4.7 and v0.4.6, both from October 2025, so the cadence is not dense and the project is still on a 0.x version. The last push to the default branch was on 2026-04-02, which is the same day as the v0.4.8 release.
For upgrade cost, the parts that can break are the ones the README already flags as patched: the grammars, and by extension the queries written against them. A rule that matches today can stop matching after a grammar change, and because misses are silent, the failure appears as an unchanged file rather than an error. Pinning the version and re-running your rules against the tree-sitter playground before upgrading is the concrete check available.
Licensing is Apache-2.0, declared in the LICENSE file and in pyproject.toml, with a NOTICE file at the repository root and a license_header.txt used by the pre-commit configuration. Apache-2.0 includes an explicit patent grant and requires attribution and notice retention; the README also states that this is not an official Uber product and is provided as is. That last line is worth reading literally when you decide how much to depend on it. This is a description of the licence, not legal advice.
Editorial conclusion
Adopt PolyglotPiranha if your feature flag API is one of the supported languages and you can express the cleanup as tree-sitter queries with a rule graph. Do not adopt it if you expect a switch that reads your flag service and deletes dead branches, or if you need a language outside the set Uber uses. Verify first that your flag API matches an existing cleanup rule or that you can write a query for it, and check the grammar patches under crates/ and plugins/ against your source, because the README warns of discrepancies with upstream tree-sitter grammars.
Frequently asked questions
What is PolyglotPiranha used for?
It is a code transformation toolset for automating large scale changes, and at Uber it is mostly used to clean up stale feature flags. The README describes it as taking a flag name and expected behaviour, plus a list of flag APIs in a properties file, and refactoring the code accordingly.
How do I install PolyglotPiranha?
The Python API installs with pip install polyglot-piranha and requires Python 3.8 or later. The command-line interface is built from source: clone the repository, run cargo build --release (or cargo build --release --no-default-features on macOS), and the binary appears under target/release.
Which languages does PolyglotPiranha support?
Only languages used at Uber, and the README states that new languages likely will not be added in this repository. It points to forks for additional features. The example in the README uses Java, and the repository topics list Java, JavaScript, Objective-C and Swift.
Does PolyglotPiranha find stale feature flags for me?
No. The README describes the input as the name of the flag and the expected behaviour, with flag APIs listed in a properties file. Deciding which flags are stale happens before the tool runs.
What licence is PolyglotPiranha under?
Apache-2.0, declared in pyproject.toml and in the LICENSE file, with a NOTICE file at the repository root. The README also states that this is not an official Uber product and is provided as is.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/uber-piranha)