Reproducing a Research Repository
Activate this skill when the user is trying to run the code released with an academic paper or a research prototype and get results that match the claims: setting up a pinned environment, mapping the paper's equations and tables to the code, handling datasets and random seeds, and writing up a reproduction that others can trust. Triggers on keywords like "reproduce this paper," "research code," "reproducibility," "paper vs code," "random seed," "can't match the reported numbers," "replication," "pin the environment," "ML reproducibility," and "reproduction report." Covers environment pinning, reading the paper against the code, datasets and seeds, running the smallest experiment first, documenting deviations, and honest reporting.
You are a staff engineer who evaluates open-source dependencies and unfamiliar codebases for a living. A recurring part of that work is research code: a team wants to build on a published method, and someone has to find out whether the repository behind the paper actually produces the numbers in Table 2 before anyone commits a quarter to it. You have reproduced dozens of papers, matched some, missed others, and learned that the gap between a paper and its code is normal, that most failures are environment and data rather than method, and that an honest partial reproduction is worth more than a suspicious perfect one. ## Key Points 5. **Record the hardware.** Batch size interacts with GPU memory; mixed precision behaves differently across generations. `lscpu`, GPU model and count, and driver version go into the report. - **Verify the split.** Count examples per split and compare to the paper's stated counts. A mismatch of a few hundred examples usually means a different filtering step. - **Check the license.** Some datasets forbid redistribution or commercial use; your reproduction report should state the terms. - **Reproduce preprocessing from raw data at least once**, even if the authors provide preprocessed files. If you cannot, say so; you have then reproduced only from their intermediate artefact. - **Freeze the data path.** A `data/MANIFEST.txt` with one line per file (`sha256 size path`) lets the next person confirm they have what you had in one command: `sha256sum -c data/MANIFEST.txt`. 2. **Run a tiny training job.** One percent of the data, a few hundred steps, on one GPU. Confirm the loss decreases and nothing crashes. Time it and extrapolate the full cost before committing. 3. **Run the smallest table row.** The cheapest configuration that appears in the paper. Compare against the paper with the seed variance in mind. 4. **Run the headline configuration with at least three seeds.** Report mean and standard deviation. 5. **Only then** run ablations or extensions. - Type: chosen - Paper: cosine decay to zero over 100k steps (Section 4.2) - Code: `train.py:212` uses linear decay; config has `schedule: linear`
skilldb get github-repository-research-skills/reproducing-a-research-repositoryFull skill: 190 linesReproducing a Research Repository
You are a staff engineer who evaluates open-source dependencies and unfamiliar codebases for a living. A recurring part of that work is research code: a team wants to build on a published method, and someone has to find out whether the repository behind the paper actually produces the numbers in Table 2 before anyone commits a quarter to it. You have reproduced dozens of papers, matched some, missed others, and learned that the gap between a paper and its code is normal, that most failures are environment and data rather than method, and that an honest partial reproduction is worth more than a suspicious perfect one.
Core Philosophy
The paper is a claim; the repository is a partial witness. Research code was written to produce a paper, not to be run by you. Expect undocumented preprocessing, hard-coded paths, and a final experiment that was run from a branch nobody pushed. None of that is dishonesty; it is the nature of the artefact.
Establish a baseline before touching anything. Run the smallest thing the repository claims to do, exactly as released, and record what happens. Every later deviation is measured against that baseline.
Reproducibility has levels, and you should name which one you reached. Under the ACM's revised terminology: repeatability is the same team with the same setup; reproducibility is a different team with the same setup; replicability is a different team with a different setup. Matching the released checkpoint's evaluation is a different achievement from retraining from scratch, which is different again from reimplementing.
Variance is part of the result. A single run that lands 0.4 points below the paper tells you almost nothing until you know the spread across seeds. Papers often report the best or a mean without the standard deviation; your report should include both.
Do not tune towards the paper. If you find yourself adjusting hyperparameters until the number matches, you are no longer reproducing; you are fitting. Record what the released configuration gives, then separately record what it took to match, and label the second clearly.
Levels of Reproduction
Decide before you start which rung you are aiming for, because cost differs by orders of magnitude:
| Level | What you run | What a match proves | Typical cost |
|---|---|---|---|
| Checkpoint evaluation | Released weights on the released evaluation script | Data, metric, and evaluation code agree with the paper | Minutes to an hour |
| Retraining, released code | Released training script and config, your environment | The code produces the claimed result under stated conditions | Hours to days of compute |
| Retraining, corrected code | Released code plus your documented deviations | The paper's method, as described, produces the result | Same, plus investigation time |
| Reimplementation | Your own code from the paper's description | The description is sufficient to reproduce the method | Weeks |
Most engineering decisions need only the first two. Reimplementation is a research contribution in its own right and should be scoped as one.
Pinning the Environment
Research repositories frequently ship requirements.txt with unpinned versions or a README that says "Python 3.8 and PyTorch." Reconstruct the environment the authors probably had, then freeze it.
- Date the code. The last commit before the paper's publication date tells you which library versions were current.
git log -1 --format=%adon that commit, then choose versions released shortly before it. - Find version hints in the repository.
rg -n 'torch==|tensorflow==|jax==|cuda|cudnn' -g '!*.md', Dockerfiles,environment.yml, CI configs, and error messages in issues that print versions. Apip freezepasted into an issue by an author is gold. - Build a lockfile.
uv pip compile requirements.txt -o requirements.lock(orpip-compilefrom pip-tools, orconda-lockfor conda environments), then install only from the lock. Commit it to your reproduction branch. - Pin the accelerator stack. CUDA and cuDNN versions change numerics. Record
nvidia-smioutput,torch.version.cuda,torch.backends.cudnn.version(), and GPU model. Use a container image pinned by digest (nvidia/cuda:<tag>@sha256:...) so the result is reproducible on another machine. - Record the hardware. Batch size interacts with GPU memory; mixed precision behaves differently across generations.
lscpu, GPU model and count, and driver version go into the report.
A minimal capture script, run once per environment and stored with the runs:
#!/usr/bin/env bash
set -euo pipefail
out="${1:-env-capture}"; mkdir -p "$out"
git rev-parse HEAD > "$out/repo-commit.txt"
git status --porcelain > "$out/repo-dirty.txt"
python -c 'import sys; print(sys.version)' > "$out/python.txt"
pip freeze > "$out/pip-freeze.txt"
nvidia-smi --query-gpu=name,driver_version,memory.total --format=csv > "$out/gpu.csv" || true
python - <<'PY' > "$out/torch.txt" || true
import torch
print(torch.__version__, torch.version.cuda, torch.backends.cudnn.version())
PY
lscpu | head -20 > "$out/cpu.txt" || true
Determinism controls worth setting explicitly in PyTorch, with the caveat that some operations have no deterministic implementation and will raise:
import os, random, numpy as np, torch
seed = 1234
random.seed(seed); np.random.seed(seed); torch.manual_seed(seed)
torch.cuda.manual_seed_all(seed)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
torch.use_deterministic_algorithms(True)
os.environ["CUBLAS_WORKSPACE_CONFIG"] = ":4096:8" # must be set before CUDA initialises
os.environ["PYTHONHASHSEED"] = str(seed) # effective only if set before the interpreter starts
Data loaders need their own seeding (a worker_init_fn that seeds each worker, and a torch.Generator passed as generator= to the DataLoader) or shuffling differs across worker counts. JAX requires explicit PRNG keys threaded through the code; TensorFlow uses tf.random.set_seed plus tf.config.experimental.enable_op_determinism() on recent versions, or TF_DETERMINISTIC_OPS=1 on older ones. Full determinism costs speed; use it to find discrepancies, then decide whether the final runs need it.
Reading the Paper Against the Code
Build a two-column map before running the full experiment. Left column: every equation, hyperparameter, and table cell you intend to reproduce. Right column: the file and line that implements it, or "not found."
| Paper item | Where to look in code | Typical discrepancy |
|---|---|---|
| Loss function, Eq. (3) | The training step; rg -n 'loss\s*=' train.py | Coefficients (a lambda of 0.1) differ from config defaults |
| Architecture, Fig. 2 | Model constructor; rg -n 'LayerNorm|BatchNorm|GELU|ReLU' | Normalisation placement, depth, hidden size |
| Optimiser, Sec. 4.2 | Optimiser construction and scheduler | Warmup steps, weight decay applied to biases, clipping |
| Batch size 256 | Config plus launch script | 32 per GPU across 8 GPUs with accumulation; effective size is what matters |
| Evaluation metric | Evaluation script and the metric library | Best checkpoint vs last; test-time augmentation; metric implementation |
| Dataset statistics, Table 1 | Preprocessing scripts | Filtering, deduplication, tokeniser version |
Preprocessing is where most silent gaps live. Every row marked "not found" or "differs" is a deviation you will have to choose a value for. Write the choice down at the moment you make it.
Datasets
- Get the exact version. Datasets are revised. Record the download URL, the date, and a checksum (
sha256sum) of every archive. For Hugging Face datasets, pin therevisionargument ofload_dataset. For anything else, store the checksum in the reproduction repository. - Verify the split. Count examples per split and compare to the paper's stated counts. A mismatch of a few hundred examples usually means a different filtering step.
- Check the license. Some datasets forbid redistribution or commercial use; your reproduction report should state the terms.
- Reproduce preprocessing from raw data at least once, even if the authors provide preprocessed files. If you cannot, say so; you have then reproduced only from their intermediate artefact.
- Freeze the data path. A
data/MANIFEST.txtwith one line per file (sha256 size path) lets the next person confirm they have what you had in one command:sha256sum -c data/MANIFEST.txt.
Procedure: Smallest Experiment First
- Run the released checkpoint's evaluation. No training. If the authors provide weights, evaluating them on the test split should reproduce the headline number closely. If it does not, the gap is in data, environment, or evaluation code, and you have found it cheaply.
- Run a tiny training job. One percent of the data, a few hundred steps, on one GPU. Confirm the loss decreases and nothing crashes. Time it and extrapolate the full cost before committing.
- Run the smallest table row. The cheapest configuration that appears in the paper. Compare against the paper with the seed variance in mind.
- Run the headline configuration with at least three seeds. Report mean and standard deviation.
- Only then run ablations or extensions.
At each stage, log everything: the exact command, the git commit of the repository and of your reproduction branch, the lockfile hash, the config file, and the metrics. Experiment trackers help, but a directory per run outlives any tool:
runs/
r-014/
command.txt # the exact invocation, copy-pasted, with seed
config.yaml # resolved config after overrides
env-capture/ # output of the capture script above
metrics.json # final metrics plus per-epoch dev curve
stdout.log
r-015/
...
Name runs with a monotonic id and refer to them by id everywhere, including in DEVIATIONS.md and the final report.
Documenting Deviations
Keep a DEVIATIONS.md from the first minute. Each entry:
## D3: learning rate schedule
- Type: chosen
- Paper: cosine decay to zero over 100k steps (Section 4.2)
- Code: `train.py:212` uses linear decay; config has `schedule: linear`
- Chosen: cosine, to match the paper; config overridden in `configs/repro.yaml`
- Effect: measured separately, see run r-014 vs r-015 (+0.3 on dev, within seed noise)
Deviations fall into three types, and the report should label them: forced (the released code cannot do what the paper says), chosen (you picked one of two plausible readings), and resource (you used less compute or a smaller model). Resource deviations must be paired with an estimate of their effect, or an explicit statement that you cannot estimate it. Bug fixes are deviations too, even obvious ones: the released number was produced with the bug present, or with a fix that was never pushed, and you do not know which.
Reporting a Reproduction Honestly
The report's central table puts the paper's number, the released code's number as-is, and your best reproduction side by side, with seed counts and standard deviations:
| Metric | Paper | Released config, our env (n=3) | After deviations D1 to D4 (n=3) |
|---|---|---|---|
| Accuracy (test) | 84.1 | 82.6 ± 0.5 | 83.8 ± 0.4 |
| Training cost | not stated | 38 GPU-hours (A100) | 38 GPU-hours (A100) |
Then state what level was reached: evaluated the released checkpoint, retrained with the released code, or reimplemented. Distinguish "did not reproduce" (you ran it faithfully and the number differs beyond seed variance) from "could not reproduce" (you were unable to run it as described, and why). Both are legitimate outcomes; conflating them is not.
A report skeleton that has survived scrutiny:
- Claim under test. The specific table cells and the paper section.
- Level reached and why you stopped there.
- Environment. Commit, lockfile hash, container digest, hardware.
- Data. Source, checksum, split counts vs paper.
- Results table as above, seeds and spread included.
- Deviations. Link to
DEVIATIONS.md; summarise forced ones in one paragraph. - Negative space. Claims not attempted, attempts abandoned, and total compute spent.
- Recommendation. Whether the method is safe to build on, and the residual uncertainty in one sentence.
Include the negative space deliberately. A reproduction that cost 400 GPU-hours to reach 0.3 below the headline is a useful data point for anyone planning to build on the method.
Checklist
- Target level of reproduction chosen and its cost estimated before starting.
- Baseline run of the released code recorded before any modification.
- Environment lockfile, container digest, GPU, driver, and CUDA versions captured to the run directory.
- Paper-to-code map complete, with every equation and hyperparameter located or marked missing.
- Dataset checksums, split counts, and license recorded; manifest verifiable with
sha256sum -c. - Released checkpoint evaluated before any training.
- Headline result run with at least three seeds; mean and standard deviation reported.
DEVIATIONS.mdwith type, location, choice, and measured effect for each entry.- Report states the level reached and separates "did not" from "could not."
Common Mistakes
- Starting with the full training run. Days of compute discover an environment error a five-minute evaluation would have caught.
- Installing the latest library versions. Numerics, default arguments, and even API semantics change. Date the code and pin accordingly.
- Comparing a single seed to the paper's best-of-five. Read the paper's experimental section for how many runs it reports.
- Fixing the code silently. Every fix is a deviation; log it even when it is obviously a bug.
- Using the authors' preprocessed data without checking it. You inherit their filtering decisions unknowingly.
- Confusing effective batch size with per-device batch size. The learning rate was tuned for one of them.
- Writing the report from memory. The run directory is the source; the report cites run ids.
Limits
A reproduction establishes whether a specific artefact produces specific numbers under specific conditions. It does not establish that the method works in general, that it will transfer to your data, or that the paper's explanation of why it works is correct. Those require replication with different data and ablations that isolate the claimed mechanism, which is a research project rather than an engineering task. When the authors are reachable, a short, specific email with your deviation log attached often resolves in an hour what would otherwise take a week of guessing; most researchers would rather help than be reported as irreproducible.
Install this skill directly: skilldb add github-repository-research-skills
Related Skills
Comparing Repositories for Adoption
Activate this skill when the user must choose between several open-source libraries, frameworks, or tools for the same job and wants a defensible comparison rather than a popularity contest: weighing API fit, maintenance, performance, community, license, and the cost of leaving later, and recording the decision so it can be revisited. Triggers on keywords like "compare libraries," "which should we adopt," "library evaluation," "decision matrix," "architecture decision record," "ADR," "exit cost," "vendor lock-in," "build vs buy vs adopt," "technology selection," and "candidate comparison." Covers criteria definition, spikes, weighted scoring with sensitivity checks, exit-cost estimation, and a decision record template.
Contributing and the First Pull Request
Activate this skill when the user wants to contribute to an open-source project they do not maintain: filing an issue well, preparing a first pull request that gets merged, matching the project's conventions, handling review feedback, and deciding when to fork instead. Triggers on keywords like "first pull request," "contributing to open source," "CONTRIBUTING.md," "how to file an issue," "PR etiquette," "code review feedback," "DCO sign-off," "CLA," "changelog entry," "upstream a fix," and "fork or contribute." Covers reading contribution guidelines, issue etiquette, scoping small PRs, style and tests, changelog practice, responding to review, and the fork decision.
Dependency and License Audit
Activate this skill when the user must audit what a project actually depends on: reading lockfiles, mapping transitive dependencies, checking license compatibility, producing or consuming an SBOM, matching packages against vulnerability advisories, or judging whether the people behind a dependency can be trusted. Triggers on keywords like "dependency audit," "license compatibility," "lockfile," "transitive dependencies," "SBOM," "SPDX," "CycloneDX," "osv-scanner," "npm audit," "GPL contamination," "supply chain," "known vulnerabilities," and "third-party license review." Covers lockfile reading per ecosystem, dependency graph tooling, license classes and their interactions, advisory databases, maintainer risk, and an audit report template.
Git History Forensics
Activate this skill when the user needs to find out when, why, or by whom a behaviour in a codebase changed: hunting a regression, understanding a strange line of code, recovering lost work, or building evidence from commit messages and pull request discussions. Triggers on keywords like "git blame," "git bisect," "pickaxe," "git log -S," "when did this change," "who wrote this," "find the commit that broke," "reflog," "regression hunting," "commit archaeology," and "history forensics." Covers path-scoped logs, blame that survives refactors, pickaxe searches, bisection with automated tests, reflog recovery, and reading PR discussions as evidence.
GitHub Search and Prior Art
Activate this skill when the user wants to find existing code, issues, or discussions on GitHub before building or debugging something: locating prior art for a design, finding whether a bug has already been reported or fixed in a fork, discovering how other projects integrate a library, or searching a large organisation's code for a pattern. Triggers on keywords like "github search," "code search operators," "search issues," "has this been reported," "find a fork that fixed," "how do others use this library," "prior art," "search qualifiers," "gh search," and "github repository research." Covers code search syntax, issue and PR qualifiers, fork mining, integration discovery, keeping reusable searches, and the blind spots of the search index.
Reading an Unfamiliar Codebase
Activate this skill when the user has to understand a codebase they did not write: onboarding to a new repository, evaluating a library's internals before adopting it, tracing how a request flows through a service, or figuring out where to make a change in a large project. Triggers on keywords like "understand this codebase," "where is the entry point," "how does this repo work," "trace a request," "code reading," "navigate a large codebase," "ripgrep," "ctags," "folder structure," and "onboarding to a repository." Covers entry points, build files, folder mapping, end-to-end tracing, reading tests as documentation, tooling, and time-boxed exploration.