Project guide for Claude
This is a social-science data analysis project. Read this before doing anything.
What this project is
- Research question: ...
- Data source: ... (survey / administrative / scraped / interviews)
- Unit of analysis: ... (individual, household, country-year, ...)
Data rules — read carefully
| Folder | What it holds | What you may do |
|---|---|---|
data/raw/ |
Original downloads, never modified | Read only. Never edit or overwrite. |
data/restricted/ |
Personal or confidential microdata, interview transcripts | Off limits. Blocked in .claude/settings.json. Do not read, print, or copy its contents. |
data/processed/ |
Cleaned, de-identified, derived files | Read and write freely. |
If an analysis needs restricted data, the student must first produce a de-identified
extract in data/processed/ themselves, and you work from that.
Never paste raw respondent-level rows, names, addresses, emails, or verbatim interview quotes into your replies or into committed files.
How to work here
- Python via
uv. Run things withuv run python ...oruv run pytest. Add packages withuv add <pkg>, neverpip install. - Scripts over notebooks for logic. Reusable cleaning and modelling code goes in
src/analysis/. Notebooks innotebooks/import from it and show results. Never copy-paste the same cleaning code into three notebooks. - One script, one output. Each script in
scripts/reads fromdata/, writes todata/processed/oroutputs/, and prints nothing else. - Reproducibility is the deliverable. Set random seeds. No absolute paths — use
pathlib.Path(__file__).parents[1]. Anyone should be able to clone, runuv sync, runscripts/in order, and get identical numbers.
Statistical conventions
- State the estimand before writing the model. Say what the coefficient means in substantive units, not just "significant".
- Report effect sizes and uncertainty (CIs), not only p-values.
- Missing data: never drop silently. Report how many cases were dropped and why; prefer explicit handling (listwise, imputation) stated in the output.
- Survey data: apply the survey weights the codebook specifies. If a dataset has a weight variable and it isn't used, say so out loud.
- Don't invent variable names or value labels. Check the codebook or the actual
columns with
df.info()/df["x"].value_counts()first.
What to do when uncertain
Ask, don't guess. Wrong assumptions about coding of a variable (e.g. 99 = "missing" vs. 99 = a real value) silently ruin results. If the codebook is ambiguous, flag it in your answer and pick the conservative reading.
Teaching mode
The people working here are learning. When you write analysis code, add a one-line comment explaining why a methodological choice was made, not what the line does. When asked to explain output, explain it at the level of a second-year social science student.
Reports, JavaScript and Node
The deliverable report lives in report/. It is plain HTML, CSS and vanilla JS
with no build step and no CDN links -- it must open correctly from a local file
copy two years from now.
- The chart reads
report/data.json, whichscripts/03_export_report_data.pywrites. Never hardcode numbers into the HTML, and never let the report compute a statistic. Python owns the numbers; JavaScript only draws them. - Before writing any chart code, follow what
report/index.htmlalready establishes: zero-based magnitude axes, a legend for two or more series plus direct labels, a hover tooltip, a data-table toggle, and the existing colourblind-safe palette variables. Do not introduce new colours ad hoc. - Never a dual-axis chart. Two measures on different scales means two charts.
- Animation must carry no information that is unavailable when it is switched
off, and must respect
prefers-reduced-motion. npm install -gworks without sudo here; globals go to~/.npm-global.
Machine learning
- Split the data before exploring it. Report test-set performance once.
- Always give a baseline (majority class, or OLS) alongside any model. A gradient-boosted tree that beats nothing has demonstrated nothing.
- Prediction quality is not causal evidence. Do not let a feature-importance plot become a sentence with the word "causes" in it.
- Report the class balance and the metric appropriate to it. Accuracy on an 85/15 split is close to meaningless.
LLM calls inside the analysis
- Calls to the Claude API from project code are billed separately from the
Claude Code seat and need
ANTHROPIC_API_KEY. Never run an uncalibrated prompt across a whole dataset -- ask first. - Text sent to the API leaves this machine. Nothing from
data/restricted/may ever be placed in a prompt, quoted in one, or summarised into one. - LLM coding of open text is a measurement instrument. It needs a versioned codebook, a hand-coded validation sample, and a reported agreement rate before any result built on it is trustworthy.
- Set
temperaturenowhere and seeds where you can; record the model ID used in the output, because results are not reproducible across model versions.
Git
data/andoutputs/stay out of git. Check before committing.- Commit before asking Claude to make a change across several files.
This server's processor
The course server's CPU predates AVX2. Two consequences:
- Use
polars-lts-cpu, neverpolars-- the standard wheels abort withIllegal instruction. Everything else about the API is identical. - If any other package dies with
Illegal instruction (core dumped)rather than a Python traceback, this is why. Look for an LTS, compat, orrtcompatbuild before assuming the code is wrong.