• 4 min read

Catching code plagiarism without vector embeddings

Table of Contents

Astra is a code similarity detection system that analyzes Python assignments based on their structure rather than their raw text.

You can read more about this project in this

notebook

Why we built it

Astra started from an observation in our own classes: some programming assignments looked suspiciously similar. We didn’t care why. We wanted a way to actually measure similarity between two pieces of code.

Text comparison doesn’t work well for this. Two programs can solve the same problem while looking completely different because of renamed variables, formatting, or reordered functions, and two files can look different as plain text while sharing nearly identical logic. Since this was an algorithms course project, we treated it as one: code isn’t just text, it has structure, so Astra asks whether two files are built from similar structures instead of similar words.

How it turned out

Astra is a Python system that compares code through a structural pipeline, available as both a CLI and a web app. The CLI handles batch analysis: point it at a folder of submissions and it produces ranked similarity results. The web app exposes the same pipeline through an interface that makes it easier to inspect suspicious pairs and see why they were flagged.

Comparing programs by structure, not appearance

The core idea is that source code means more than its characters. A Python program first gets parsed into an Abstract Syntax Tree (AST), which represents its actual structure.

For example, changing:

score = total / count

to:

average = numbers / length

changes the text but keeps the same underlying structure. Astra normalizes the AST to strip out these irrelevant differences and focus on what the program actually does.

Breaking programs into comparable pieces

Comparing entire files at once makes partial similarities hard to catch, so Astra divides programs into smaller chunks like functions and classes. That way it can flag cases where only part of a submission is similar, instead of judging the whole file as one block, and it’s more forgiving when students organize their code differently.

Using classic algorithms for a modern problem

Astra doesn’t use machine learning or vector embeddings. It converts code structures into sequences and compares them with edit distance, specifically Damerau-Levenshtein distance, which measures how many insertions, deletions, substitutions, and transpositions it takes to turn one sequence into another. That algorithm is decades old, but it still works because it directly models the problem.

How we built it

The pipeline: parse the source into an AST, normalize it, extract structural chunks, convert those chunks into sequences, then score similarity between submissions.

The hard part wasn’t implementing the comparison algorithm. It was deciding what information actually matters. Strip out too much structure and unrelated programs start looking similar. Keep too much and something as simple as renaming a variable tanks the similarity score.

What I learned

Astra reinforced something I keep relearning: the newest technology isn’t always the right one. It’s tempting to reach for embeddings or an LLM the moment a problem touches text or code, but for code similarity what matters is structure, not wording, and a well-designed algorithm captures that directly, more explainably than a model would. Good engineering starts with picking the right abstraction. Sometimes that’s a modern model, sometimes it’s an algorithm from decades ago that already solves the problem.