Open-source Clinical Study Report builder

Versioned numbers, versioned words, one traceable loop.

Every number in an open.csr report is computed by a versioned spec, serialized as an Analysis Results Dataset, rendered into a display, and bound — never retyped — into the sentence that quotes it. Change the request, regenerate the number, and the prose moves with it as one transaction.

Open the demo reportSee the evidenceRead the design

The demo is one view with four ways in — the assembled documents, the table and ARD behind any number, the prose that quotes them, and the document models they assemble into.

10displays registered10 generated
33text blocksbinding numbers, not stating them
316reviewed requirements15 matrices
546test recordsjs-unit · r-unit · text-review

The documents

One study, one set of ARDs, one values store — and every document the template library holds, assembled from them. The same display is a different table number in each, from one unchanged specification.

prose approved

Abbreviated Clinical Study Report (ICH E3)

library/templates/e3-abbreviated

18 of 75 sections populated · 10 prose blocks

Read it → · Its document model →

planned

Statistical Analysis Plan

library/templates/

Planned. Needs a SAP template in library/templates/ before it can assemble.

The gap open.csr occupies

Open source owns the numbers

pharmaverse, NEST and the R Consortium pilots generate submission-grade tables — and stop at the output object.

Commercial owns the words

CoAuthor, Yseop, TriloDocs and Narrativa assemble documents — and treat the TFL package as an opaque, already-final input.

Both halves break at the same seam: prose quotes numbers the authoring tool did not compute. Cross-checking numbers against tables is a patch over that seam. open.csr closes it.

The closed loop

  1. 1Change requestA reviewer asks for a risk-difference column on the AE overview.
  2. 2Spec diffThe agent proposes an edit to analysis.yaml — reviewable, small, versioned.
  3. 3RegenerationThe pipeline writes a new outputs/<slug>/vNNN/: spec snapshot, ARD, display, manifest.
  4. 4Re-bindingEvery sentence that binds a number from that display re-resolves against the new ARD.
  5. 5GateCI diffs the ARD, re-checks numeric fidelity, and republishes the evidence.

One transaction, fully versioned, every artifact reproducible from the commit. Agents write source; humans approve; the pipeline is the only thing that regenerates.

Architecture

 pharmaverseadam ──▶ data-prep ──▶  ARDs  ──▶ displays ──▶ assembled CSR ──▶ demo site
      (ADaM)        (R, tested)    (cards)   (gt/tfrmt/    (Node, from       (GitHub
                                              r2rtf)        the E3 model)     Pages)
                         ▲            ▲           ▲              ▲
                library/tfl/    library/tfl/  library/text/  library/templates/
                analysis.yaml   display.yaml   text blocks    ich-e3/
                iterations.yaml                     ▲         sections.yaml
                                                    │         assembly.yaml
                                              library/values/
                                              values.yaml — a number named once,
                                              resolved from the committed ARDs

 ┌──────────────────────────────────────────────────────────────────────────┐
 │  quality/ — requirement matrices · testthat + vitest evidence · guards    │
 └──────────────────────────────────────────────────────────────────────────┘

TFL Builder + Library

library/tfl/<slug>/

  • analysis.yaml — what to compute (ARS-aligned)
  • display.yaml — how to show it
  • iterations.yaml — every saved regeneration

Values Store

library/values/values.yaml

  • A number the report reuses, named once
  • source — an address into a committed ARD
  • derived — declared arithmetic, closed vocabulary

Text Library

library/text/<ID>.md

  • Three tiers: boilerplate, parameterized, generated
  • Numbers arrive as {{ard:…}} bindings
  • Approval state travels in the frontmatter

Report Template Library

library/templates/<id>/

  • A document as data: sections, content models
  • Assembly slots and display numbering at build time
  • Provenance appendix generated mechanically

How the four connect, end to end, with one display followed from the dataset to the sentence that quotes it: the data design framework.

Traceability, end to end

Every number on this site answers five questions — which dataset, which spec, which ARD row, which display, which sentence.

adam (pkg version + hash) → data-prep manifest → ard.json (rows + envelope)
  → display vNNN (manifest: spec hash, commit) → CSR slot (assembly.yaml) → text binding

The CSR Reader renders that chain as a trace panel: click a bound number and the whole provenance path opens beside it.