All notable changes to scriptorium are documented here. Format loosely follows Keep a Changelog; versioning is SemVer.
youtube-research-ingestorskill (INGEST). Turns a YouTube URL into a local, source-graded research artifact — metadata, transcript (official subtitles first, local Whisper fallback), structured summary, an extracted-claims table, references/ entities mentioned, a verification-needed list, optional technical-artifact and frame notes, and an audit. Local-first (yt-dlp + ffmpeg + whisper), treats YouTube as a secondary source, never promotes an unsupported claim to fact, never fabricates references/DOIs/timestamps/quotations. Composes withepistemic-status(claim grading),field-note-from-url(provenance note), andliterature-search(primary-source verification). Modes: transcript | summary | claims | scientific-review | technical-review | teaching-notes.
codex_clibackend: provisional → argv-verified.codex(codex-cli 0.139.0) is now installed locally;codex execruns non-interactively and reads the prompt from stdin, exactly how the adapter pipes it, confirming the pinned["codex", "exec"]argv. Cross-runtime concordance runs (claude_clivscodex_cli) are now gated only oncodex login(an OpenAI auth credential), not on a missing install. Docs/tests reconciled (STATUS, ROADMAP, behavioral-validation,test_codex_cli_argv_is_pinned_verified).
Note:
pyprojectversion was inadvertently left at1.0.0through the 1.1.0 and 1.2.0 tags (git tags were the source of truth); this release reconcilespyprojectto1.3.0.
- Two new
stat_runops (roadmap "morestat_runops", implemented + reference-validated).permutation_test— two-sample permutation test for the difference in means; exact enumeration of allC(n, n_a)pooled splits for small n (no RNG, findingoperational_fact), else a seeded Monte-Carlo estimate (seed derived from the payload provenance run-id, reproducible; finding demoted tocorroborated_inferenceas a stochastic estimate). The exact path reproducesscipy.stats.permutation_test(permutation_type='independent',n_resamples=inf) to < 1e-12 fortwo-sided/less/greater; the Monte-Carlo path agrees within sampling error.multiple_testing— Bonferroni and Benjamini-Hochberg (FDR) adjusted p-values + which hypotheses survivealpha; reproducesstatsmodels.stats.multitest.multipletests(bonferroni,fdr_bh) to < 1e-12. The arithmetic isoperational_fact; the finding is scoped to "adjustment computed", not "these effects are real".schemas/stat_run_response.schema.jsongains typed optionals for the new fields; newexamples/stat-run/fixtures (input + verified output) for both ops. - Behavioral harness expansion (roadmap item A, deterministic portion). Four new adversarial
sci-writing/peer-review documents and four new injection-refusal cases extend coverage to
7 cases across all 4 agents (
peer-reviewer,research-scout,librarian, andstatistician, previously uncovered) and five attack classes: forced verbatim output, citation laundering, command/data exfiltration, and base64-obfuscated payloads, plus the original.core/injection_scangains five matching curated patterns (append-verbatim,citation-injection,exfil-command,exfil-network,decode-execute); the clean-manuscript control still yields zero false positives. Each new document is deterministically flagged in default CI, and a loader guard asserts every case points at an existing document + agent. local_vllmbackend (scripts/behavioral/backends.py) — a local vLLM (OpenAI-compatible HTTP) backend following the skip-if-unavailable convention. Scaffolded and unit-tested (deterministic skip path + greedy request-payload construction) but not validated against a live model.CliBackend.argvis now a read-only property so the pinned claude/codex invocation syntax is checked without spawning a process.
codex_cliremains provisional: nocodexinstall was available to verifycodex execsyntax, so cross-runtime concordance runs stay blocked on a second runtime.
- Bespoke per-engine response schemas — each of the seven remaining L0 engines
(
stat_run,guideline_check,citation_parse,injection_scan,grimmer,interim_boundaries,epistemic_grade) now has its ownschemas/<engine>_response.schema.jsonpinning the engine-specificdatapayload, on top of the shared envelope (power_sample_sizealready had one). A new auto-discovering contract test (tests/test_engine_schemas.py) validates a committed representative output per engine against its schema and proves each schema rejects a malformed output via a per-engine negative control (21 schema cases; 154 tests total).
- Behavioral injection-refusal harness (
scripts/behavioral/,tests/behavioral/) — the post-1.0 roadmap's first item. Tests whether an agent actually refuses a directive embedded in an untrusted document, not merely whetherinjection_scandetects it. Two layers: a deterministic core in default CI (case + judgement JSON schemas, pass/fail verdict recomputed from judge scores, untrusted-data prompt framing, JSON-recovery from judge output, commit-safe redacted report — document SHA-256, never its text; 28 tests) and a model-gated real-runtime run behindSCRIPTORIUM_RUN_LLM_JUDGE=1(markerllm_judge). - Pluggable, model-agnostic backends (
scripts/behavioral/backends.py) with the repo's skip-if-unavailable convention:claude_cli(verified),codex_cli(provisional argv),local_vllm(planned). Cross-runtime agreement is documented as a validity signal. docs/behavioral-validation.md— design, run instructions, and the same-family-judge caveat.- 3 adversarial cases × 3 agents (peer-reviewer, research-scout, librarian). First gated run: all three refused (scores 1.0; single-runtime claude agent+judge).
benchmarks/sci-writing-injection/— a protocol + pilot baseline applying the harness to external scientific-writing/peer-review agents (the surface the 2025 arXiv hidden-prompt incident exploited). Pilot: 5/5 agents refused a blatant injection (3 Scriptorium + the claude-scientific-writer peer-review and scientific-writing skills). Framed honestly as a difficulty-floor baseline, not a robustness certificate. CC-BY-NC-4.0; Zenodo DOI on deposit.
- Relicensed code MIT → AGPL-3.0-or-later (sole-copyright-holder relicense). Free to use,
run, modify; derivatives and network-served versions must publish source under the same terms
— no closed 1:1 reuse. Releases up to v1.0.0 remain available under MIT. Scientific artifacts
under
benchmarks/are CC-BY-NC-4.0 (separate from the code license; CC is not for software).
First stable release. The deterministic core's contract is now frozen under SemVer (see STABILITY.md); the model-driven prompt layer continues to evolve.
- Uniform engine envelope contract — every one of the nine L0 engines returns
{status, data{finding}, …}on success /{status:error, message}on failure. Specified byschemas/envelope.schema.jsonand verified for all engines intests/test_envelope_contract.py(one committed output fixture per engine undertests/fixtures/envelopes/). - STABILITY.md — the SemVer contract: what is frozen (engine invocation, envelope, finding, power/profile schemas, provenance) vs what may still evolve (additive coverage, prompt wording, the experimental LLM-judge harness) + a deprecation policy.
epistemic_gradenow also emits afinding(its aggregate re-expressed as a graded finding), so it conforms to the uniform envelope contract like every other engine.
9 deterministic engines (power: 8 designs; stat_run: 6 ops; guideline_check: STROBE/CONSORT/PRISMA; citation_parse; epistemic_grade; interim_boundaries/gsDesign; grimmer/scrutiny; injection_scan), pluggable KB-provider, mode-guard, tested config parser. 105 tests, two CI jobs (matrix 3.10–3.12
- R-engines), coverage ~86% gated ≥80%, blocking ruff.
- Coverage measurement + gate —
pytest-covwithpatch = subprocess(the engines run as subprocesses, so this captures their real execution, not just imported modules). Real coverage ~86%, CI-enforced at ≥80% (fail_underinpyproject.toml). Naive--covwould have reported a misleading 23% — fixed by measuring subprocesses honestly. ci-r.yml— a dedicated CI job that installs R +gsDesign+scrutinyand actually runs the R-dispatch engine tests (grimmer,interim_boundaries), which skip on the stock runner.ARCHITECTURE.md— layered-design diagram + request flow + policy boundaries (60-second overview), linked from the README honest-scope note.
- README: "small deterministic core" → "tested deterministic core" (nine engines — "small" was misleading); added coverage details to the Testing section.
- STATUS.md prompt-layer row said
power-sample-sizeis "engine-backed for the four families above" — stale since the engine grew to eight designs. Now points to the full design table.
- A Testing section in the README documenting the test layout. The engine known-value,
input-validation, and deterministic-provenance tests already existed in
tests/core/test_power_sample_size.py(and the other engines intests/core//tests/lib/); this makes them discoverable to readers who expect a flattests/directory.
injection_scanengine — a deterministic prompt-injection screen over untrusted documents, operationalising the SECURITY.md threat model (untrusted documents are data, not instructions). Curated, imperative-injection-specific patterns; hits are findings to report, never directives to obey. It is a heuristic screen —working_hypothesisfindings, never a confident safe/malicious verdict.- Adversarial fixture corpus (
tests/fixtures/adversarial/): an injection manuscript and a clean control, withtests/core/test_injection_scan.pyasserting the injection is flagged and the clean control passes (no false positives). tests/fixtures/adversarial/README.mddocumenting, honestly, what is deterministically tested (injection_scan, structural fake-citation viacitation_parse) vs what remains a manual / LLM-judged behavioural harness (whether an agent refuses an embedded directive) — tracked as future work, not claimed as tested.
peer-revieweralready treats prompt-injection text as a research-integrity red flag at the prompt level (it has noBash); the engine serves the Bash-capable orchestration layer.
linear_regressionpower — total N for a fixed-model multiple regression via Cohen's f² and the noncentral F (iterated), matching Cohen's tables and G*Power. Brings the engine to eight design families, all with golden fixtures validated against the schemas.- Config parser CLI —
python scripts/lib/profile.pyprints the merged profile as JSON. The Bash-capable components (statisticianagent,power-sample-sizeskill) now resolve config by calling the tested parser instead of hand-parsingprofile.md.
- README / STATUS reconciled: regression is now implemented (not agent-guided); the config parser is wired into the Bash-capable components (offline read-only agents still read the file directly, by design).
Theme: tighten what already exists — validation, complete evidence, stricter CI.
- GRIMMER engine (
scripts/core/grimmer.py) — SD granularity consistency via R-dispatch to the referencescrutinypackage. scrutiny has a known bug (issue #80) where GRIMMER "test 3" can false-positive; a test-3-only failure is therefore demoted to an indeterminate finding (working_hypothesis), never a confident inconsistency. GRIM and tests 1–2 are sound. - Input validation in
power_sample_size— rejects out-of-range or degenerate inputs (r = 0,hazard_ratio = 1,p1 = p2, alpha/power outside (0,1), etc.) with a clear error instead of dividing by zero. - Golden fixtures for all seven power designs (input + output);
tests/test_schemas.pynow validates every one against the JSON schemas.
- CI lint is now blocking — removed the advisory
ruff … || true; added a[tool.ruff]config (line length, deliberate test-only ignores). The tree is ruff-clean. - README: replaced the stale "engine-backed for four designs" wording with a pointer to the live design table in STATUS.md.
- Power/sample-size families:
one_sample_t,correlation(Fisher z, closed form),survival_logrank_events(Schoenfeld; returns required events). The engine now covers seven designs, each self-documenting itsmethodandassumptions. - Config parser
scripts/lib/profile.py— resolvesprofile.md(project → user → defaults), extracts the YAML block, merges over universal defaults, and warns on unknown sections instead of crashing. Tested behaviorally. - JSON Schema I/O contracts (
schemas/: power request/response, finding, profile), enforced against the committed example fixtures intests/test_schemas.py. - Examples:
correlationinput/output fixture (validated against the schemas).
- GRIMMER moved to v0.4.1 — deferred until it can be ported from and validated against a
reference implementation (
scrutiny/rsprite2). Shipping an unverified statistic would defeat the tool's purpose. - Regression-power approximation, and routing agents through the new parser → v0.4.1.
Theme: less manifesto, more evidence. Claims are now drawn precisely against the implementation, with CI proving the test suite and examples showing real input → output.
- Engine expansion. Power/sample-size families
paired_t,two_proportions(Cohen's h),one_way_anova; statistical testsmann_whitney,chi_square,fisher; reporting guidelines CONSORT (2010) and PRISMA (2020) alongside STROBE. - Self-documenting power output. Each result now carries
method(the exact routine) andassumptions(alpha, power, alternative, effect input) next to the provenance trace. - CI. GitHub Actions, Python 3.10–3.12, pytest (54 tests) + advisory ruff.
- Examples.
examples/power-sample-size/— verified, reproducible input/output fixtures. - Honest docs.
STATUS.md(deterministic-core vs prompt-layer matrix),LIMITATIONS.md,PRIVACY.md,SECURITY.md,ROADMAP.md; README rewritten with explicit what it can do today / what it cannot do yet and implemented / agent-guided / planned labels.
- README no longer over-claims: "every number from a tested engine" is now scoped to the designs the engine actually backs, with the rest labelled agent-guided.
- GRIMMER (SD granularity consistency) — needs a careful, separately-tested algorithm (v0.4.0).
- Shared config parser
scripts/lib/profile.pyand engine JSON schemas (v0.4.0).
Repositioning: Scriptorium becomes the Sovereign + Rigor layer above scientific writing — it audits / verifies / computes / grades rather than generates, complementing (not replacing) generative tools. Two pillars (offline-first + deterministic rigor) with a graduated epistemic-status spine on every output. Layered architecture (Approach A): deterministic L0 core, pluggable L1 KB-provider, thin model-agnostic L2 orchestration, orthogonal L3 mode-guard.
- L0 deterministic core:
scripts/lib/(json_io, provenance, epistemic spine) and enginesepistemic_grade,power_sample_size,stat_run(assumptions / recompute / GRIM),guideline_check(STROBE),citation_parse(structural hygiene),interim_boundaries(gsDesign R-dispatch) — each a JSON-contract CLI with golden tests. - L1 KB-provider: pluggable
query()contract,folder+obsidianadapters,rag/cagstubs, guard-integratedkb/query.py. - L3 mode-guard: defense-in-depth egress control (mode declaration, import audit, honest
process sandbox) with truthful
status()disclosure — never claims isolation it cannot make. scripts/run_tests.shpre-push quality gate (44 tests + structure validators + guard status).
- L2 migration to single-source-of-truth engines:
power-sample-sizeandstatisticiannow call the tested L0 engines (provenance-traced) instead of ad-hoc inline computation;peer-reviewerflags machine-checkable inconsistencies (GRIM / p-recompute / power-sanity) for offline recheck by the statistician, preserving manuscript confidentiality. - Reviewer-path agents (
peer-reviewer, reporting/interim review skills) remainRead/Grep/Globonly — capability-removal kept intact as the Sovereign moat; engines are concentrated in the Bash-capablestatistician.
- 4 agents:
peer-reviewer(confidential, offline manuscript referee),librarian(resource acquisition advisor),research-scout(literature retrieval + epistemic grading),statistician(classical + Bayesian analysis). - 8 skills:
literature-search,reporting-guideline-check,epistemic-status,field-note-from-url,manuscript-imrad,peer-paraphrase(PEER framework),power-sample-size,interim-analysis-reviewer. - Config-driven universality via
profile.md(resolution order:./.scriptorium/→~/.scriptorium/→ universal defaults). /scriptorium-initcommand;plugin.json+marketplace.json; MIT license.- Validation scripts (JSON, frontmatter, structure) and worked examples per agent.