Reproducibility
Reproducible analysis means you can re-run exactly what you did — on the same data or on new data — and get the same result, and that someone else can read and verify your steps. ChakataStat is built around this: every menu action is also a command, and the commands form a stream you can read, edit, save, replay, batch and export.
The syntax console (.cks)
Open it with View → Syntax (Ctrl+4). It shows your session as an editable
ChakataStat syntax script — the .cks language. Every analysis, chart and
journalable transform you run from the menus appends a line here automatically:
descriptives variables=[Age, BMI, SystolicBP]
correlate variables=[BMI, SystolicBP], method=pearson
compute target=BMI_cat, expr="IF(BMI >= 30, 1, 0)"
histogram variable=BMI
The grammar is small and readable: toolname arg=value, arg=[a, b], arg="text",
with # for comments. A saved script's first line is one such comment,
# dataset <hash>, naming the data it was recorded against (see
the dataset fingerprint).
One command per line
A command occupies exactly one line, however long it gets. There is no line-continuation character, and this is deliberate rather than unfinished: the journal's contract is one line per output, which is what lets the chart editor amend the line that produced a chart instead of appending a new one.
So if you paste a command that has been wrapped across two lines — out of a
document, an email, or this guide before it was corrected — the second line
is read as a new command and you get errors like Trailing "," with no argument and Unknown tool "colors". Both say the same thing: join the
lines. The console names that cause when it can see it, and offers a
Join wrapped lines button beside the errors that does it for you. The
button appears only when joining actually makes the script parse, so it is
never a guess — if it is not there, the problem is something else.
Long lines are normal here. The console wraps them for display; the stored script keeps them as one line.
The editor
The console is a real syntax editor, built so that a researcher who has never programmed can read it immediately — and so that editing never changes what a script means:
- Line numbers in a gutter on the left. Long commands soft-wrap for display; the wrapped rows are not numbered, because they are still one line (and one command).
- Syntax colours, muted and theme-derived in both light and dark themes: comments, tool names, argument names, strings and numbers each get a quiet distinction. Colouring is display-only — it never alters the text.
- The current line carries a subtle full-width band, so the caret is easy to find in a long script.
- Bracket matching: place the caret at a
[or]and both ends of the list light up. A bracket inside a quoted string is text, not a bracket, and stays quiet. - Find & replace (
Ctrl+F, orCtrl+Hwith the replace row): a compact bar under the editor with a live match count, next/previous that wrap around, a match-case toggle (Aa), and highlighted matches with the current one emphasised. Replace changes the current match and moves on; All changes every match — and either way oneCtrl+Ztakes it back in a single step.Esccloses the bar and clears the highlights.
The keyboard, at the editor:
| Keys | Action |
|---|---|
Ctrl+Enter |
Run the selected lines — or the caret's line when nothing is selected |
Ctrl+Shift+Enter |
Run the whole script |
Ctrl+/ |
Comment or uncomment the selected lines |
Ctrl+F |
Find (seeded from the selection, if any) |
Ctrl+H |
Find & replace |
Ctrl+Space |
Open the completion list at the caret |
Ctrl+Z |
Undo — typing, a comment toggle, a replace-all, an accepted completion or a Join wrapped lines repair each undo as one step |
(In the find bar, Enter and Shift+Enter step to the next and previous
match, and Esc closes it. While the completion list is open, ↑/↓
move through it, Enter or Tab accepts, and Esc closes it — Tab
goes back to moving focus the moment the list is closed. On keyboard
layouts where / is not a plain key, the Ctrl+/ chord may not be
available.)
As you type: checking, completion and hover help
The console checks your commands as you type. Shortly after you pause, each line is parsed — the same parse that would run it — and a broken line gets a wavy underline over its text and a dot in the gutter. Hover either one and the tooltip shows exactly what the parser will say if you press Run; for a misspelled tool or argument name it adds a suggestion when something in the catalog is close (Did you mean "variables"?). Fix the line and the marks disappear. Nothing is highlighted mid-word while you are still typing — the check waits for your pause, and the status panel under the editor reports the same errors when a run is blocked, so the two never disagree.
Completion offers what the command needs next, and only when it has something real to offer:
- at the start of a line — the tool names, each with its one-line description;
- after a tool — its remaining argument names, completed as
name=(arguments the line already has are not offered again); - after the
=of an argument that takes variables, or inside its[...]list — your dataset's variables, each with its type, measurement level and label; - for an option with a fixed set of values (like
method=) — the allowed values.
The list opens as you type a name (or on Ctrl+Space anywhere), narrows
with every keystroke, and never inserts anything you did not accept:
Enter, Tab or a click takes the highlighted candidate, Esc (or just
clicking elsewhere) makes it go away. Accepting replaces the whole
half-typed word, and one Ctrl+Z undoes it.
Hover help is the same knowledge at rest: hold the pointer over a tool name to see what it does, over an argument name for what it accepts, or over a variable in a command to see its type, measurement level and label. It reads only what is already known — nothing is computed or analyzed by pointing at things.
Running and editing
- Run all / Run selection parse the script and dispatch each command into the Output log. Replaying does not re-record the commands.
- Parse errors and failed commands are reported in a status panel as data — a bad line never crashes the run. Drag the panel's top edge to make it taller (double-click the edge to reset); its text follows the Content text size setting.
- The console and the GUI are two views of one stream: edit the text and re-run, or keep clicking menus and watch the script grow.
Options a dialog does not expose
Every command is a tool name plus named arguments, and the console accepts arguments the dialog has no control for. Two groups are worth knowing about:
Chart presentation. title and colors (a list of hex strings, one per
series, in series order) are accepted by every chart tool; legend (auto /
right / bottom / none) by the charts that draw one; line_width by the
charts that draw lines; and stacked / stack_mode / bar_gap by the bar
chart. They are journaled, so a styled chart re-runs styled:
kaplan_meier time=Months, status=Event, factor=Treatment, plot=true, legend=bottom, colors=["#1f77b4", "#d62728"], line_width=2.5
This is also the per-chart override for the palette chosen in Settings — use it for a one-off (matching a house style in a report) without changing every other chart.
You rarely have to type any of it: the chart editor sets the same arguments from a preview, and writes them back into this same line.
Randomisation seeds. Anything that draws random numbers takes a seed, and
defaults to 1 so that a command is reproducible unless you say otherwise —
the bootstrap, multiple imputation, the Monte-Carlo
permutation tests, and the
quantile residuals
behind a logistic or count model's diagnostic plots. Change it to check that a
result is not an artefact of one particular draw:
logistic_regression dependent=Hypertensive, predictors=[Age, BMI], diagnostics=true, seed=7
When editing a chart amends the script
The chart editor is the one thing that writes into the middle of your script rather than appending to it. Applying an edit finds the line that produced the chart, replaces it with the same command carrying the style you chose, and swaps the restyled chart into the same place in the Output log — same position, same timestamp. If you ran the same command twice, each chart tracks its own line, so editing the second one leaves the first alone.
If that line is not there any more — you rewrote or deleted it, or the chart came from the AI assistant, which runs tools without recording them — the styled command is appended instead, and the chart's note says so. Nothing is guessed at, and either way the script still reproduces the output you are looking at, styled as you see it.
Saving and opening scripts
Save the script as an .cks file and open it later (or hand it to a colleague).
The session also remembers the script between launches.
The command palette
View → Command Palette… (Ctrl+Shift+P) is a fast, keyboard-driven launcher:
start typing the name of any analysis, chart, transform, file or view command and
run it without hunting through menus. It is built from the same tool catalog the
menus, the AI and MCP use, so it can never drift out of sync.
Direct dispatch
The palette also speaks .cks. Type a fully-specified command — the same
one-line grammar as the syntax console:
frequencies variables=[Age, BMI]
and a Run row appears at the top. Enter dispatches the call straight through the engine, bypassing the dialog, and journals exactly the line the dialog would have journaled — so a palette-run analysis replays like any other. This is for the moment you already know the call you want: the same user who edits the console should not have to re-enter it through a form.
- A partially-specified call (required arguments missing) does not error: the row offers to open the tool's dialog instead, and names what is missing.
- A call that fails (a mistyped variable, a bad argument value) shows the engine's message in the palette, with your text still editable.
- A plain word never triggers any of this — the fuzzy search only yields to
the parser once the query contains an
=.
Headless batch mode (--run)
For pipelines, CI and reproducible research, run a script against a dataset with no window:
ChakataStat --run script.cks data.ckd --out report.html
This loads the dataset, runs every command in the .cks script through the same
engine, and writes the output log as a report. The output format follows the
--out extension — HTML, Markdown or LaTeX. It shares the headless
engine bootstrap with the MCP mode, so batch results match what the GUI produces.
A third headless mode, --verify, runs the built-in installation check and
exits 0 only on a full pass — see
Verify this Installation. Together they close the
loop: --verify proves the installed engine reproduces independent reference
values, and --run replays your own script on it.
The dataset fingerprint — "same data"
Every result's footer carries, beside the engine version, a short data
fingerprint: data 3f2a9c1b7e04. It is the first twelve characters of a
SHA-256 over the data your dataset holds — every value, in column order,
with each variable's type and your user-missing definitions applied — so two
results with the same fingerprint were computed from the same numbers. The
footer also names the active conditions: filter age > 30,
weighted by w, split by group.
The fingerprint deliberately ignores anything that cannot change a result:
variable names, labels, value labels, measurement levels, column widths.
Rename or relabel as much as you like — the fingerprint stands. Edit a value,
change a type, or declare a missing code, and it moves. The same data opened
from a .ckd file, a CSV or a Parquet file has one fingerprint.
On a saved script. When you Save Syntax…, the .cks file starts with
a comment naming the data it was recorded against:
# dataset 3f2a9c1b7e04a1e5… (the full 64-character hash)
descriptives variables=[Age, BMI]
It is an ordinary comment — older versions read the script unchanged, and
you can delete it. When you open that script later and run it — in the
console, or headless with --run — ChakataStat compares the header with the
dataset that is open before the first command runs, and puts the verdict
at the top of the output as a Script Provenance entry:
- Same data: yes — the open dataset is, value for value, what the script was recorded against.
- NO — different data — a warning, with both hashes. The script still runs; the results are for the data you have open, and the entry says so. Nothing refuses to run on your behalf here: that is the job of the reproducibility bundle (a later feature), whose whole point is to refuse.
The full convention — exactly what is hashed and how — is recorded in the developer documentation, so a reader can compute the same hash independently.
The reproducibility bundle (.cksb)
A bundle is one small file that lets someone else check your results — re-run this and compare — without you having to describe what you did.
As the author. With your analysis in the output log, choose File →
Export Reproducibility Bundle…. The .cksb file contains:
- your syntax journal (the
.cksscript); - the data fingerprint (and the name of the file you had open);
- the ChakataStat version, the engine version and your platform;
- every output in the log, exactly as it was rendered — every table, and each chart as the geometry table its CSV export produces.
It does not contain your data. Whether and how to share the data is your decision, made separately; the bundle only says what you ran and what you saw. For a clean bundle, Clear All the output and Run All from the console first, so the log holds exactly what the journal produces (an assistant reply or an installation report in the log has no journal line to re-run, and the verifier will say so).
From a pipeline, --run script.cks data.ckd --bundle analysis.cksb writes
the same bundle from a headless run.
As the reader. Obtain the data from the author, then either File → Verify Reproducibility Bundle… (pick the bundle, then the data file), or headless:
ChakataStat --verify analysis.cksb data.csv --out report.html
The verifier checks the data first. If its fingerprint is not the bundle's,
it refuses — the report says REFUSED — different data with both hashes,
and nothing is re-run. This is stricter than the script header's warning on
purpose: the bundle's whole point is to compare against the author's data.
With the right data it re-runs the journal and compares every cell of every
output with the bundle, within the precision the author saw it printed at,
and reports PASS or FAIL per output, naming the first cells that
differ. The exit status is 0 only on a full pass, so a reviewer's script can
gate on it.
Where the installation check (Verify this Installation) proves the software on a machine, the bundle proves a particular result — together with the fingerprint they are the three questions a sceptical reader asks, each answered by a report rather than a promise.
Exporting the output log
File → Export Output… (or the Output view's Export… button) writes your whole results log to HTML, Markdown or LaTeX — the format chosen from the file extension. Tables are escaped per format and charts are rendered as their geometry. For a single result, right-click its card and choose Export as CSV… to drop it straight into a spreadsheet (or use copy-to-clipboard).
Exporting a session as Python
Export as Python… (from the syntax console) renders your recorded session as a runnable Python script for the ChakataStat Python client — installable from PyPI:
pip install chakatastat
The client drives a headless engine over MCP and exposes every analysis as a method; it needs the ChakataStat app installed (it contains no statistics of its own), and its version tracks the app's, so install the client version matching your app:
import chakatastat as ig
ds = ig.open("health_study.ckd") # spawns the headless engine
ds.descriptives(["Age", "BMI", "SystolicBP"])
ds.regression("SystolicBP", ["Age", "BMI"])
for col in ds.numeric_vars(): # real Python: loops, logic
ds.frequencies([col])
df = ds.to_polars() # escape hatch into the Polars ecosystem
This gives you full programmatic control and the whole Python data ecosystem
(polars, numpy, scipy, statsmodels) without ChakataStat embedding any of
it — Python is an external client over the same seam the AI and MCP use, so the
single engine and the errors-as-data discipline are preserved.
Why this matters
The flat command stream is the one canonical record of an analysis. Because the GUI both emits it and can reconstruct itself from it, "what I clicked" and "what I can replay" are the same thing — the foundation that the batch mode, the command palette, user-defined tools and the Python export all build on.
See also
- Direct Engine Access — engine diagnostics and MCP.