This file provides guidance to AI coding agents when working with code in this repository.
Keep in sync:
CLAUDE.md,AGENTS.md, and.github/copilot-instructions.mdmust contain identical guidance (except for the first heading). When updating one, update all three.
Shared library repository for Down Syndrome Education International (DSE) research projects. The primary artifact is dse-research-utils, a Python utility package (src/python/). A .NET utilities area (src/dotnet/) is a future placeholder.
When you draft or author any of the following, you must prefix it with a callout that identifies the AI tool used. Place the callout as the first lines of the body:
- document drafts
- pull request descriptions
- issue descriptions
- comments on pull requests
- comments on issues
Substitute the actual tool and model you are running as (for example, GitHub Copilot or Claude Code/Opus 4.8). This requirement applies to every drafted artifact so that human reviewers can readily distinguish AI-generated content.
Use the callout syntax that matches where the text will render:
GitHub surfaces — pull request descriptions, issues, and their comments — use GitHub alert syntax:
> [!NOTE]
> Drafted by a LLM-based AI tool (Claude Code/Opus 4.8).Quarto documents (.qmd) — GitHub alert syntax does not render in Quarto, so use a Quarto callout block instead:
::: {.callout-note appearance="simple"}
Drafted by a LLM-based AI tool (Claude Code/Opus 4.8).
:::Quarto supports five callout types (note, tip, warning, caution, important); use note for attribution. Drop appearance="simple" for the default boxed style, or add collapse="true" to make it collapsible.
When drafting Markdown — repository documents, pull request descriptions, issue descriptions, or comments on either — write each paragraph as a single unwrapped line and avoid superfluous line breaks. Do not hard-wrap prose at a fixed column or scatter extra blank lines; let the renderer wrap the text. Prettier runs with proseWrap: "preserve", so any manual wrapping is kept verbatim and produces noisy diffs.
Follow Conventional Commits for every commit — this applies to agents and humans alike.
- Subject line:
<type>[optional scope]: <description>(for examplefeat(plot): add credible-interval helperorfix: guard against zero variance). - Common types:
feat,fix,docs,refactor,perf,test,build,ci,chore,revert. - Keep the description in the imperative mood and concise, with no trailing period.
- Flag breaking changes with a
!before the colon (for examplefeat!:) or aBREAKING CHANGE:footer. - Add a body separated from the subject by a blank line when the change needs explanation.
Current projects using these libraries include:
- dseinternational/language-reading-predictors
- dseinternational/vocabulary-growth
- dspopulations/us-birth-certificates
To support developing across these repositories simultaneously, we typically check these out relative to this project as follows:
- ../language-reading-predictors
- ../vocabulary-growth
- ../../dspopulations/us-birth-certificates
npm ci
npm run spellcheck # runs cspell over all *.md filesnpm run format # rewrites Markdown files in place
npm run format:check # checks Markdown formatting without rewritingUses Prettier with proseWrap: "preserve" so existing prose line breaks are kept.
conda env create -f environment.yml # create (Python 3.14, conda required — not pip/venv)
conda activate dse-researchcd src/python
python -m build # builds wheel via hatchlingcd src/python
ruff check . # lint
ruff check . --fix # lint with auto-fix
ruff format . # formatpytest # full suite
pytest path/to/test_file.py # single file
pytest path/to/test_file.py::test_function_name # single testsrc/python/src/dse_research_utils/ is structured by domain:
environment/— system info, execution context;init_workbook()/init_script()for notebook/script setupmath/— constants (EPSILON, etc.)metadata/— package version introspectionml/— ML utilities (placeholder)plot/— matplotlib/ArviZ plotting helpers; constants followFIGSIZE_XS,COLOUR_BLUE,DPI_NOTEBOOKnamingreport/— report data-access helpers (ReportData,show_or_pending) that read a fitted model's artefacts and degrade to a visible "pending fit" placeholder before a fit existsstatistics/— descriptive stats; credible/confidence intervals (intervals.hdi_1d/eti_1d/eti_bands); the shared evidence ladder (evidence.py:evidence_label/odds_string/favoured_direction); the ROPE report card (rope.py:rope_card); the MCMC convergence gate, banner, and styled diagnostics table (diagnostics.py); and PyMC models and sampling presets
All __init__.py files are empty — no re-exports. Use fully-qualified absolute imports everywhere (e.g. from dse_research_utils.math.constants import EPSILON).
statistics/models/reporting.ReportingConfiguration carries the reporting ci_prob (credible-interval coverage) and interval_kind ("eti" equal-tailed or "hdi" highest-density); reports read both back so tables, plots, and the diagnostics summary agree on the interval convention. Credible-interval coverage defaults to 0.89 across the shared helpers (hdi_1d, eti_1d, rope_card, ReportingConfiguration.ci_prob, …), matching ArviZ's rcParams["stats.ci_prob"]; a report that wants a different width passes it explicitly (e.g. vocabulary-growth uses 0.90, language-reading-predictors uses 0.95).
Bayesian sampling presets in statistics/models/sampling.py, selected via get_sampling_configuration(config):
dev/development— 2 chains × 500 draws,target_accept=0.85(fast iteration)test/testing— 4 chains × 2000 draws,target_accept=0.90rep-lite/reporting-lite/rep_lite— 4 chains × 4000 draws,target_accept=0.95reporting/report/rep— 6 chains × 6000 draws,target_accept=0.95
License header — every source file starts with:
# Copyright (c) 2026 Down Syndrome Education International and contributors
# SPDX-License-Identifier: AGPL-3.0-or-later- Naming:
snake_casefor files/functions/variables;UPPER_CASEfor constants grouped by domain (e.g.FIGSIZE_XS,COLOUR_BLUE,DPI_NOTEBOOK) - Type hints: always on function signatures
- Type unions:
X | Ysyntax (notUnion[X, Y]) - Docstrings: NumPy-style (
Parameters,Returns,---separators); dataclass fields use attribute docstrings (bare string literals after the field declaration) print: importfrom rich import printto override built-in- Imports: fully-qualified absolute imports only — no relative imports, no
__init__.pyre-exports. The package root__init__.pyis the one exception: it stores__version__for Hatch. - Dataclasses: stdlib
@dataclass; use__post_init__for validation - Plot functions: create figure → render → optionally save to
output_diras.png(300 DPI) and.svg→return plt.gcf() - Notebooks: call
init_workbook()at top (prints environment info); scripts callinit_script()(silent setup); both apply the default matplotlib style viaset_matplotlib_default_style()
Ruff config (in src/python/pyproject.toml): line-length 120, target Python 3.14, rules: F, E, W, I, UP, B, SIM, RUF, ANN (source only; tests ignore annotation rules).
SDK pinned to 10.0.200 (rollForward: latestMinor) via global.json. Test runner is Microsoft.Testing.Platform. NuGet sources: nuget.org (all packages) and dseinternational (https://nuget.pkg.github.com/dseinternational/index.json, DSE.* packages only) — package source mapping enforced with <clear />. No projects exist yet.