What happens when you want to build a codebase analyzer, and your first instinct is to install a library for everything?
You install a package for CLI handling.
Another for parsing.
Another for graphs.
Another for searching.
And suddenly your “zero-dependency” project has... a lot of dependencies. 😭
For the Zero Dependency Hackathon, our team decided to build RepoXray, a command-line tool for understanding unfamiliar codebases.
The catch?
We couldn't use third-party runtime dependencies.
So instead of asking “Which package should we use?”, we had to start asking:
“What do we actually need, and can Python's standard library give us enough to build it ourselves?”
That turned out to be the interesting part.
What is RepoXray?
When you open an unfamiliar repository, you usually want answers to a few basic questions:
What is this project?
Where is the important code?
What depends on what?
Which files use this one?
If I change something here, what might break?
RepoXray tries to answer those questions from the command line.
Its workflow is:
SCAN → INDEX → RESOLVE → ANALYZE → ANSWER
It scans a repository, builds a local index, searches its contents, inspects files, resolves local relationships, and performs dependency and impact analysis.
The idea isn't to replace an IDE or a full language server.
It's to make exploring an unfamiliar codebase faster and more structured.
Then the package manager disappeared
This was the part that changed how we approached the project.
Normally, reaching for an existing library is often the sensible engineering decision.
Need graph traversal? There are libraries for that.
Need parsing? There are libraries for that too.
But the hackathon constraint meant we had to build around what Python already provides.
Some of the pieces we ended up using were:
argparse → command-line parsing
pathlib / os → filesystem operations
ast → Python analysis
re → pattern matching
hashlib → file fingerprints
json → persistent index data
collections → graph/data structures
sqlite3 → database inspection
zipfile → archive inspection
unittest → testing
We documented 11 meaningful standard-library substitutions in our STDLIB log.
But the interesting part wasn't finding a one-to-one replacement for every package.
It was deciding how much functionality we actually needed.
The hardest part wasn't scanning files
Walking through a repository and calculating a SHA-256 hash isn't particularly difficult.
Building a useful index around that information is.
We had to handle things like:
added and deleted files
modified files
renamed files
empty projects
corrupt indexes
unchanged files that should be reused
That led to incremental indexing, where unchanged information can be reused instead of rebuilding everything from scratch.
The standard library gave us the building blocks.
The actual behavior was ours to design.
Import resolution: don't turn guesses into facts
Another interesting problem was figuring out which files depend on which.
For Python and JavaScript/TypeScript projects, imports aren't always straightforward file paths.
There can be relative imports, different extensions, ambiguous candidates, and imports that aren't repository-local at all.
So RepoXray doesn't pretend every relationship is certain.
It distinguishes between:
Resolved
Heuristic
Ambiguous
Unresolved
That was a deliberate choice.
A tool that confidently gives you the wrong dependency graph is worse than one that admits when it isn't sure.
Once those relationships exist, we can ask higher-level questions:
python3 repoxray.py depends-on repoxray.py .
python3 repoxray.py who-uses repoxray.py .
python3 repoxray.py impact repoxray.py .
So instead of simply searching for text, RepoXray can reason about repository relationships.
What would we normally install?
This is where the “Package Killer” idea becomes interesting, even though RepoXray itself isn't a replacement for one specific package.
For graph-related functionality, for example, NetworkX would be an obvious library to consider.
But we didn't recreate NetworkX.
We didn't need all of NetworkX.
We needed a smaller set of graph operations for our specific problem, so we implemented those ourselves using standard-library data structures and traversal logic.
The same principle applied throughout the project.
We weren't trying to rebuild the Python ecosystem.
We were trying to build the functionality our application actually needed without depending on it.
Then we tried to break it
A demo can show that your program works once.
Tests tell you what happens when someone tries to ruin your day. 😭
Our test suite covers cases including:
empty projects
malformed and corrupt indexes
ambiguous imports
relative imports
JavaScript imports
cycles and self-references
deep traversals
incremental changes
large-file searching
Unicode and spaces in paths
The full suite finished with:
Ran 21 tests in 5.960s
OK
We also checked that RepoXray could import with Python's site-packages disabled:
python3 -S -c "import repoxray; print('stdlib import check passed')"
Result:
stdlib import check passed
And we packaged the application as a Python zipapp:
python3 build.py
producing:
dist/repoxray.pyz
The artifact could then be executed directly with:
python3 dist/repoxray.pyz --help
What I actually learned
The biggest surprise was that zero-dependency development isn't really about avoiding imports.
It's about understanding what those imports are buying you.
The standard library already gives Python a lot:
filesystems, hashing, parsing, data structures, serialization, databases, archives, testing, and more.
But none of those things magically becomes a codebase analyzer.
The engineering happens in the layer where those pieces are combined into something useful.
That was probably the best part of the constraint.
It forced us to stop asking:
“What package does this problem have?”
and start asking:
“What is the actual problem we're solving?”
Sometimes the answer was a few standard-library calls.
Sometimes it was significantly more code.
And sometimes the right answer was simply to accept a limitation instead of trying to recreate an entire ecosystem.
Final thoughts
RepoXray isn't trying to prove that third-party packages are bad.
They're not.
Packages exist for a reason, and rebuilding mature libraries from scratch is usually not a good use of engineering time.
The interesting thing about this hackathon was being forced to operate without that safety net.
We ended up building a codebase analyzer with repository scanning, indexing, search, import resolution, dependency relationships, impact analysis, testing, and a runnable zipapp, all while keeping the runtime dependency-free.
And somewhere along the way, a simple restriction turned into one of the more useful engineering exercises we've done.
Not:
“How do we avoid using packages?”
But:
“What can we actually build with what we already have?”
For a first-year student team, that's a question I'm pretty happy we got to explore.
And yes, I'm still signing up for more hackathons.
Apparently I learn slowly. 😭
RepoXray: https://github.com/saksham-2x7/repoxray
What package would you normally reach for when building something like this? 👀
Top comments (0)