← All posts
#open source#developer tools#static analysis#go#tree-sitter

Finding Familiar Code with Mori

A local tool I built to find structurally similar code, and why I now use it across most of my larger projects.

Two similar branching code structures illuminated among a dark forest of syntax trees.

I have started using Mori on most of my larger projects.

It is a little strange reaching for a tool I only built recently as though it has always been part of the routine, but it has settled into that role surprisingly quickly. I run it when a project begins to feel too large to hold comfortably in my head, or when I find a new piece of code and have the nagging feeling that I have seen the same idea somewhere else.

That feeling is usually difficult to search for.

Normal text search works when I remember a function name, a useful string, or some particularly distinctive bit of syntax. It is less helpful when two pieces of code do roughly the same thing but use different names, live in different parts of a project, or were written in different languages.

That is what Mori is for.

Mori is a local command-line tool that looks for source fragments with similar structure. Rather than comparing the text directly, it parses the code and keeps the shape of what it finds: calls, branches, loops, returns, relationships between expressions, and a few other useful details. Formatting, comments, most names, and the actual values of literals are put to one side.

That means it can notice, for example, that a JavaScript function and a Go function both check an input, split it into pieces, loop over them, and return early when something goes wrong. The two functions might not share any useful search terms, but their underlying shape can still be recognisably similar.

A basic scan is deliberately uneventful:

mori scan --profile review .

The result is a shortlist of places to inspect, along with a similarity score and a small explanation of what the fragments have in common.

The important word there is inspect.

Mori cannot prove that two functions behave in the same way. It does not know enough about runtime values, side effects, external services, database constraints, or the particular promises a piece of code makes to the rest of an application. A very high score can still hide a small but important difference in an error path or nested callback.

I do not treat its output as a list of things to refactor. I treat it as a list of questions.

Sometimes the answer is that two functions really are copies that have slowly drifted apart. Sometimes one is an older implementation that can now be removed. Sometimes they merely follow the same sensible pattern and should remain exactly where they are. Repetition is not automatically a defect, and removing it is not automatically an improvement.

What Mori gives me is a better place to begin reading.

That has been especially useful in projects which have grown across several languages. Mori currently understands Go, JavaScript and JSX, TypeScript and TSX, Python, Rust, Swift, Bash and POSIX shell, Zsh, and SQL. It can compare code within one language family or look for similar shapes across languages.

The cross-language part was the original interesting problem, but using Mori on real projects quickly exposed a less glamorous one: useful results depend on being honest about what was actually examined.

Large repositories contain generated files, tests, migrations, framework scaffolding, tiny callbacks, and intentionally repetitive code. A tool can produce a very confident-looking report from a fairly meaningless selection of those things. Mori therefore records warnings and coverage information, and its review profile starts with a more conservative selection.

The first scan of a project is usually followed by a little housekeeping. I decide which generated or repetitive areas should be excluded and record that in .mori.json or .moriignore. The configuration is part of the review rather than something Mori tries to guess on my behalf.

For changes in progress, I can also ask Mori to bring results involving changed files to the front:

mori scan \
  --changed-since origin/main \
  --profile review \
  .

It still compares against the rest of the repository. This matters because a new function may resemble something old and untouched elsewhere in the project. Looking only at the diff would miss the exact relationship I am interested in.

Once I have reviewed an intentional match, I can add it to a baseline so it does not dominate every future report. New matches continue to appear, while the things I have already considered become quiet. The baseline records that I accepted the similarity, not that the two pieces of code are equivalent.

Mori also runs entirely locally. It reads source but does not execute it, and the scanning path does not make network requests or send telemetry. Its machine-readable reports contain paths, names, scores, and structural evidence, but not the source bodies themselves. That makes it practical to use on private projects rather than reserving it for code I am happy to send elsewhere.

There are more advanced parts now: PostgreSQL parsing, embedded SQL in Go, smaller statement-block comparisons, deterministic JSON reports, CI failure modes, and an optional skill that helps coding agents interpret the results sensibly. They have mostly grown out of using the tool and finding places where the original, simpler version was not quite enough.

But the reason I keep reaching for it has remained fairly modest.

A large codebase can be difficult to navigate because there are too many potentially interesting places to look. Mori reduces that space. It points at a few pairs of functions or queries and says, in effect, “these have something in common.”

The decision about what that commonality means is still mine.

Mori is open source under the MIT licence. Prebuilt versions for macOS, Linux, and Windows are available from the latest release, or it can be installed from source with Go 1.23 or newer and a C compiler:

go install \
  github.com/Cyberlane/mori/cmd/mori@latest

If you work in a large repository and occasionally find yourself wondering whether you have seen a particular piece of code before, it may be useful to you too.

Finding Familiar Code with Mori

A local tool I built to find structurally similar code, and why I now use it across most of my larger projects.

Two similar branching code structures illuminated among a dark forest of syntax trees.

I have started using Mori on most of my larger projects.

It is a little strange reaching for a tool I only built recently as though it has always been part of the routine, but it has settled into that role surprisingly quickly. I run it when a project begins to feel too large to hold comfortably in my head, or when I find a new piece of code and have the nagging feeling that I have seen the same idea somewhere else.

That feeling is usually difficult to search for.

Normal text search works when I remember a function name, a useful string, or some particularly distinctive bit of syntax. It is less helpful when two pieces of code do roughly the same thing but use different names, live in different parts of a project, or were written in different languages.

That is what Mori is for.

Mori is a local command-line tool that looks for source fragments with similar structure. Rather than comparing the text directly, it parses the code and keeps the shape of what it finds: calls, branches, loops, returns, relationships between expressions, and a few other useful details. Formatting, comments, most names, and the actual values of literals are put to one side.

That means it can notice, for example, that a JavaScript function and a Go function both check an input, split it into pieces, loop over them, and return early when something goes wrong. The two functions might not share any useful search terms, but their underlying shape can still be recognisably similar.

A basic scan is deliberately uneventful:

mori scan --profile review .

The result is a shortlist of places to inspect, along with a similarity score and a small explanation of what the fragments have in common.

The important word there is inspect.

Mori cannot prove that two functions behave in the same way. It does not know enough about runtime values, side effects, external services, database constraints, or the particular promises a piece of code makes to the rest of an application. A very high score can still hide a small but important difference in an error path or nested callback.

I do not treat its output as a list of things to refactor. I treat it as a list of questions.

Sometimes the answer is that two functions really are copies that have slowly drifted apart. Sometimes one is an older implementation that can now be removed. Sometimes they merely follow the same sensible pattern and should remain exactly where they are. Repetition is not automatically a defect, and removing it is not automatically an improvement.

What Mori gives me is a better place to begin reading.

That has been especially useful in projects which have grown across several languages. Mori currently understands Go, JavaScript and JSX, TypeScript and TSX, Python, Rust, Swift, Bash and POSIX shell, Zsh, and SQL. It can compare code within one language family or look for similar shapes across languages.

The cross-language part was the original interesting problem, but using Mori on real projects quickly exposed a less glamorous one: useful results depend on being honest about what was actually examined.

Large repositories contain generated files, tests, migrations, framework scaffolding, tiny callbacks, and intentionally repetitive code. A tool can produce a very confident-looking report from a fairly meaningless selection of those things. Mori therefore records warnings and coverage information, and its review profile starts with a more conservative selection.

The first scan of a project is usually followed by a little housekeeping. I decide which generated or repetitive areas should be excluded and record that in .mori.json or .moriignore. The configuration is part of the review rather than something Mori tries to guess on my behalf.

For changes in progress, I can also ask Mori to bring results involving changed files to the front:

mori scan \
  --changed-since origin/main \
  --profile review \
  .

It still compares against the rest of the repository. This matters because a new function may resemble something old and untouched elsewhere in the project. Looking only at the diff would miss the exact relationship I am interested in.

Once I have reviewed an intentional match, I can add it to a baseline so it does not dominate every future report. New matches continue to appear, while the things I have already considered become quiet. The baseline records that I accepted the similarity, not that the two pieces of code are equivalent.

Mori also runs entirely locally. It reads source but does not execute it, and the scanning path does not make network requests or send telemetry. Its machine-readable reports contain paths, names, scores, and structural evidence, but not the source bodies themselves. That makes it practical to use on private projects rather than reserving it for code I am happy to send elsewhere.

There are more advanced parts now: PostgreSQL parsing, embedded SQL in Go, smaller statement-block comparisons, deterministic JSON reports, CI failure modes, and an optional skill that helps coding agents interpret the results sensibly. They have mostly grown out of using the tool and finding places where the original, simpler version was not quite enough.

But the reason I keep reaching for it has remained fairly modest.

A large codebase can be difficult to navigate because there are too many potentially interesting places to look. Mori reduces that space. It points at a few pairs of functions or queries and says, in effect, “these have something in common.”

The decision about what that commonality means is still mine.

Mori is open source under the MIT licence. Prebuilt versions for macOS, Linux, and Windows are available from the latest release, or it can be installed from source with Go 1.23 or newer and a C compiler:

go install \
  github.com/Cyberlane/mori/cmd/mori@latest

If you work in a large repository and occasionally find yourself wondering whether you have seen a particular piece of code before, it may be useful to you too.