Step 7 — paper.md + paper.bib
The JOSS paper: what it is and how to write it
The Journal of Open Source Software is a peer-reviewed venue whose “paper” is a ~1000-word Markdown file stored at the top of your GitHub repo. That file, plus a BibTeX file with your references, is your submission. There is no LaTeX to fight, no journal template to download, no page-charge invoice.
The paper is not the primary thing reviewers evaluate — the software is. Their code review is on GitHub, in the open. But the paper is what shows up in Google Scholar once published, and what your readers will cite. So it’s worth writing well.
This chapter walks through what belongs in paper.md, what belongs in paper.bib, and how to keep both under JOSS’s word-count guidance.
The two files, side by side
At the repo root:
yourthing/
├── paper.md
├── paper.bib
└── ...
paper.md — the manuscript itself, in pandoc-flavoured Markdown with a YAML front-matter block for authors + metadata.
paper.bib — BibTeX file with every reference. When JOSS’s Inara/pandoc pipeline renders the paper, it reads paper.bib, walks paper.md for [@key] citations, and formats a References section automatically.
The paper.md front matter
The YAML block at the top of paper.md looks like this:
---
title: 'yourthing: what it does in one line'
tags:
- Python
- your subfield tag
- one or two more discoverability keywords
authors:
- name: Jane Smith
orcid: 0000-0000-0000-0000
corresponding: true
affiliation: '1, 2'
- name: Alice Chen
affiliation: 3
affiliations:
- name: 'School of Earth Sciences, The Ohio State University, Columbus, OH, USA'
index: 1
- name: 'BuckAI Observatory, The Ohio State University, Columbus, OH, USA'
index: 2
- name: 'Department of Computer Science, University X, City, Country'
index: 3
date: 2026-07-05
bibliography: paper.bib
---Every author needs an ORCID. Get one at https://orcid.org. Corresponding-author flag with corresponding: true — usually the person driving the submission.
Chasing down four students on Slack for their ORCIDs while the submission form has a countdown timer is not fun. Ask for them when you first add the author to paper.md — it takes each person three minutes.
The five (soft) sections
JOSS doesn’t mandate section headings, but reviewers expect this rough structure:
1. Summary (~200-300 words)
What the software is, what it does, and who it’s for — in the most accessible language you can manage. Assume the reader is a scientist in an adjacent field, not your subfield. Name the key concepts and cite the key tools.
Avoid marketing language. “State-of-the-art,” “innovative,” “revolutionary,” “cutting-edge” are red flags for a JOSS reviewer.
2. Statement of need (~300-500 words)
Why this software exists, what problem it solves, and what fills that space right now.
Structure this as: (a) what a typical workflow currently looks like without your software, (b) what silently goes wrong in that workflow, (c) how your software fixes it, and (d) one or two concrete architectural decisions that distinguish your library from generic alternatives.
The Statement of need is the section that most often bounces a submission. Reviewers want to see that you have identified a real gap — not “there’s no Python package called yourthing yet” but “here is a specific problem that people currently solve in a specific costly way, and here is why our approach helps.”
4. Research applications (~50-150 words)
Evidence that the software is actually used in research. This became more important with JOSS’s January 2026 scope-and-significance update, which explicitly weighs “papers or preprints citing the software” as the strongest signal of research impact.
Cite any papers — yours, your collaborators’, anyone else’s — that use the software. A preprint counts. A conference paper counts. Aspirational “will be used” statements do not count.
If your software is brand-new and hasn’t been cited anywhere yet, JOSS will still consider the submission, but expect closer scrutiny on the Statement of need.
5. Acknowledgements + AI disclosure
Standard funding acknowledgements, then the AI-assistance disclosure, which JOSS now formally requires. See AI-assisted development for the specific wording and what has to be covered.
Followed by a # References heading — this is the anchor pandoc uses to inject the formatted reference list. Leave the section body empty; the machinery fills it in during compile.
# ReferencesThat’s the whole section in the source file.
The paper.bib
Standard BibTeX. Every entry in paper.bib should be cited in paper.md ([@key] inline), and every citation in paper.md should have an entry in paper.bib. Nothing dangles.
A trick that costs nothing: at the end of every writing session, grep both files:
# keys cited in paper.md
grep -oE '\[@[a-zA-Z0-9_-]+' paper.md | sort -u
# entries defined in paper.bib
grep -oE '^@\w+\{[^,]+' paper.bib | sort -uThe two lists should match. Uncited entries create a “reviewers wondering why you added this” question. Un-defined citations fail the pandoc render.
Word count: the 1000-word soft cap
JOSS suggests 250-1000 words. This is a soft cap — many published papers are longer, some by quite a bit. But if you’re pushing past 1500 words, ask yourself whether every paragraph is earning its place. Reviewers with time pressure will thank you for brevity.
Count words minus code blocks, front matter, and citations:
python3 -c "
import re
text = open('paper.md').read()
text = re.sub(r'\`\`\`.*?\`\`\`', '', text, flags=re.DOTALL) # code blocks
text = re.sub(r'^---.*?---', '', text, flags=re.DOTALL) # frontmatter
text = re.sub(r'\[@[^\]]+\]', '', text) # citation tokens
print(len(text.split()), 'words')
"Local rendering to PDF — the draft workflow
You will want to see your paper as a formatted PDF before submitting. Two options:
Option A — Docker (if you have Docker locally)
docker run --rm \
--volume "$PWD:/data" \
--user $(id -u):$(id -g) \
--env JOURNAL=joss \
openjournals/inaraThis produces paper.pdf in the same directory as paper.md. Uses the exact same Inara/pandoc pipeline that JOSS itself uses on its acceptance side, so if this renders your paper cleanly, JOSS’s compile will too.
Option B — GitHub Actions (no local Docker needed)
Add .github/workflows/draft-pdf.yml:
name: Draft PDF
on:
push:
paths: [paper.md, paper.bib, .github/workflows/draft-pdf.yml]
pull_request:
paths: [paper.md, paper.bib, .github/workflows/draft-pdf.yml]
workflow_dispatch:
jobs:
paper:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build draft PDF
uses: openjournals/openjournals-draft-action@master
with:
journal: joss
paper-path: paper.md
- uses: actions/upload-artifact@v4
with:
name: paper
path: paper.pdfNow every push that touches paper.md or paper.bib builds a PDF you can download from the workflow’s Artifacts section. Very useful for iterating.
Common issues in paper.md
Empty References section in the PDF. — Expected. # References at the end of paper.md is a placeholder that pandoc fills in at compile time from paper.bib citations.
Placeholder text in the footer (¿VOL?, ¿ISSUE?, ¿PAGE?, 01 January 1970). — Also expected. Inara’s intentional placeholders for values that don’t exist until acceptance. Don’t try to override them.
Unicode glyphs render as boxes or �. — Font-substitution failure in the JOSS template. The safest fix is to move to inline LaTeX math: F1 $\approx 0.95$ instead of the bare ≈ glyph.
Missing ORCID icon in the byline. — The author has no orcid: in the YAML front matter. Add it.
Checklist
When your PDF renders cleanly and your co-authors have signed off on the manuscript, on to Step 8 — JOSS submission form walk-through.