# Psy Ana Coder

> Generate, modify, or debug reproducible R or Python analysis code from a completed analysis config YAML or concrete existing script. Use for data import/cleaning, statistical models, assumption checks, effect sizes, sensitivity analyses, publication figures, reports, session information, and analysis-script runtime errors. Do not choose unresolved statistical methods or issue publication-readiness verdicts; use psy-ana-designer or psy-ana-reviewer for those stages.

- Skill: `soupandpsy/psy-ana-coder` (Agent Skill, multi-file: 15 files)
- Install (CLI): `npx skillmds@latest add soupandpsy/psy-ana-coder`
- Raw SKILL.md: https://api.skillmd.com/api/skills/soupandpsy/psy-ana-coder/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: soupandpsy (https://skillmd.com/u/soupandpsy)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/soupandpsy/psy-ana-coder

---


# Analysis Coder

> **Authoritative-source boundary:** never load or copy files under `python/demo/` or `r/demo/` during generation. They are quarantined historical demonstrations and do not satisfy the v1.4.0 analysis contract. Use only the confirmed config plus the current spec, mapping, and checklist selected below.

## Version

v1.4.0 — unified evidence-gated contract, 2026-07-23. Sub-skill of [amazing-psycoder](../SKILL.md).

## Purpose

Receive the analysis config from `psy-ana-designer` and implement it in R or Python. Preserve the same estimand and decision rules across languages, but do not claim API/capability equivalence: if a selected model has no validated implementation in the chosen ecosystem, block or obtain approval for a scientifically equivalent alternative.

**Does not design analyses** — only implements a confirmed analysis plan.

## Platform Routing

```
Analysis config YAML
       │
       ├── User language = R      → r/     (tidyverse, lme4, ggplot2, RMarkdown)
       └── User language = Python → python/ (pandas, statsmodels, seaborn, Jupyter)
```

Each platform includes authoritative `spec/`, `mapping/`, and `checklist/` components. Existing `demo/` directories are quarantined historical material and are excluded from generation context.

## Phase 0: Config Ingestion & Validation

**Goal**: Receive and validate the analysis config YAML, and confirm the language preference.

### 0.1 Receive Config

> "Please provide the analysis config YAML generated by psy-ana-designer. You may paste its content, or provide a file path (e.g., `analysis_config.yaml`)."

Validate immediately after reading the config:
- `version` is compatible (current contract: v1.2)
- Required fields: `analysis_mode`, exact `runtime.language`/`runtime.language_version`/dependency strategy/concrete `dependency_file`/target environment, `design.design_type`, `design.observation_level`, `design.dvs`, `questions[].estimand`, `questions[].selected_method`, and `model.stochastic`
- If `model.stochastic: true`, `model.seed` is required; deterministic plans need no ceremonial seed
- At least one `questions[]` entry
- Field types are correct (`rt_lower` is numeric when used, `correction` is explicit and supported by the selected inference, etc.)

Select `PYTHON_BIN` only after `$PYTHON_BIN -c "import yaml"` succeeds; if no interpreter passes, stop and provide the isolated validation-environment setup from `<amazing-psycoder-root>/PLATFORMS.md`. Run `$PYTHON_BIN <amazing-psycoder-root>/scripts/validate_analysis.py <analysis_config.yaml>` and treat every error as blocking. After generation, run it again with `--code <analysis-file> --language r|python`; a pass means ready for execution testing at most. After a clean run, add `--execution-log <configured-log>` and resolve every hash/environment error before routing outputs to Reviewer.

Validation failure → list missing/incorrect fields, ask the user to correct and re-submit. Do not proceed.

### 0.2 Runtime Confirmation

Route to the platform declared in `runtime.language` and confirm that its exact version/dependency strategy is available. Generate the declared `runtime.dependency_file` from the packages actually imported, with direct dependencies exactly pinned or resolved in a lockfile; never invent unused packages merely to fill a template. If the selected estimator is unsupported there, report the concrete limitation and return to Designer for an approved method/runtime revision; do not silently switch ecosystems or implementations.

### 0.3 Generate Preview

Display the generation plan:
- Platform: R / Python
- Model: {model types extracted from config}
- Figures: {figure list extracted from config}
- Output files: analysis.R/py + report.Rmd/ipynb + the declared dependency pin/lock artifact

> "Confirm the plan above is correct? Then code generation will begin."

After user confirmation, proceed to generation.

## Red Lines

| # | Rule |
|---|------|
| 1 | Stochastic step without a seed/control strategy → do not deliver |
| 2 | Exclusion log missing → do not deliver |
| 3 | Applicable diagnostics/fallback code missing → do not deliver; never add irrelevant omnibus assumption tests |
| 4 | Claim-appropriate effect estimate and uncertainty missing → do not deliver |
| 5 | Multiple comparison scheme not reflected → do not deliver |
| 6 | Environment info (sessionInfo/sys.version) not output → do not deliver |
| 7 | Never generate code with hardcoded paths |
| 8 | Comment language MUST match user language → do not deliver |
| 9 | Declared dependency artifact absent, incomplete for actual imports, or inconsistent with the target runtime → do not deliver |
| 10 | Execution manifest is written only on success, so a failed clean run leaves no machine-readable failure evidence → do not deliver |

---

## Shared Analysis Logic

> The logic below applies to both R and Python equally. For platform-specific API mappings, see each platform's `mapping/` file.

### Comment Language Specification (Highest Priority)

**All generated code comments must use the user's language.** Chinese user → Chinese comments, English user → English comments. Comments should explain "why this is done" rather than merely "what is done."

Each step's comments should include:
- **The purpose of this step** (why this step is necessary)
- **The meaning and provenance of key parameters** (e.g., "the protocol-confirmed RT lower bound is applied as an anticipatory-response rule"; never invent a universal cutoff)
- **The rationale for the chosen statistical method** (e.g., the model estimates the declared trial-level contrast while representing the confirmed subject/item dependence)
- **Result interpretation hints** that emphasize estimates, uncertainty, diagnostics, and limitations rather than treating a non-significant assumption test as proof

The comment style follows "pedagogical comments" — enabling a colleague unfamiliar with this analysis method to understand what every step does and why it is done.

### 12-Step Script Structure

```
1. Title comment    Experiment name, estimand/model, date, config version
2. Environment setup    Package loading, environment capture, conditional stochastic controls
3. Data import    Read + column name validation (missing column → error)
4. Data cleaning   Apply only the config-declared rules in their declared order; never assume correct-only or SD trimming
5. Exclusion log    Print exclusion counts and proportions at each step
6. Descriptive stats    n, mean, sd, se, ci95, median, mad, grouped by condition
7. Model diagnostics    Estimand/model-appropriate residual, convergence, dispersion, calibration, or predictive checks
8. Statistical modeling    t-test / ANOVA / lmer / glmer / Bayes (per config selection)
9. Effect estimates      Planned contrasts/OR/probability differences/effect sizes with uncertainty
10. Declared comparisons   Model-scale/marginal contrasts + the confirmed claim-family/multiplicity strategy when applicable
11. Figure generation   Generate only declared estimand-supporting figures and save them to disk
12. Environment info    Version + package versions
```

(This is Phase 1 — the generation phase executed after Phase 0 validation passes.)

**Priority**: implement `questions[].selected_method` and its confirmed formula/estimand. If these are absent or incompatible with the data hierarchy, stop and route to `psy-ana-designer`; the Coder must not choose a new inferential method.

### Model Implementation Guard

```
selected_method + estimand + outcome family + observation hierarchy
  ├── compatible → implement exactly and add declared diagnostics/sensitivity rules
  ├── unsupported by chosen language/runtime → report concrete dependency limitation and return for an approved alternative
  └── incompatible/unresolved → stop; route to psy-ana-designer
```

**Formula/dependence validation**: Before using `model_formula` and `dependence_structure`, verify:
- Trial/event-level repeated data → formula or estimator must represent declared subject/item/session dependence; the exact random structure is design-dependent
- Binary DV → use the confirmed binomial/ordinal likelihood and dependence structure (for example GLMM, GEE, or a justified Bayesian hierarchy); never use a Gaussian LMM merely because it is convenient
- Variable names in the formula must exist in the data columns
Validation failure → block generation and return an actionable config error. Never silently substitute another model.

### Data Aggregation Rules

| Analysis | Aggregation Level |
|------|---------|
| Paired t-test | Subject × Condition means |
| lmer / MixedLM | Trial level (no aggregation) |
| Descriptive statistics | Condition |
| Participant exclusion | Subject |

### Missing Config Fields

Do not silently invent cleaning thresholds, missing-data policy, contrasts, multiplicity correction, figures, or effect estimates. Missing scientific choices block generation and return to `psy-ana-designer`. Pure presentation defaults (file names, theme, image resolution) may be applied if logged in the report and do not change inference.

### Figure Mapping

See psy-ana-designer's [plots/](../psy-ana-designer/plots/) directory (48 detailed figure specifications) and the R ↔ Python mapping table in this document.

| Figure Type | When to Use | Elements |
|---------|--------|------|
| Raincloud | Within-subjects two-group | Violin + boxplot + individual scatter |
| Individual lines | Within-subjects | One line per person + red mean |
| Boxplot + scatter | Multi-group | Boxplot + jitter |
| Interaction plot | Multi-factor | Grouped lines + error bars |
| QQ plot | Normality test | Theoretical quantiles vs actual |

### Effect Size Quick Reference

| Method | Metric | Interpretation |
|------|------|------|
| t-test | Design-appropriate standardized and/or raw contrast + 95% CI | Interpret against the construct and domain evidence; do not impose universal small/medium/large cutoffs |
| ANOVA | Estimand-compatible contrast and CI; η²/ω² when useful | Interpret magnitude in the construct, scale, and design context; do not impose universal cutoffs |
| Mixed model | Planned marginal contrast + CI; optionally marginal/conditional R² | Focal effect plus model fit |
| Logistic model | Odds ratio and/or probability-scale contrast + 95% CI | State the reference direction and interpret on a domain-relevant scale |

### Multiple Comparison Schemes

| Method | Characteristics |
|------|------|
| Holm / Bonferroni | Family-wise error control for a declared family; Holm is often less conservative |
| FDR (BH) | False-discovery-rate control for a declared discovery family |
| Tukey HSD | Simultaneous inference for a declared all-pairwise family under its model assumptions |
| Planned/hierarchical/no adjustment | Use when the question structure justifies it and record the claim family and rationale |

### Sensitivity Analysis

Run only prespecified sensitivity analyses (cleaning, missingness, distribution/random structure, or estimator variants). Report estimate/uncertainty changes, not merely whether p-values cross 0.05.

### Report Template

Generate a reproducible report: R → RMarkdown/Quarto, Python → Jupyter or a script-rendered HTML report. Include title, exclusion provenance, descriptive statistics, model estimates, diagnostics, figures, and environment info. When execution is possible, run in a clean process and save `analysis-run.json` with command/timestamps/exit status, config/code/dependency/input hashes, warnings, output inventory plus hashes, and environment snapshot. Generation without a successful run is only `ready_for_execution`, never publication-ready.

---

## R ↔ Python Mapping

| Operation | R | Python |
|------|-----|--------|
| Data import | Dispatch from declared format to `readr`/`readxl`/`arrow`/`jsonlite` | Dispatch from declared format to the matching pandas reader |
| Filter | `filter(col > x)` | `df[df['col'] > x]` |
| Group summary | `group_by() %>% summarise()` | `df.groupby().agg()` |
| Pipe | `%>%` | Chained calls |
| Paired t-test | `t.test(y~x, paired=TRUE)` | `scipy.stats.ttest_rel(a,b)` |
| Independent Welch t-test | `t.test(y~x, var.equal=FALSE)` | `scipy.stats.ttest_ind(a,b,equal_var=False)` |
| Within-subjects ANOVA | `afex::aov_ez()` | `pingouin.rm_anova()` |
| Between-subjects ANOVA | `oneway.test(y~x)` | `scipy.stats.f_oneway()` |
| Mixed model | `lme4::lmer()` | `statsmodels.MixedLM()` |
| Logistic mixed | `lme4::glmer(binomial)` | Bambi Bernoulli multilevel model, or a documented `BinomialBayesMixedGLM` design within its limits; plain `Logit()` has no random effects |
| Distribution diagnostics | Model-specific residual/convergence/dispersion checks | Model-specific residual/convergence/dispersion or posterior-predictive checks |
| Homogeneity of variance | `leveneTest()` | `scipy.stats.levene()` |
| Cohen's d | `effectsize::cohens_d()` | `pingouin.compute_effsize()` |
| η² | `effectsize::eta_squared()` | `pingouin.anova(detailed=True)` |
| R² (mixed) | `performance::r2()` | Manual calculation |
| Estimated marginal means | `emmeans::emmeans()` | statsmodels pairwise |
| Post-hoc comparisons | `pairs(emm, adjust=)` | `multipletests(pvals, method=)` |
| Raincloud plot | `ggrain::geom_rain()` | `ptitprince.RainCloud()` |
| Save figure | `ggsave()` | `plt.savefig()` |
| Seed | `set.seed()` | `np.random.seed()` |
| Environment info | exact R-version check + `sessionInfo()` + declared dependency artifact | exact Python-version check + platform/package snapshot + declared dependency artifact |

---

## Routing

```
Analysis config YAML (input)
       │
       ├── Target=R      → r/spec/ + r/mapping/
       │                  → Generate: analysis.R + report.Rmd → save to output.save_path/
       └── Target=Python → python/spec/ + python/mapping/
                          → Generate: analysis.py + report.ipynb → save to output.save_path/
       Both routes also generate runtime.dependency_file beside the project config.
       │
       ▼
psy-ana-reviewer (audit)
```

**After generation**: Code has been saved to `{output.save_path}/`.
> "Code generation complete. Next step: input `/psy-ana-reviewer` and provide the generated script path for audit."

