Draft a complete JAMA Network Open paper in LaTeX using the template and all upstream outputs. Produces paper.tex with structured abstract (7 subsections), Key Points box, Introduction, Methods, Results, Discussion, Limitations, Conclusions, and Supplement. Follows JAMA writing conventions. Triggers on: "write paper", "draft paper", "write the manuscript", "generate LaTeX", or any request to produce the paper from analysis results.
Draft a complete JAMA Network Open research paper in LaTeX, integrating all upstream analysis outputs.
/write-paper <output_folder>
Reads from all upstream stage outputs in <output_folder>/ and the template at sample/tex/template.tex. Writes to <output_folder>/6_paper/.
This skill uses progress_utils.py for stage-level progress tracking. Progress is saved to <output_folder>/6_paper/progress.json.
Steps tracked:
step_1_load_inputs: Load all upstream outputs and templatestep_2_copy_assets: Copy figures, tables, references to stage folderstep_3_draft_paper: Write complete paper.tex contentstep_4_validate: Validate LaTeX structure and completenessIf interrupted, read and continue from the last incomplete step.
progress.jsonIf progress.json says last completed is... | Resume at |
|---|---|
step_1_load_inputs | Step 2: Copy assets |
step_2_copy_assets | Step 3: Draft paper |
step_3_draft_paper | Step 4: Validate |
step_4_validate | Complete (skip) |
You are a medical writer experienced in drafting JAMA Network Open research articles. Write a complete, publication-ready manuscript integrating statistical results, figures, tables, and references.
Initialize progress tracker and load helper module at start:
import sys
sys.path.insert(0, "workflow/scripts")
sys.path.insert(0, "workflow/skills/write-paper")
from progress_utils import create_stage_tracker
from write_paper import (
load_all_inputs, copy_assets, generate_paper_skeleton,
validate_paper_tex, format_stat, format_descriptive, format_count_pct
)
tracker = create_stage_tracker(output_folder, "write_paper",
["step_1_load_inputs", "step_2_copy_assets", "step_3_draft_paper", "step_4_validate"])
Use the helper function to load all upstream outputs:
inputs = load_all_inputs(output_folder)
if not inputs["ready"]:
raise RuntimeError(f"Missing required inputs: {inputs['missing_required']}")
This loads:
<output_folder>/2_scoring/ranked_questions.json — Research questions, variable roles, study design.
1b. <output_folder>/decision_log.json (if exists) — Question selection audit trail. Use to describe the question selection process in the Methods section (e.g., number of candidates considered, scoring approach, any feedback cycles).<output_folder>/3_analysis/analysis_results.json — All statistical results.<output_folder>/4_figures/manifest.json — List of figures and tables with titles and file paths.<output_folder>/5_references/references.bib — Bibliography entries.workflow/templates/template.tex — The JAMA Network Open LaTeX template.<output_folder>/1_data_profile/profile.json — Dataset context for data description.Use the helper function:
copied = copy_assets(output_folder)
This handles:
references.bib to <output_folder>/6_paper/references.bib..png and .pdf) from <output_folder>/4_figures/figures/ to <output_folder>/6_paper/figures/..tex files from <output_folder>/4_figures/tables/ to <output_folder>/6_paper/tables/.Option A — Generate skeleton first, then fill in content:
skeleton = generate_paper_skeleton(output_folder, "workflow/templates/template.tex", inputs)
This creates paper.tex with the full LaTeX preamble, section structure, and %%FILL: markers where you must write content. Then edit the file to replace all %%FILL: markers with actual paper content.
Option B — Write paper.tex from scratch using the template.
Either way, the final <output_folder>/6_paper/paper.tex must contain these sections:
\usepackage, color definitions, style settings).\usepackage[T1]{fontenc} and \usepackage{lmodern} (before \usepackage{times}). This prevents font-size substitution warnings for fractional sizes (8.5pt, 7.5pt) used in JAMA-style captions.\usepackage{microtype} if present. The times/helvet fonts have no protrusion tables; loading microtype produces ~20 harmless but noisy warnings with no benefit for these fonts.\jamashorttitle{} with a short version of the paper title.\jamasubject{} with the appropriate subject area (e.g., "Public Health").{\sffamily\bfseries\fontsize{18}{21}\selectfont\color{jamadarkgray}
Full Title of the Paper: A Descriptive Subtitle\par}
Use the template's \abslabel{} and \absrule commands:
| Subsection | Content | Length |
|---|---|---|
| IMPORTANCE | Why this study matters — gap in knowledge | 1-2 sentences |
| OBJECTIVE | Research aim, starting with "To determine..." or "To evaluate..." | 1 sentence |
| DESIGN, SETTING, AND PARTICIPANTS | Study design, data source, time period, sample size, eligibility | 2-3 sentences |
| EXPOSURE | Primary exposure/intervention description | 1 sentence |
| MAIN OUTCOMES AND MEASURES | Primary outcome definition and analytic approach | 1-2 sentences |
| RESULTS | Key demographics (N, age, sex), then main findings with effect sizes and CIs | 3-4 sentences |
| CONCLUSIONS AND RELEVANCE | Interpretation and implications | 1-2 sentences |
Fill the three fields in the keypointsbox:
Structure:
Subsections:
research_questions.json.analysis_results.json → primary_analysis.method. State software ("Analyses were performed using Python version 3.x with statsmodels and pandas."), significance level ("Statistical significance was set at 2-sided P < .05."), and any special techniques.Note: Figures and tables within this section will occupy ~0.5-1 page, reducing available word space.
Structure:
Structure:
research_questions.json → feasibility_assessment.limitations.2-3 sentences. Summarize the main finding and its primary implication. Do not overstate.
{\fontsize{8.5}{10.5}\selectfont
\bibliographystyle{vancouver}
\bibliography{references}
}
CRITICAL: The supplement must be populated with actual statistical content from analysis_results.json, NOT placeholder text. Extract information and generate well-written supplementary content using the LLM.
On a new page after references:
\clearpage
\section*{Supplement 1}
Then generate these sections by extracting from analysis_results.json:
eAppendix 1: Statistical Model Specification
Extract from analysis_results.json → primary_analysis:
method (e.g., "OLS Linear Regression", "Logistic Regression", "Poisson Regression")outcome (primary outcome variable)exposure (primary exposure variable)models[].covariates (list of adjustment variables)Generate:
Model equation in proper LaTeX math format — Use the appropriate form for the method:
$Y = \beta_0 + \beta_1 X_1 + \beta_2 X_2 + \cdots + \beta_k X_k + \epsilon$$\operatorname{logit}[P(Y=1)] = \beta_0 + \sum_{j=1}^{k} \beta_j X_j$$\log(\mathbb{E}[Y]) = \beta_0 + \sum_{j=1}^{k} \beta_j X_j$$h(t|X) = h_0(t) \exp(\sum_{j=1}^{k} \beta_j X_j)$Variable definitions — Define each term in the equation:
primary_analysis.outcome]primary_analysis.exposure]primary_analysis.models[].covariates]Software and packages — State software used:
Estimation method — Brief description:
Example LaTeX structure:
\subsection*{eAppendix 1. Statistical Model Specification}
The primary analysis used [method] to examine the association between [exposure] and [outcome]. The model was specified as:
\[
\operatorname{logit}[P(Y=1)] = \beta_0 + \beta_1 \text{[Exposure]} + \beta_2 \text{[Covariate}_1] + \beta_3 \text{[Covariate}_2] + \cdots + \beta_k \text{[Covariate}_{k-1}]
\]
where $Y$ represents [outcome description], $\text{[Exposure]}$ indicates [exposure description], and the remaining terms represent adjustment variables: [list covariates from model].
Model parameters were estimated using maximum likelihood. All analyses were performed using Python 3.x with statsmodels.
eAppendix 2: Model Assumption Checks and Diagnostic Results
Extract from analysis_results.json → look for any assumption-related fields:
primary_analysis.assumption_checks if it existsprimary_analysis.model_fit (R², AIC, BIC, etc.)primary_analysis.models[].r_squared, adj_r_squared, df_resid for fit statisticsGenerate:
Model fit statistics — Report for each model:
Assumption checks — If available in the results, report:
If no formal assumption checks in JSON, still document:
Example LaTeX structure:
\subsection*{eAppendix 2. Model Fit and Assumption Checks}
\textbf{Model Fit Statistics.} Table eTable 1 presents the full model results for all specifications. The primary model (Model [n]) achieved an $R^2$ of [value], indicating that [percent]\% of the variance in [outcome] was explained by the included predictors.
\textbf{Assumption Checks.} [If available: "The following assumptions were evaluated: [list]. [Assumption name] was assessed using [test name]; results indicated [passed/failed] (P = [value])."]
[If assumptions failed: "To address [issue], [remedial action taken] was used."]
eTable 1: Full Model Results
Extract from analysis_results.json → primary_analysis.models[] and generate a complete coefficient table.
For each model in the array, create rows showing:
Use JAMA table style (no vertical rules, booktabs, \toprule, \midrule, \bottomrule):
\subsection*{eTable 1. Full Model Results for Association Between [Exposure] and [Outcome]}
\begin{table}[H]
\centering
\sffamily\fontsize{8.5}{11}\selectfont
\caption{Complete Regression Results for All Model Specifications}
\label{tab:e1}
\begin{tabularx}{\textwidth}{@{} >{\raggedright\arraybackslash}p{4.5cm}
*{4}{>{\centering\arraybackslash}X} @{}}
\toprule
\textbf{Variable} & \textbf{Model 1\newline(Unadjusted)} & \textbf{Model 2\newline(Region Adjusted)} & \textbf{Model 3\newline(Fully Adjusted)} \\
\cmidrule(lr){1-1} \cmidrule(lr){2-2} \cmidrule(lr){3-3} \cmidrule(lr){4-4}
& $\beta$ (SE) & $\beta$ (SE) & $\beta$ (SE) \\
\midrule
Intercept & [estimate] ([SE]) & [estimate] ([SE]) & [estimate] ([SE]) \\
[Exposure] & [estimate] ([SE]) & [estimate] ([SE]) & [estimate] ([SE]) \\
[Covariate 1] & & [estimate] ([SE]) & [estimate] ([SE]) \\
[Covariate 2] & & [estimate] ([SE]) & [estimate] ([SE]) \\
\midrule
\multicolumn{4}{@{}l}{\textbf{Model fit}} \\
$N$ & [n] & [n] & [n] \\
$R^2$ & [r2] & [r2] & [r2] \\
\bottomrule
\end{tabularx}
\vspace{4pt}
\begin{flushleft}
\fontsize{7.5}{9.5}\selectfont\rmfamily\color{jamagray}
SE indicates standard error. Model 1 includes [exposure] only. Model 2 adjusts for [covariates]. Model 3 adds [additional covariates].
\end{flushleft}
\end{table}
Important formatting rules:
\beta for the coefficient symbol, never β95\% not 95%eTable 2: Sensitivity Analysis Summary (if applicable)
Extract from analysis_results.json → sensitivity_analyses[]
If sensitivity analyses exist, create a comparison table:
\subsection*{eTable 2. Sensitivity Analysis Results}
\begin{table}[H]
\centering
\sffamily\fontsize{8.5}{11}\selectfont
\caption{Comparison of Primary Analysis With Sensitivity Analyses}
\label{tab:e2}
\begin{tabularx}{\textwidth}{@{} >{\raggedright\arraybackslash}p{5cm}
*{2}{>{\centering\arraybackslash}X} @{}}
\toprule
\textbf{Analysis} & \textbf{Estimate (95\% CI)} & \textbf{P Value} \\
\midrule
Primary analysis & [estimate] ([CI]) & [p-value] \\
[Sensitivity 1 name] & [estimate] ([CI]) & [p-value] \\
[Sensitivity 2 name] & [estimate] ([CI]) & [p-value] \\
\bottomrule
\end{tabularx}
\vspace{4pt}
\begin{flushleft}
\fontsize{7.5}{9.5}\selectfont\rmfamily\color{jamagray}
CI indicates confidence interval. [Sensitivity analysis descriptions from JSON].
\end{flushleft}
\end{table}
If no sensitivity analyses exist, omit this section entirely.
eFigure 1 (Optional) — If there are supplementary figures in 4_figures/, include them:
\subsection*{eFigure 1. [Figure Title]}
\begin{figure}[H]
\centering
\includegraphics[width=0.9\textwidth]{figures/figureX.pdf}
\caption{[Caption from manifest.json]}
\label{fig:e1}
\end{figure}
Content Generation Guidelines:
analysis_results.json — no fabrication.\beta, \leq, etc., never Unicode.CRITICAL: Always use LaTeX commands, NEVER Unicode characters for mathematical symbols. Unicode characters (β, α, χ², ≥, ≤, μ, σ) cause LaTeX compilation failures or inconsistent rendering.
| Symbol | Use | NEVER |
|---|---|---|
| Greek letters | \alpha, \beta, \chi, \mu, \sigma, \kappa, \lambda, \tau | α, β, χ, μ, σ, κ, λ, τ |
| Comparisons | \geq, \leq, \approx, \neq, \pm | ≥, ≤, ≈, ≠, ± |
| Superscript | ^2, ^{2} | ² |
| Subscript | _2, _{2} | ₂ |
| Math mode | $\beta = 0.5$ or \(\beta = 0.5\) | β = 0.5 (plain text) |
| P-value | $P < .05$ or \textit{P} < .05 | P < .05 (no formatting) |
| CI notation | 95\% CI (with escaped percent) | 95% CI (unescaped) |
Before finalizing paper.tex, search for common Unicode patterns and replace with LaTeX:
grep -n '[αβγδεζηθικλμνξοπρστυφχψω]' paper.tex
grep -n '[≥≤≈≠±]' paper.tex
grep -n '[²³¹₀₁₂₃₄₅₆₇₈₉]' paper.tex
Examples of correct usage:
\cite{key} which produces superscript numbers via natbib.\input{tables/table1.tex} for tables and \includegraphics for figures.For figures:
\begin{figure}[H]
\centering
\includegraphics[width=\textwidth]{figures/figure1.pdf}
\caption{Descriptive title from manifest.json}
\label{fig:figure1}
\end{figure}
For tables, input the pre-generated .tex file:
\input{tables/table1.tex}
Use the helper function for automated validation:
validation = validate_paper_tex(output_folder)
if not validation["passed"]:
print(f"Errors: {validation['errors']}")
# Fix errors and re-validate
The validator checks:
paper.tex is valid LaTeX (balanced braces, environments, commands)\cite{} keys match entries in references.bib\includegraphics{} paths point to files that exist in 6_paper/figures/\input{} paths point to files that exist in 6_paper/tables/references.bib is copied to <output_folder>/6_paper/\beta, \logit, etc., not Unicode)analysis_results.jsonLaTeX compilation validation:
Run the following command to validate the LaTeX file compiles without fatal errors:
cd <output_folder>/6_paper && latexmk -pdf -interaction=nonstopmode paper.tex
Alternatively, use the traditional pdflatex+bibtex workflow. You must run exactly 4 commands in sequence — do not skip passes:
cd <output_folder>/6_paper
pdflatex -interaction=nonstopmode paper.tex # pass 1: builds aux, may show ?? in page numbers
bibtex paper # resolves citations
pdflatex -interaction=nonstopmode paper.tex # pass 2: reads citations + lastpage label
pdflatex -interaction=nonstopmode paper.tex # pass 3: resolves all cross-references, ?? disappears
Why 3 pdflatex passes are required:
\newlabel{LastPage} and citation labels to .aux — page numbers show ??.aux; resolves citations but may still have stale references\pageref{LastPage} correctly shows total page countAfter compilation, verify there are no ?? in the PDF:
pdftotext paper.pdf - | grep "??"
If any ?? remain, run pdflatex one more time.
What constitutes a fatal error vs. warning:
! error, PDF not generated, undefined control sequence, missing file errors?? in page numbers: Not a warning — means too few pdflatex passes. Run another pass.If compilation fails, check the .log file for specific error messages and fix accordingly.
If upstream files are missing:
2_scoring/ranked_questions.json — Re-run the score-and-rank stage3_analysis/analysis_results.json — Re-run the statistical-analysis stage4_figures/manifest.json — Re-run the generate-figures stage5_references/references.bib — Re-run the literature-review stagetemplate.tex — Verify sample/tex/template.tex existsIf LaTeX compilation fails:
paper.log for the specific error (search for ! which indicates errors)\includegraphics{} and \input{} paths$: Math symbols outside math modeIf citation keys don't resolve:
\cite{key} matches an @entry{key,} in references.bibreferences.bib is in the same directory as paper.texIf figures/tables don't appear:
6_paper/figures/ or 6_paper/tables/\includegraphics{} and \input{} are relative to 6_paper/.tex file is valid LaTeX table codeAdditionally, manually verify:
analysis_results.json values exactlyFormat statistics using the helper:
# JAMA-style formatting
stat_text = format_stat(-23.4, -35.2, -11.5, "<0.001")
# → "-23.4 (95\\% CI, -35.2 to -11.5; P < .001)"
desc_text = format_descriptive(41.6, 24.9)
# → "41.6 (SD, 24.9)"
count_text = format_count_pct(16, 30.8)
# → "16 (30.8\\%)"
Progress checkpoint - Mark stage complete:
from progress_utils import complete_stage
complete_stage(output_folder, "write_paper",
expected_outputs=["6_paper/paper.tex", "6_paper/references.bib"])
<output_folder>/6_paper/paper.tex — Complete LaTeX source file.
<output_folder>/6_paper/references.bib — Copy of bibliography.
<output_folder>/6_paper/figures/ — Copies of all figure files (.png, .pdf).
<output_folder>/6_paper/tables/ — Copies of all LaTeX table files (.tex).