This tutorial is for a statistician who has never used Sapling. You start from a protocol and finish with a draft
statistical analysis plan (SAP), its PDF, and the structured SAP that the analysis chain reads. You do not need to
know the Sapling syntax: the editor writes the first plan from the protocol, and you work in the visual editor, a
document with forms. The compiler checks every change at once. The .qmd file under it stays the one source, and you
can show it beside the document at any time.
The example is the CDISC pilot study (CDISCPILOT01, protocol H2Q-MC-LZZT). Its protocol is in
examples/cdiscpilot01/protocol/ of the Sapling repository: CDISC_Pilot_Study_v4.json (the protocol as CDISC USDM)
and protocol.json (its text, section by section). Its ADaM specification is in examples/cdiscpilot01/adam/.
The short way: one command line (Rails-style)#
If you like a terminal, five commands take a protocol and its SDTM data to the study dashboard (docs/omakase.md):
sapling new mystudy --protocol usdm.json --sdtm path/to/sdtm # the study folder and a first SAP with the defaults
cd mystudy && sapling open # the SAP in the visual editor: change what you like
sapling decide # the open decisions; answer each with --by "<your name>"
sapling build && sapling run # the PDF, the specs, the programs, the ADaM, the TLFs
sapling dashboard # the study dashboard
The status bar of the editor shows the next step ("Next: sapling build"), and the insert palette (+ or /) has the same generators under Ready-made from your protocol. The rest of this tutorial does it in the editor, step by step.
Before you start (once, 3 minutes)#
| You need | How |
|---|---|
| VS Code or Positron | any recent version |
| The Sapling extension | cd vscode && npm install && npm run package, then code --install-extension vscode/sapling-sap-0.7.0.vsix (Positron: its code command, or Extensions → … → Install from VSIX) |
| Your AI agent (optional) | the AI command-line agent you already use, a local model, or any command: install it, log in once, and choose it in the setting sapling.ai.provider. Sapling uses your own login; it never reads or stores a key. Everything except Ask AI works without it. |
| Quarto (for the PDF) | install it from https://quarto.org/docs/get-started/ (sapling doctor checks it) |
Open the folder examples/cdiscpilot01 in the editor (File → Open Folder).
1. A first plan from the protocol (1 minute)#
- Open the Command Palette (⇧⌘P, or Ctrl+Shift+P) and run Sapling: New SAP from Protocol (USDM)….
- Choose
CDISC_Pilot_Study_v4.jsonin the list of the protocols (CDISC USDM) of the folder (Another file… opens a file dialog). The editor findsprotocol/protocol.json(the protocol's text) and theadam/folder (the ADaM specification) by itself. - Keep the study id it proposes, or type
CDISCPILOT01. Save the plan asstudy.qmd.
The plan has the sections of a SAP in the order of the SAP guideline (Gamble et al. 2017) and already contains what the protocol says: the three arms, the visits, the significance level, the design, the planned 300 patients, the objectives and endpoints, the estimand EST1, three populations and the tests that the protocol names. Each rests on a sentence of the protocol. Everything the protocol leaves open is an open decision (about 29). The plan compiles with 0 errors.
2. The visual editor (1 minute)#
The plan opens in the visual editor, as a document that looks like its PDF: the cover with the title and the DRAFT
mark, the contents and the progress on the left (the decisions made, the blocks with a source, the findings left), the
sections, the text, the populations, the tables and the estimand. A strip on top of a new plan says what to do next.
The bar on top shows the state: Compiles (or the number of errors), the warnings of the review, the open decisions.
Click one: the navigator lists them all with their message, their source and their section; a click goes there, and
the count, the arrows of the list, F8 and ⇧F8 step through them. ⇧⌘K (or the search button) finds a
section or a block by its words (MMRM, SAFFL, Week 24) and inserts a block ("insert table").
- Text: click in a paragraph and type. The commands in the text are chips: a citation (
§4.2), a variable, a test, an equation. Click a chip to change it. Select words for B, I, code, math or Cite. - Blocks: click a population, a table or the estimand. It opens as a form; Done (or Esc) closes it.
- The Markdown: click Markdown. The
.qmdopens beside the document. A change on one side shows on the other side at once. Undo (⌘Z) and save (⌘S) work as in any file.
Plans open in the visual editor by default; to open them as text: Sapling: Use the Visual Editor for Plans by Default (on/off).
3. Change a block with its form (2 minutes)#
Go to Analysis populations (in Statistical principles) and click the efficacy population.
- The sentence reads: The
Efficacy populationare the subjects whereADSL.EFFFLis Y. The condition builder offers the ADaM variables with their labels, and the codelist values of each variable. Click + condition to add a clause. - Source shows the closest sentence of the protocol when the block has none: Use this source cites it. Or click Cite the protocol (or Change beside the source), type words, for example postrandomization measurement, and click the sentence. The citation is written with the words that find it in the protocol.
- An open decision has Decide it: write your answer and your name, Record my decision. Your name and today's
date go into the plan (
answer="..." by="..." on="..."); the AI never decides. - Comment (on the card's tools) leaves a note for the author or the reviewer: an HTML comment
(
<!-- review (Name, date): text -->) above the block, shown on its card with Resolve; the PDF does not show it.
The first plan has no tables yet. Open pilot.qmd (the pilot SAP, written out) in the visual editor to see them, or
add one with + → Table (step 4). Go to the demographics table (4.2 of pilot.qmd). The table designer shows
the population, the Total column, the p-values, one row per variable with its test, and the footnotes. Click Categorical to add a row: it takes a variable that the table
does not show yet. Choose its test. The shell under the form (As typeset) changes as you type; the table button of
the card shows the shell as the chain makes it.
Go to the efficacy table (4.3.3) and click Model on the row P_ADAS. The equation is in an equation editor:
type in it, or open LaTeX under it (the math as text, as it is written between $$ in the plan). Each symbol is
bound to an ADaM variable (The symbols). The green box shows what the compiler reads: the formula
CHG ~ BASE + SITEGR1 + TRTPN, the method (ANCOVA, test for linear dose response), the dose, the covariates and the
factors. Options of the model makes it an MMRM (covariance us, the fallback structures in order, Kenward-Roger).
A new Model analysis row starts as an equation too; a row written as an R formula has Write it as an equation.
Under the model, the Method Lab (docs/method-lab.md) shows the analysis from four sides: Formula (the model,
the estimand to the estimator, the hypotheses, the test statistic, the CI), Program (R, SAS and pseudocode for
exactly this analysis, to copy or open), Assumptions (the checks on BLINDED data), Simulation (the type I error
and the power of the planned test, against the sample size) and Example (the program on dummy data, its numbers
labelled EXAMPLE). The R parts run when you click Run; the data mode is on every tab; unblinded data only when you
ask, each time. The data folder: the setting sapling.lab.data.
4. Add what the plan needs (3 minutes)#
Move the pointer between two blocks: a + shows on the left. Click it (or type / in the text) and choose a block: a population, an estimand, a table, an open decision, multiplicity, sample size, missing data, a sensitivity analysis, ... It is inserted as a form with values from your plan: a new Population takes the ADaM population flag the plan does not use yet (the safety flag first) with its name; the Adverse events table (TEAEs by SOC and PT), Demographics table, Efficacy table with a model and Table by visit come with the population that fits. A block's Duplicate makes a copy with new ids. For example, add Multiplicity, choose the procedure graphical, two hypotheses with their weights and the transitions: the graph is drawn under the form.
Ask AI (in the palette, on the bar, or on a card) drafts a block from your words, for example: Write a table of the treatment-emergent adverse events by maximum severity for the safety population. The draft is compiled in its place before you see it; when it does not compile, the compiler's messages go back to the AI (at most twice). You see the block typeset and "Compiles in its place". Nothing is written until you click Insert. The block carries the mark drafted by the AI until you read it and remove the mark.
5. Fix what the compiler finds (1 minute)#
A card with an error has a red mark in the margin; a card with a warning of the review an amber one. Open the card: the
messages are at the bottom, each with the fix, the guideline it rests on, and the quick fixes as buttons. For example,
when the plan says AVISIT = "WEEK 24", the card says "WEEK 24" is not a value of ADQSADAS.AVISIT and offers
Write AVISIT = "Week 24". A rule that the plan does not follow on purpose: Waive with a reason…, then write the
reason; the PDF shows it. A fix the visual editor cannot make as a button shows the text to write under Fix:. For
example the safety tables without a safety population have Add the safety population SAF and use it on ….
6. The PDF and the products (2 minutes)#
| Where | What you get |
|---|---|
| PDF (the bar of the visual editor) | out/study.pdf: title page with the approval table, the sections, the estimand boxes, the protocol's words under each block, the table shells in the appendix |
| Preview | the plan typeset beside the editor |
| Sapling: Build the Structured SAP | out/sap.md (the structured SAP the chain reads), out/sap.json, out/sap.html |
| Sapling: Run the Chain's Checker | the chain's own checker sap_build.py on the plan: SAP BUILD PASS (it needs the scratch chain: zsh tools/chain_proof.sh once) |
From a terminal: node src/cli.ts pdf study.qmd and node src/cli.ts build study.qmd.
What you did not do#
You did not approve the plan, and you did not decide the open decisions in the AI's place. Only a person approves:
when the decisions are made and the review is clean, the statistician writes approved: {by: Name, on: Date, role: statistician} under sapling:
and status: APPROVED under sapling: in the plan. The compiler, the AI and the MCP server refuse to write them.
Next#
- The language, block by block, with an example each: markdown.md. You need it only for what the forms do not show; every block also opens as Markdown (the code button on its card).
- The rules of the review and their sources: rules.md.
- The plan as a whole, from the protocol to the TLFs through the R chain:
zsh tools/full_chain.sh(README). - Without the editor's extension: the snippets for any VS Code (
vscode/snippets/sapling-markdown.code-snippets).