Handling legacy research codebases
Introduction
In modern scientific research, it becomes increasingly common for researchers
to inherit some research codebases, which often have minimal documentation or
in a semi-working state. This is not because researchers enjoy giving bad
codebases to their successors, often it is just that the focus of researchers
is to produce results under deadline and the accompanying codebases are merely a
tool which they developed solely for themselves.
With the popularity of coding agents, it becomes easier to handle this
situation. However, just prompting the coding agent with 'explain this
codebase' will probably produce a well-written summary which could be wrong in
a subtle way and later when you actually run the code, most likely it won't
work.
What you will do in this module
This module is an attempt to provide some guidance about how you could use
coding agents as an assistance when you inherit a research codebase. A lot of
principles exist before the advent of LLMs and we will see how coding agents
excel or probably not so helpful in understanding a research codebase.
You will produce an
AGENTS.md/CLAUDE.md for a real-world research codebase
in a step-by-step manner, either with your own inherited codebase or a codebase
written by other researchers. Most importantly, you are not generating an
AGENTS.md/CLAUDE.md with a coding agent despite commands such as /init
exist or use some templates. You are going to write an
AGENTS.md/CLAUDE.md by yourself with information you have personally
verified. Creating AGENTS.md/CLAUDE.md files by a coding agent risks
circular reasoning, which the coding agents put in false claims you are not
aware of and future session reference them as source of truth. Besides, forcing
yourself to write each sentence out will make sure you understand it first, as
it is harder for one to write something that you do not believe. With an
AGENTS.md/CLAUDE.md, it provides a first step for you to reproduce some of
its results, modify the algorithm, or implement some new features with the
assistance of coding agents.Five codebases have been curated below if you do not 'bring your own codebase',
and feel free to pick one closest to your domain to work in this module.
| Repository | Field |
|---|---|
SamStudio8/gretel | Bioinformatics, metagenomics |
epicf/ef_python | Accelerator physics, plasma physics |
whaley-group-berkeley/qspectra | Molecular spectroscopy, quantum dynamics |
cgq-qgc/HydroSensorReader | Hydrogeology, environmental data |
modsim/molyso | Quantitative microscopy, microbiology |
These repositories are teaching examples and they were selected because they
produced or support real research which are valuable. The author of this module
has no intention to criticise or imply something have been done improperly.
Their authorship of the above repositories should be respected throughout this
module. Work in your own clone or fork and do not submit AI-generated pull
requests, issues, or comments to the original repositories. If you maintain one
of these repositories and would prefer it not to be included, please contact
rse-training@dtc.ox.ac.uk.
Dealing with legacy codebases
We will try to follow some steps which can help you to understand an unfamiliar
research codebase and how coding agents can assist you in the process.
The entry point
When you inherited a codebase, the first thing you should find out is how the
software is invoked and this is called the entry point. The best way is, of
course, asking someone who knows but often, you are on your own to figure this
out.
Where are the entry points?
For a Python codebase, how do you commonly locate the entry points? Be as
exhaustive as possible.
How the coding agent can help
If you are well versed in the terminal, you could probably assemble some
grep
commands with some regex to get an initial impression. Nowadays, we have coding
agents and they are powerful to look up information. However only a human with
the right domain knowledge and context can decide what the real entry point is.
Asking a coding agent 'Tell me the entry point of this codebase' will probably
give you something like main.py or run_me.sh, which may or may not be true.
A lot of codebases also have multiple entry points.Write the prompt
You can always ask the coding agent to enumerate all the plausible entry points
and you pick those that are relevant to you. Write such prompt, then
evaluate the output and decide what entry points are relevant.
'What this is' section in
AGENTS.md/CLAUDE.md: in your own words, a
one-sentence overview of what the software does, the location of the entry
point(s), and how to trigger each of them.Run something minimal
Once you know the entry point, the next natural step is to run it to see how it
goes. Unless it is a trivial script, chances are there are dependencies you
would need to install or run something like
make install/cmake to build the
software, so we need to figure out how to install those dependencies or compile
it. Afterwards, we can run something minimal or its tests to see if it works.When running something unfamiliar to you, it is often good practice to run it
in an isolated environment in case something unpleasant happen. You could
consider install and run everything with a container with your chosen
repository in this module.
Where do the dependencies come from?
What would you normally do to figure out the dependencies of the codebase or
the steps of compilation?
However, legacy research codebases usually lack the above information, and even
if you know the dependencies or how to build it, most likely it will give you
errors even running something minimal. The reason is not because of the
codebase itself, it is because the world has since moved on and interfaces from
the dependencies may just be changed or removed. Even worse, the interfaces
remain the same but the underlying implementation changed or the same
parameters mean different things now etc.
How the coding agent can help
If there is completely no information about the dependencies or how to build
it, you could
grep or visually inspect the import statements in the case of
Python. Coding agents are also quite good at figuring out the dependencies for
you (it most probably just grep the import and come up with a
pyproject.toml for you), or suggest the first step how you could compile it.Coding agents are very good at looking up dependencies history, deprecation
warnings, and their motivation in relevant discussion. Once you have built a
virtual environment or a container with the dependencies and encountered an
error after running something minimal or tests with it, give your coding agent
the traceback and let it diagnose.
Write the prompt
Assume you got an error after running something minimal using an entry point
with your virtual environment or container for the first time, write a prompt
for a coding agent so it can assist you to know why and fix it.
Given you encounter a deprecation, it is your call whether to fix the code or
pin a package to a particular version. Below are something to consider:
To pin:
- It is faster for now.
- It reduces one variable if you encounter any error later.
- It preserves exactly the behaviour from that dependency.
Not to pin and fix the code:
- It is slower but avoids accumulating further technical debt.
- You get the new functionality or optimisation from the package.
- A new version of the dependency may break something in other places subtly.
- If you are going to further develop this codebase, this is usually a better option.
It is useful to record the current status of the inherited codebase by running
the existing tests, if any. Some tests may already fail before you fix or
implement something and with a record, it will be clearer whether this is
because of your new changes or something is just not working when you inherit
the codebase. In some cases, the failed tests are not relevant anymore and you
can decide to remove them all together.
'Quick start' section in
AGENTS.md/CLAUDE.md: in your own words,
how to set up the environment, pinned dependencies with a concise reason
for each pin, the exact commands/scripts that work, errors you hit with
their reasons and workarounds, and the current test results.The structure of the codebase
If you are going to use the codebase beyond anything like running it for few
times to reproduce something trivial, you are going to need a clear picture of
how different parts of the codebase connect with each other in order to
implement a new feature or fix a bug.
How would you do it without an LLM?
Outline some methods that will be helpful in understanding an unfamiliar
codebase (without any LLM).
How the coding agent can help
Prompting the coding agents with 'explain the codebase' will get you something
that looks plausible, however you have no idea whether the well-organised
claims are true or not. They may silently infer some claims from its knowledge
as it was trained with possibly thousands similar codebases.
How to prevent this?
How can we instruct the coding agents to avoid the above problem? Or at least
decrease the likelihood of hallucinating false claims about the codebase.
Research codebases typically contain experimental or unfinished features that
are never used in the existing analysis. Depending on your situation, those
features may be important to you as you are the one to extend some of the
features in your research. Isolating them from the production run path is one
of the most important insights to gain from understanding the structure of the
codebase, and coding agents can be a powerful tool here as they possess some
semantic understanding.
Find the dead code
After understanding the run paths from different entry points, you should have
a better understanding of what functions are used and what they are for.
Assume you have some text files containing the functions used from all the
entry points you are interested in and the order of which they are called,
write a prompt to identify 'the dead code' (which may be of interest to you as
you are going to work on them).
'The structure of the codebase' section in
AGENTS.md/CLAUDE.md: in
your own words, the functions/modules that really matter and what each is
for, the path data takes from entry point to output, and the parts that are
currently dead (unused) and why.Reproduce previous results
Most of the research codebases you inherited have produced some sort of
research outputs, such as publication or conference abstract. If not, there
will be at least some reports or presentations internally in your research
group. These actually give you some sort of specifications you can check the
implementation against with the current codebases you inherited.
This also opens you to one of the characteristics of research codebases: the
differences between what a figure or a table in a publication or a report says
and what the codes actually do. This is because researchers often tinker
things when new data arrived or tune some parameters in an ad-hoc way, and if
you are lucky, those would be recorded in the report but often it is just in
the 'mind of the researchers'. All tests and CI pipelines will pass despite the
code cannot reproduce the figure or table you want.
How the coding agent can help
Be extremely cautious about the sycophancy nature of coding agents here. If you
prompt with 'does this code implement what this paper describes?', you will
certainly get a confident 'yes' with supporting details that look correct. It
tends to find agreements and avoid any discrepancy, unless you tell the
coding agents explicitly. The output will be misleading, especially if you are
unfamiliar with the inherited codebase.
This is one area that the domain knowledge of a human can genuinely help a lot
before asking the coding agent. You, the researcher, hopefully knows roughly,
for instance, how a certain figure was produced in theory. What you do not
know is how to use the inherited codebase to reproduce such figure, and with
the help of coding agents, this could be cut down from months to weeks.
Equipped with the knowledge of the structure of the codebase (from last
section), you should now know what functions/files are related to the
production of such figure, or in the worst case, you can eliminate irrelevant
code.
Write the prompt
The powerful ability of coding agents to collect information and summarise them
is very useful in this situation. Write a prompt that guide the coding agent to
reproduce a figure in a publication that you know was once generated by your
inherited codebase.
Below are something that often result in discrepancy between the published
result and the code:
- hard-coded constant, e.g. threshold
- convention, e.g. normalisation
- hidden assumptions, e.g. background is removed in an ambiguous way
'How to reproduce XXX' section in
AGENTS.md/CLAUDE.md: in your own
words, for the result you want to work on, the claims made in the
publication/report and the corresponding parts of the code, any discrepancy
with your resolution, and the steps to reproduce it, at least partially.When the coding agents fail to reproduce something, you should watch out for
them silently tweaking something that makes the code agree with the published
result. For instance, it may adjust some default values without any valid
scientific reason just to match the numbers in the publication. Whether this is
'cheating' or not entirely relies on you to decide. When iterating with the
coding agents to reproduce something, you may need to provide additional
constraints progressively if you spot something it should not change.
Conclusion
When you are handed a legacy research codebase, it could be a frustrating
experience, especially when there is minimal help from your colleagues (not that
they hate you, but no one really knows what it is about) and you need to
produce something out of it. It used to take months of significant effort from
a researcher to make sense of it. With the power of modern coding agents, the
time can be shortened to weeks. Coding agents genuinely provide values in
modern scientific research.
This module provided some guidance about how you could use coding agents to
handle legacy research codebase by manually producing an
AGENTS.md/CLAUDE.md
file with the assistance of coding agents using either your own inherited
codebase or one of the curated ones. This AGENTS.md/CLAUDE.md file serves
as the context for coding agents which is a starting point for you to further
work on the codebase, such as refactoring, fixing bugs, implementing new
features or algorithm, and optimisation etc.- Coding agents excel at gathering information from messy sources such as a legacy research codebase.
- It is easier to start with metadata of a codebase (packaging, CI pipelines, tests, commit history etc.) than the code themselves when exploring an unfamiliar codebase.
- Provide concrete evidence (e.g. tracebacks) to the coding agents when you want it to further investigate something.
- Domain knowledge is invaluable in handling legacy research codebases as, for instance, only you can decide a reproduced result is actually right or not. You should make your own judgement based on evidence you have verified.