From edsl-research
Answer questions about a generated analysis report - reads report artifacts, performs additional analysis if needed, and saves the answer with metadata
How this skill is triggered — by the user, by Claude, or both
Slash command
/edsl-research:answer-questionThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Read a generated analysis report (from `/analyze-results`) and answer a specific question about it. Can perform additional analysis on the underlying data if the existing report doesn't fully answer the question. Saves the answer as markdown with supporting files in a dedicated directory.
Read a generated analysis report (from /analyze-results) and answer a specific question about it. Can perform additional analysis on the underlying data if the existing report doesn't fully answer the question. Saves the answer as markdown with supporting files in a dedicated directory.
/answer-question What is the sample size?
/answer-question How does weight vary by position? ./analysis_1
If no analysis directory is specified, the skill will locate the most recent one automatically.
Extract two things from the user's input:
./analysis_3)If no analysis directory is provided, check how many analysis directories contain a report.md:
import glob
import os
existing = sorted(glob.glob("./analysis_*"), key=os.path.getmtime, reverse=True)
with_reports = [d for d in existing if os.path.isfile(os.path.join(d, "report.md"))]
/analyze-results first.AskUserQuestion to let the user pick. Read the first line of each report.md to build descriptive labels:# Build option labels like "analysis_5 — Anchoring Bias Experiment (2026-02-06)"
options = []
for d in with_reports:
first_line = open(os.path.join(d, "report.md")).readline().strip().lstrip("# ")
options.append({"label": os.path.basename(d), "description": first_line})
Then ask:
Which analysis directory should I use?
with those options. Use the user's choice as analysis_dir.
Load the key artifacts from the analysis directory:
report.md — The main analysis report. Read it fully.results.csv — The raw data. Load it into pandas for potential follow-up analysis.survey.md — The survey structure. Read it for context about question wording and types.import pandas as pd
report_md = open(f"{analysis_dir}/report.md").read()
survey_md = open(f"{analysis_dir}/survey.md").read()
df = pd.read_csv(f"{analysis_dir}/results.csv")
Also read any other files in the directory (mermaid diagrams, existing charts) to have full context.
Create a directory named with a slugified version of the question:
import re
import os
def slugify(text, max_length=60):
"""Convert text to a URL-friendly slug."""
text = text.lower().strip()
# Remove punctuation except hyphens
text = re.sub(r'[^\w\s-]', '', text)
# Replace whitespace with hyphens
text = re.sub(r'[\s_]+', '-', text)
# Remove leading/trailing hyphens
text = text.strip('-')
# Truncate to max_length at a word boundary
if len(text) > max_length:
text = text[:max_length].rsplit('-', 1)[0]
return text
slug = slugify(question)
output_dir = f"{analysis_dir}/{slug}"
os.makedirs(output_dir, exist_ok=True)
For example:
analysis_1/what-is-the-sample-size/analysis_1/how-does-weight-vary-by-position/If the directory already exists, append a numeric suffix: what-is-the-sample-size-2.
Attempt to answer the question in this order:
a) Check the existing report first. If the report already contains the answer, extract and summarize it. No additional analysis needed.
b) If the report doesn't fully answer the question, do additional analysis. Write and run Python scripts against results.csv to compute statistics, generate charts, or perform deeper analysis. Save any generated charts or data files to the output directory.
c) If the question requires information not available in the data, say so clearly and explain what data would be needed.
When performing additional analysis, save the Python script as analysis.py in the output directory for reproducibility.
Write the answer as answer.md in the output directory:
# [Question text here]
[Clear, concise answer in 1-3 paragraphs]
## Supporting Evidence
[Tables, statistics, or references to charts that back up the answer]
## Additional Context
[Any caveats, limitations, or related observations — only if relevant]
Keep answers direct and focused. Lead with the answer, then provide evidence.
If charts or visualizations were generated, reference them with relative paths:

Save a meta.json file in the output directory:
import json
from datetime import datetime, timezone
meta = {
"question": question,
"slug": slug,
"analysis_dir": analysis_dir,
"timestamp": datetime.now(timezone.utc).isoformat(),
"files": os.listdir(output_dir),
"required_additional_analysis": True # or False
}
with open(f"{output_dir}/meta.json", "w") as f:
json.dump(meta, f, indent=2)
If the answer includes charts or tables, convert to HTML for easy viewing:
# Locate the bundled CSS using Glob("**/assets/report.css")
CSS_FILE="<discovered_css_path>"
pandoc "${output_dir}/answer.md" \
-o "${output_dir}/answer.html" \
--css="${CSS_FILE}" \
--standalone
Tell the user:
| File | Description |
|---|---|
answer.md | The answer in markdown format |
answer.html | Styled HTML version of the answer (if generated) |
meta.json | Metadata: question, timestamp, files list, flags |
analysis.py | Python script used for additional analysis (if any) |
*.png | Charts or visualizations generated (if any) |
User runs:
/answer-question What is the average weight by position?
Skill finds ./analysis_1/ (most recent), reads report.md and results.csv, sees the report already has a position breakdown, extracts and reformats it, and produces:
analysis_1/what-is-the-average-weight-by-position/
├── answer.md
├── answer.html
└── meta.json
If the report didn't have that breakdown, the skill would write and run a script:
analysis_1/what-is-the-average-weight-by-position/
├── answer.md
├── answer.html
├── meta.json
├── analysis.py
└── weight_by_position.png
npx claudepluginhub expectedparrot/ep-skills --plugin edsl-researchConverts data analysis results into structured reports covering assumptions, findings, validation, limitations, and next steps.
Compiles causal analysis artifacts into a structured report with tables, figures, and method summaries. Invoked for 'write a report' or 'summarize analysis' requests.
Writes structured post-experiment research reports after analysis artifacts are ready. Produces decision-oriented narratives with statistical validation and next actions, writing into an Obsidian vault.