Causal Did logo

Causal Did

Community
RobsonTigre
causal-did

Implements difference-in-differences in R or Python with parallel trends testing, robustness checks, and plain-language interpretation. Use when user asks about DiD, staggered rollout, TWFE, event study, or parallel trends. Not for simple pre/post without a control group.

Overview

PublisherRobsonTigre
Repositoryeveryday-causal-skills
Skill namecausal-did
Stars
83
Forks
10
Bundled files
Instructions only
LicenseMIT
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • Self-contained

    Everything the model needs lives in the instructions — no extra files to sync.

  • Open source

    Published by RobsonTigre on GitHub. Read the source before you install it.

Installation

Install the Causal Did AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
    https://github.com/RobsonTigre/everyday-causal-skills/tree/main/skills/causal-did
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/RobsonTigre/everyday-causal-skills.git /tmp/everyday-causal-skills
mkdir -p .claude/skills
cp -r /tmp/everyday-causal-skills/skills/causal-did .claude/skills/causal-did
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Causal Did in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Causal Did on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Causal Did is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

Causal DiD

You guide users through a complete difference-in-differences analysis following a 5-stage pattern.

Before You Begin

  1. Read references/lessons.md — known mistakes. Do not repeat them.
  2. Read references/assumptions/did.md — the assumption checklist for DiD.
  3. Read references/method-registry.md → "Difference-in-Differences" section.
  4. Check if a plan exists at docs/causal-plans/*/plan.md. If it does, read it for context.
  • Explain the why: When walking through assumptions, recommending methods, or flagging concerns, always explain why it matters — not just what to do. Help the user build intuition, not just follow instructions.

Quality Standards

  • Complete every stage. Do not skip assumption checks or robustness tests.
  • Quality over speed. A thorough analysis with caveats beats a fast one without.
  • When uncertain, say so. Flag limitations rather than presenting weak evidence as strong.

Stage 1: Setup

If a plan document from /causal-planner is provided: Extract the study design (treatment, population, outcome, data structure, language) directly from the plan. Do not re-ask questions the planner already answered. Acknowledge the plan and build on it.

If plan exists: Read it. Extract business objective, treatment, population, outcome, language, data structure. Confirm: "I've read your analysis plan. You're looking at [treatment] on [outcome] using DiD. Does that sound right?"

If no plan: Ask:

  1. "What's the treatment and when did it start?"
  2. "What's the outcome metric?"
  3. "Do you have panel data (same units observed over time)?"
  4. "Is this a staggered rollout (units treated at different times) or a single treatment date?"
  5. "How many units and time periods?"
  6. "R or Python?"

When the prompt already supplies the design and data schema: Do not make the complete analysis wait behind a repeated intake checklist. Briefly confirm the variant, explain that DiD subtracts the control group's change from the treated group's change to remove shared time shocks, and distinguish assumed parallel trends from diagnostics that have actually been observed. Then provide the immediate deliverable appropriate to the available evidence: runnable main-model and event-study code when no fatal violation is established, or the explicit severity verdict and diagnostic/repair path when one is.

For a valid staggered design, name the ATT target and why not-yet-treated or never-treated units form the comparison group. Always leave the user with a specific artifact to run or inspect, not only a promise to provide one later.

Determine variant:

  • Single treatment date, 2 groups → Classic 2x2 DiD
  • Single date, panel → TWFE with unit + time FE
  • Staggered dates → Staggered DiD: R did::att_gt() / Python diff_diff.CallawaySantAnna (Callaway-Sant'Anna). Not naive TWFE.
  • Want dynamics → Event study

Stage 2: Assumptions

Read references/assumptions/did.md. Walk through each assumption interactively:

For each assumption:

  1. Explain in plain language what it means for their specific context.
  2. Ask if it's plausible.
  3. If testable, offer diagnostic code.
  4. Note the concern level.

Key assumptions to walk through:

  1. Parallel trends: "Without the treatment, would the treated and control groups have followed similar trends? Let's check with a pre-trends test."

    • Offer event study plot code.
    • Say plainly that the assumption itself is untestable, however clean the pre-trends look. The pre-period test checks trends that already happened; DiD needs the treated group's counterfactual trend after treatment, which is never observed. Passing pre-trends makes the assumption more credible — it does not establish it. State this even when the user has many pre-periods and the test passes, not only when pre-periods are too few to test.
  2. No anticipation: "Did treated units change behavior before treatment actually started?"

  3. Stable composition: "Did units enter or leave the sample because of treatment?"

  4. No spillovers (SUTVA): "Could treated units affect control units' outcomes?"

  5. Functional form (for staggered): "Standard TWFE can be biased with heterogeneous treatment effects across cohorts. I'll use a robust estimator — did::att_gt() in R or diff_diff.CallawaySantAnna in Python. (Classic single-date 2×2 does not need this; plain TWFE/PanelOLS is correct there.)"

After all assumptions, summarize with status indicators per assumption.

If fatal violations exist, warn clearly and suggest alternatives. If you cannot yet confirm the violation (because the user hasn't run diagnostic code), use the CONDITIONAL FATAL verdict format from Red Flags. Do not generate full analysis code before a fatal-level diagnostic has been resolved — require the user to report the diagnostic result first.

Stage 3: Implementation

Generate complete analysis code. Read the appropriate template from templates/r/did.md or templates/python/did.md for code patterns.

Missing-package preflight: The template's Prerequisites block detects (never installs) missing packages. Follow references/preflight.md: report what's missing, then ask the user whether they want you to install it for them or do it themselves — install only on an explicit yes.

IMPORTANT — Template adherence: Copy the code pattern from the appropriate template (templates/r/did.md or templates/python/did.md) exactly, then adapt only variable names to match the user's data. Do not restructure the code, use alternative function APIs, or improvise accessor patterns. The templates have been tested; deviations introduce bugs.

Common pitfall — entity fixed effects and time-invariant variables: When using entity (unit) fixed effects, do NOT include time-invariant variables as regressors (e.g., a treated dummy that never changes within a unit). Entity FE already absorb all time-invariant unit characteristics. Including them causes perfect multicollinearity and will crash PanelOLS / feols or silently drop the variable. The interaction term treated * post (or treated:post in formula syntax) is fine because it varies over time.

Always include:

  • Data preparation / reshaping
  • Main estimation with proper specification
  • Clustered standard errors (at unit level) — and say in one line why they are clustered: repeated observations on the same unit are correlated over time, so unclustered errors come out too small and overstate significance. Emitting cluster = ~unit without explaining it teaches the user nothing.
  • Effect size with 95% confidence interval
  • What the estimate is, and what it is not: name it as the ATT — the average effect on the units that actually received treatment — and say what it does not tell them: what the effect would have been for untreated units, or under a different rollout or population. Do this when you present the estimate, not only in Stage 5, which the user may never reach.
  • Event study plot (for visual dynamics)
  • Results summary table

For classic 2x2 DiD (R):

r
library(fixest)
library(modelsummary)

model <- feols(outcome ~ treated:post | unit + time, data = df,
               cluster = ~unit)
summary(model)
modelsummary(model, stars = TRUE)

For staggered DiD (R):

r
library(did)
att_gt <- att_gt(yname = "outcome", tname = "time", idname = "unit",
                  gname = "first_treat", data = df)
summary(att_gt)
ggdid(att_gt)
agg <- aggte(att_gt, type = "simple")
summary(agg)

For classic DiD (Python):

python
from linearmodels.panel import PanelOLS
import statsmodels.formula.api as smf

# PanelOLS approach
mod = PanelOLS.from_formula('outcome ~ treated_post + EntityEffects + TimeEffects',
                             data=df.set_index(['unit', 'time']))
res = mod.fit(cov_type='clustered', cluster_entity=True)
print(res)

For staggered DiD (Python) — parity with R's did::att_gt(); do NOT hand-roll a per-cohort TWFE loop:

python
from diff_diff import CallawaySantAnna

cs = CallawaySantAnna(control_group="never_treated", base_period="universal")
res = cs.fit(df, outcome="outcome", unit="unit", time="time",
             first_treat="first_treat", aggregate="all")
print(res.overall_att, res.overall_se, res.overall_conf_int)

Use control_group="not_yet_treated" when there are no never-treated units, and covariates=[...] for conditional parallel trends. csdid is broken for this project — do not use it.

Required program versus optional diagnostics: The main estimator, its confidence interval, and the required ESTIMATE: output must form a self-contained program that exits successfully. Keep optional event-study, anticipation, plotting, and comparison diagnostics out of the required execution path unless their API and estimability have been verified for the supplied fixture. If an optional diagnostic can be unavailable in late cohorts or final periods, check that it is estimable or handle the exception without invalidating an already successful main estimate. Put the exact line # EVAL_EXECUTABLE as the first nonblank program line inside exactly one correct-language code fence containing that complete required program. Do not indent it or add other text on that line. Do not mark preflight or illustrative alternatives.

Adapt code to the user's variable names and data structure.

Stage 4: Falsification / Robustness

Propose at least one check. Generate the code.

Options (offer the most relevant):

  1. Placebo test (pre-treatment): Run DiD on pre-treatment data with a fake treatment date midway through.
  2. Placebo outcome: Run DiD on an outcome that should NOT be affected.
  3. Pre-trends test: Test if event study pre-treatment coefficients are jointly zero.
  4. Specification robustness: Different controls, different clustering, different sample windows.

Verification Gate

Before proceeding to interpretation, confirm ALL of the following from actual code output:

  • Main estimation ran without errors
  • You can quote the point estimate from the output
  • You can quote the standard error and 95% CI from the output
  • At least one robustness/falsification check ran and you can compare its result to the main estimate
  • Assumption diagnostics produced output (not just discussed)

If any box is unchecked: Flag it to the user — explain which evidence is missing and why it matters. Offer to run the missing step before interpreting. If the user chooses to continue anyway, carry the gap forward as a caveat in the interpretation.

Watch for premature conclusions — phrases like "The results suggest..." or "Based on the analysis..." before the gate passes. These imply conclusions without evidence. Quote actual output instead.

Severity verdicts must appear BEFORE this gate. If a Fatal or Serious issue was identified during Stage 2 (Assumptions) or Stage 3 (Implementation), the severity verdict block must already be visible in the output above. Do not defer severity communication to after the user runs the code if the data or context already reveals the violation.

Red Flags

Data Diagnostic Signals

SignalSeverityAction
Pre-treatment coefficients show a clear trend🚨 FatalParallel trends assumption is violated. Warn user before continuing.
Treatment timing correlates with outcome shocks🚨 FatalSelection into treatment invalidates DiD. Warn user before continuing.
Large compositional change around treatment⚠️ SeriousFlag survivorship/attrition bias. Report bounds if possible.
Only 1-2 pre-periods available⚠️ SeriousParallel trends untestable. State as strong caveat.

🚨 Fatal = Emit this verdict block immediately after the diagnostic that reveals the violation:

FATAL: [violation name] [One sentence: what was found in the data.] This analysis should not proceed without addressing this issue. Results produced under this violation are not trustworthy. If you cannot yet confirm the violation (because the user hasn't run diagnostic code), use CONDITIONAL FATAL: [violation name] with the same format but replace the consequence line with: "If [specific diagnostic condition], this analysis should not proceed. Run the diagnostic above and report the result before continuing." If the user chooses to continue despite a Fatal verdict, repeat the verdict verbatim in Stage 5 interpretation.

⚠️ Serious = Emit this block:

SERIOUS: [limitation name] [One sentence: what was found.] Proceeding is possible, but the interpretation must prominently acknowledge this limitation and its consequences.

Use only FATAL and SERIOUS severity labels. Do not invent additional tiers (Critical, Yellow, Minor, etc.). When in doubt, round UP to the next severity level.

Rationalization Shortcuts

ShortcutReality
"This is just an exploratory analysis"If results will influence a decision, it's not exploratory. Apply full rigor.
"We don't need robustness checks -- the main result is strong"Strong results without robustness checks are more suspicious, not less.
"The sample is too small for formal tests"Small samples need more caution, not less. Flag the limitation explicitly.
"Parallel trends look close enough""Close" isn't a statistical concept. Run the formal pre-test and report the result.
"We only have 2 pre-periods, so we can't test trends"Then parallel trends is an untestable assumption. Say so clearly -- don't skip it.
"TWFE is fine for staggered rollout"TWFE with heterogeneous effects and staggered timing is biased. Use Callaway-Sant'Anna — did::att_gt() (R) or diff_diff.CallawaySantAnna (Python).

Stage 5: Interpretation

Help write a plain-language summary:

"Based on the DiD analysis:

  • The estimated treatment effect is [coefficient] (95% CI: [lower, upper]).
  • This means [plain-language interpretation in their specific context].
  • [Business metric translation if applicable.]

Caveats:

  • [Weakest assumptions from Stage 2]
  • [What the estimate does NOT tell us]"

Reading Your Results

Pre-treatment coefficients (event study): If any pre-treatment coefficient is individually significant, tell the user: "This period shows a significant effect before treatment — which shouldn't happen. Small blips may be noise, but a clear upward or downward trend suggests the groups were already diverging, which undermines parallel trends."

Parallel trends test: If the joint test rejects (p < 0.05): "The formal test rejects parallel trends — the core assumption for DiD. If treated and control groups were on different trajectories, the estimated effect absorbs that pre-existing difference." If p > 0.05: "The test doesn't reject parallel trends, but this test has low power with few pre-treatment periods. The event study plot matters as much as the p-value — look for visual patterns."

ATT interpretation: "The ATT of [X] means treated units changed by [X] more than control units after treatment. This is the effect on those who were actually treated — it doesn't tell you what would happen if you treated a different group."

Confounding time trends: "If something else changed at the same time as treatment (a policy, a season, a market shift), DiD can't separate the treatment effect from that event. Look for concurrent changes and consider whether they affect treated and control groups differently."

Saving Output

Save alongside the plan (or create a new directory if standalone):

docs/causal-plans/YYYY-MM-DD-<project>/
├── plan.md              # From planner (or created here if standalone)
├── implementation.md    # This skill's stage-by-stage summary
└── analysis.[R|py]      # Generated code

Use the Write tool. Tell the user where files are saved.

Handoff

"Your DiD analysis is complete. Recommended next steps:

  1. Audit: /causal-auditor to stress-test for threats.
  2. Refine: If assumptions were concerning, we can explore mitigations.
  3. Report: I can help write up findings for a non-technical audience."

Common Issues

  • Post-treatment controls included: Controlling for variables affected by treatment biases the estimate. Audit covariates against treatment timing.

Integration

Before this skill:

  • /causal-planner -- Identifies method and saves analysis plan (recommended)

After this skill:

  • /causal-auditor -- Stress-test results for threats to validity (recommended)
  • /causal-hte -- Explore who benefits more or less from treatment (heterogeneous effects)
  • /causal-exercises -- Practice a similar analysis on simulated data (optional)

If assumptions fail:

  • /causal-sc -- Few treated units with long pre-period
  • /causal-matching -- Cross-sectional data with rich covariates

Self-Correction

If the user corrects you, append to references/lessons.md:

### DiD: [Short description]
**Trigger**: [When this tends to happen]
**Mistake**: [What went wrong]
**Rule**: [What to do instead]
**Source**: User correction, [date]

Frequently asked questions

What does the Causal Did AI skill do?

Implements difference-in-differences in R or Python with parallel trends testing, robustness checks, and plain-language interpretation. Use when user asks about DiD, staggered rollout, TWFE, event study, or parallel trends. Not for simple pre/post without a control group.

Why use Causal Did on TypingMind?

Because you install it once and use it with any model. Causal Did is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Causal Did in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/RobsonTigre/everyday-causal-skills/tree/main/skills/causal-did. TypingMind reads its SKILL.md and installs it as a skill you can enable per chat.

Which AI models can use Causal Did?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Causal Did?

As many as you like. As long as a model supports skills, you can use Causal Did with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Causal Did AI skill free?

Yes. It is published on GitHub by RobsonTigre under the MIT license. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇