Step 1 — Repo hygiene
Repo hygiene: the ten-minute rule
Everything else in this handbook assumes a stranger can understand your repo in ten minutes. Before you wire up Zenodo, before you write a pyproject.toml, before you draft a paper.md, get your repo into that state.
The ten-minute rule: a researcher who has never met you should be able to arrive at your GitHub repo, read the README, and know within ten minutes: (a) what this code does, (b) how to install it, (c) how to run one working example, (d) whether they’re allowed to reuse it, and (e) how to cite it.
This chapter is the pre-flight checklist for that rule. Nothing here is fancy; it’s just the stuff people skip.
1. Pick a license, and put it in a LICENSE file
Without a LICENSE file, your code is not open source — the default under U.S. copyright law is that nobody else has any rights to your work. GitHub can host it, but nobody else can legally fork, modify, or use it.
For most research software, MIT is the safest default:
- Permissive (anyone can use, modify, distribute — even commercially).
- Trivially compatible with most other licenses.
- Well-understood by lawyers at every institution.
Copy the MIT text into a top-level file called LICENSE. Change the year and copyright holder line to:
Copyright (c) 2026 The Ohio State University
(or whoever your institution’s default is — check with your tech transfer office if you’re not sure).
Other reasonable choices:
- Apache 2.0 — like MIT plus an explicit patent grant. Preferred by industry for larger projects.
- BSD-3-Clause — like MIT, with a “no endorsement” clause.
- GPL-3.0 — copyleft: any derivative must also be GPL. This is a strong choice with real consequences for adoption; make sure it’s what you want.
“I’ll pick a license later” reads to the outside world as “you can’t use this.” If you have a good-faith reason to keep the code private, keep the repo private. If you want other people to be able to use it, pick a license today.
2. Write a README.md that answers five questions
Your README doesn’t need to be beautiful. It does need to answer, in this order:
- What is this? — One sentence. “This is X, which does Y.” Not “This is X, an award-winning innovative platform for reimagining Y.”
- Who is this for? — “Graduate students entering Earth-observation ML who want a data pipeline that supports multiple missions” is a real answer. “Anyone interested in AI” is not.
- How do I install it? — Ideally one line. If you need three lines, that’s OK; if you need thirty, invest in packaging (Step 3) instead.
- How do I run one working example? — A minimum working example. Copy-pasteable. Uses either sample data bundled in the repo or public data. This is the single biggest determinant of whether anyone actually adopts your code.
- How do I cite this? — Point at your
CITATION.cfffile (Step 4 of this chapter) or at your Zenodo DOI once you have one.
Optional but strongly recommended sections: prerequisites, links to any papers that describe the method, a screenshot or diagram, contributor list, license.
The geoai-datacubes README (source) is a working reference implementation of this pattern.
3. .gitignore from day one
You will accidentally try to commit something you shouldn’t. A good .gitignore catches it before it happens.
The Python.gitignore from GitHub covers 90% of what you need. Add to it:
# secrets
.env
.env.*
credentials.json
*.pem
*.key
# local data / outputs
data/
outputs/
runs/
wandb/
lightning_logs/
mlruns/
checkpoints/
*.pt
*.pth
*.h5
*.zarr/
*.tif
*.tiff
# OS files
.DS_Store
Thumbs.db
# IDE
.vscode/
.idea/
.gitignore it
Adding a file to .gitignore only stops future commits. If you have already committed an API key, a password, or a private data file, it is in git history forever until you rewrite that history with git-filter-repo and force-push — a slow, risky operation. See the Common pitfalls appendix for the recipe. Rotate the credential first regardless.
4. CITATION.cff — how people cite your code
The Citation File Format (CITATION.cff) is a small YAML file at the repo root that tells GitHub, Zenodo, and citation managers how to cite your work. GitHub renders it as a “Cite this repository” button on the sidebar, so a visitor can grab a BibTeX or APA string in one click.
A minimum CITATION.cff:
cff-version: 1.2.0
message: "If you use this software, please cite it as below."
title: "yourthing: what it does in one line"
authors:
- family-names: Smith
given-names: Jane
orcid: "https://orcid.org/0000-0000-0000-0000"
affiliation: "The Ohio State University"
version: 0.1.0
date-released: "2026-07-05"
repository-code: "https://github.com/yourorg/yourthing"
url: "https://github.com/yourorg/yourthing"
license: MITOnce you have a Zenodo DOI (Step 2 of the handbook), add:
doi: "10.5281/zenodo.1234567"And once you have a JOSS paper, add a preferred-citation block pointing to the paper. geoai-datacubes’ CITATION.cff is a working example.
5. A minimum viable package layout
Even if you’re not planning to publish to PyPI yet, put your code in a directory that has the same name as the package you want to publish under. It costs nothing now and saves refactoring later.
yourthing/
├── README.md
├── LICENSE
├── CITATION.cff
├── .gitignore
├── pyproject.toml # (optional at this stage, required for Level 1)
├── yourthing/ # the actual Python package
│ ├── __init__.py
│ ├── main.py
│ └── ...
├── tests/ # even if empty for now — Level 1 wants it
│ └── test_smoke.py
└── examples/ # or `notebooks/` — one working example
└── quickstart.ipynb
If your current code is one big Jupyter notebook, this is the moment to break it into a package with a callable API. This refactor is usually the single hardest part of Level 1 for a first-time author — plan a full day for it, not an hour.
6. Choose the repository name carefully
Your GitHub repository name will become:
- Your PyPI package name (usually)
- Your Zenodo record title (concept DOI)
- The name people type when they cite you
- Part of your JOSS paper URL
Rules of thumb:
- Lowercase, hyphens or underscores — matches Python packaging conventions.
- Distinctive enough to search for — “modeling-tools” will get lost.
- Short enough to type — “my-earth-observation-data-pipeline-for-machine-learning” is not it.
- Available on PyPI — check
pip searchor just try to reserve the name. - Not a trademark of somebody else — do not name your package “Copernicus” if you’re not ESA.
If you’re going to publish to PyPI (Level 1), reserve the name on PyPI early — see Common pitfalls for the name-squatting story.
Checklist
Once you can tick every box, you’re ready for Step 2 — Zenodo DOI.